From 7249ea4df2b4f12a4e7ed446f270cea87e4ffd34 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Tue, 9 Jun 2009 09:53:44 -0700 Subject: mv src/lib to src/pkg tests: all.bash passes, gobuild still works, godoc still works. R=rsc OCL=30096 CL=30102 --- src/clean.bash | 2 +- src/cmd/gobuild/gobuild.go | 4 +- src/lib/Make.deps | 52 - src/lib/Makefile | 139 --- src/lib/archive/tar/Makefile | 60 - src/lib/archive/tar/testdata/small.txt | 1 - src/lib/archive/tar/testdata/small2.txt | 1 - src/lib/archive/tar/testdata/test.tar | Bin 3072 -> 0 bytes src/lib/archive/tar/untar.go | 242 ---- src/lib/archive/tar/untar_test.go | 69 -- src/lib/bignum/Makefile | 60 - src/lib/bignum/bignum.go | 1464 ---------------------- src/lib/bignum/bignum_test.go | 482 -------- src/lib/bufio/Makefile | 60 - src/lib/bufio/bufio.go | 515 -------- src/lib/bufio/bufio_test.go | 298 ----- src/lib/bytes/Makefile | 60 - src/lib/bytes/bytes.go | 164 --- src/lib/bytes/bytes_test.go | 157 --- src/lib/compress/flate/Makefile | 60 - src/lib/compress/flate/flate_test.go | 131 -- src/lib/compress/flate/inflate.go | 673 ---------- src/lib/compress/gzip/Makefile | 60 - src/lib/compress/gzip/gunzip.go | 236 ---- src/lib/compress/gzip/gunzip_test.go | 268 ---- src/lib/container/list/Makefile | 60 - src/lib/container/list/list.go | 130 -- src/lib/container/list/list_test.go | 91 -- src/lib/container/vector/Makefile | 69 -- src/lib/container/vector/intvector.go | 118 -- src/lib/container/vector/stringvector.go | 118 -- src/lib/container/vector/vector.go | 244 ---- src/lib/container/vector/vector_test.go | 209 ---- src/lib/crypto/aes/Makefile | 76 -- src/lib/crypto/aes/aes_test.go | 353 ------ src/lib/crypto/aes/block.go | 182 --- src/lib/crypto/aes/cipher.go | 71 -- src/lib/crypto/aes/const.go | 363 ------ src/lib/crypto/block/Makefile | 82 -- src/lib/crypto/block/cbc.go | 75 -- src/lib/crypto/block/cbc_aes_test.go | 107 -- src/lib/crypto/block/cfb.go | 100 -- src/lib/crypto/block/cfb_aes_test.go | 316 ----- src/lib/crypto/block/cipher.go | 74 -- src/lib/crypto/block/cmac.go | 105 -- src/lib/crypto/block/cmac_aes_test.go | 165 --- src/lib/crypto/block/ctr.go | 69 -- src/lib/crypto/block/ctr_aes_test.go | 115 -- src/lib/crypto/block/eax.go | 254 ---- src/lib/crypto/block/eax_aes_test.go | 239 ---- src/lib/crypto/block/ecb.go | 271 ---- src/lib/crypto/block/ecb_aes_test.go | 136 -- src/lib/crypto/block/ecb_test.go | 183 --- src/lib/crypto/block/ofb.go | 61 - src/lib/crypto/block/ofb_aes_test.go | 113 -- src/lib/crypto/block/xor.go | 126 -- src/lib/crypto/block/xor_test.go | 169 --- src/lib/crypto/hmac/Makefile | 60 - src/lib/crypto/hmac/hmac.go | 104 -- src/lib/crypto/hmac/hmac_test.go | 100 -- src/lib/crypto/md5/Makefile | 68 - src/lib/crypto/md5/md5.go | 117 -- src/lib/crypto/md5/md5_test.go | 68 - src/lib/crypto/md5/md5block.go | 178 --- src/lib/crypto/sha1/Makefile | 68 - src/lib/crypto/sha1/sha1.go | 119 -- src/lib/crypto/sha1/sha1_test.go | 70 -- src/lib/crypto/sha1/sha1block.go | 86 -- src/lib/datafmt/Makefile | 68 - src/lib/datafmt/datafmt.go | 789 ------------ src/lib/datafmt/datafmt_test.go | 375 ------ src/lib/datafmt/parser.go | 447 ------- src/lib/exec/Makefile | 60 - src/lib/exec/exec.go | 228 ---- src/lib/exec/exec_test.go | 51 - src/lib/exvar/Makefile | 60 - src/lib/exvar/exvar.go | 214 ---- src/lib/exvar/exvar_test.go | 93 -- src/lib/flag/Makefile | 60 - src/lib/flag/flag.go | 486 -------- src/lib/flag/flag_test.go | 77 -- src/lib/fmt/Makefile | 68 - src/lib/fmt/fmt_test.go | 247 ---- src/lib/fmt/format.go | 533 -------- src/lib/fmt/print.go | 705 ----------- src/lib/go/ast/Makefile | 68 - src/lib/go/ast/ast.go | 772 ------------ src/lib/go/ast/format.go | 123 -- src/lib/go/doc/Makefile | 68 - src/lib/go/doc/comment.go | 310 ----- src/lib/go/doc/doc.go | 486 -------- src/lib/go/parser/Makefile | 60 - src/lib/go/parser/parser.go | 1975 ------------------------------ src/lib/go/parser/parser_test.go | 68 - src/lib/go/scanner/Makefile | 60 - src/lib/go/scanner/scanner.go | 501 -------- src/lib/go/scanner/scanner_test.go | 276 ----- src/lib/go/token/Makefile | 60 - src/lib/go/token/token.go | 347 ------ src/lib/hash/Makefile | 60 - src/lib/hash/adler32/Makefile | 60 - src/lib/hash/adler32/adler32.go | 96 -- src/lib/hash/adler32/adler32_test.go | 65 - src/lib/hash/crc32/Makefile | 60 - src/lib/hash/crc32/crc32.go | 120 -- src/lib/hash/crc32/crc32_test.go | 64 - src/lib/hash/hash.go | 24 - src/lib/hash/test_cases.txt | 31 - src/lib/hash/test_gen.awk | 14 - src/lib/http/Makefile | 85 -- src/lib/http/fs.go | 184 --- src/lib/http/request.go | 413 ------- src/lib/http/server.go | 575 --------- src/lib/http/status.go | 101 -- src/lib/http/triv.go | 159 --- src/lib/http/url.go | 303 ----- src/lib/http/url_test.go | 348 ------ src/lib/io/Makefile | 70 -- src/lib/io/bytebuffer.go | 109 -- src/lib/io/bytebuffer_test.go | 158 --- src/lib/io/io.go | 223 ---- src/lib/io/pipe.go | 226 ---- src/lib/io/pipe_test.go | 225 ---- src/lib/io/utils.go | 29 - src/lib/io/utils_test.go | 37 - src/lib/json/Makefile | 69 -- src/lib/json/generic.go | 331 ----- src/lib/json/generic_test.go | 76 -- src/lib/json/parse.go | 419 ------- src/lib/json/struct.go | 269 ---- src/lib/json/struct_test.go | 82 -- src/lib/log/Makefile | 60 - src/lib/log/log.go | 195 --- src/lib/log/log_test.go | 82 -- src/lib/malloc/Makefile | 60 - src/lib/malloc/malloc.go | 24 - src/lib/math/Makefile | 98 -- src/lib/math/all_test.go | 278 ----- src/lib/math/asin.go | 46 - src/lib/math/atan.go | 67 - src/lib/math/atan2.go | 28 - src/lib/math/const.go | 26 - src/lib/math/exp.go | 141 --- src/lib/math/fabs.go | 14 - src/lib/math/floor.go | 25 - src/lib/math/fmod.go | 41 - src/lib/math/hypot.go | 49 - src/lib/math/log.go | 131 -- src/lib/math/pow.go | 80 -- src/lib/math/pow10.go | 37 - src/lib/math/runtime.go | 52 - src/lib/math/sin.go | 65 - src/lib/math/sinh.go | 70 -- src/lib/math/sqrt.go | 66 - src/lib/math/tan.go | 67 - src/lib/math/tanh.go | 30 - src/lib/net/Makefile | 96 -- src/lib/net/dialgoogle_test.go | 100 -- src/lib/net/dnsclient.go | 227 ---- src/lib/net/dnsconfig.go | 113 -- src/lib/net/dnsmsg.go | 679 ---------- src/lib/net/fd.go | 429 ------- src/lib/net/fd_darwin.go | 115 -- src/lib/net/fd_linux.go | 150 --- src/lib/net/ip.go | 421 ------- src/lib/net/ip_test.go | 50 - src/lib/net/net.go | 862 ------------- src/lib/net/parse.go | 160 --- src/lib/net/parse_test.go | 44 - src/lib/net/port.go | 77 -- src/lib/net/port_test.go | 59 - src/lib/net/server_test.go | 93 -- src/lib/net/timeout_test.go | 42 - src/lib/once/Makefile | 60 - src/lib/once/once.go | 46 - src/lib/once/once_test.go | 31 - src/lib/os/Makefile | 91 -- src/lib/os/dir_darwin_386.go | 76 -- src/lib/os/dir_darwin_amd64.go | 76 -- src/lib/os/dir_linux_386.go | 83 -- src/lib/os/dir_linux_amd64.go | 79 -- src/lib/os/env.go | 80 -- src/lib/os/error.go | 83 -- src/lib/os/exec.go | 101 -- src/lib/os/file.go | 383 ------ src/lib/os/getwd.go | 94 -- src/lib/os/os_test.go | 549 --------- src/lib/os/path.go | 121 -- src/lib/os/path_test.go | 152 --- src/lib/os/proc.go | 50 - src/lib/os/proc_linux.go | 20 - src/lib/os/stat_darwin_386.go | 41 - src/lib/os/stat_darwin_amd64.go | 41 - src/lib/os/stat_linux_386.go | 47 - src/lib/os/stat_linux_amd64.go | 41 - src/lib/os/time.go | 24 - src/lib/os/types.go | 75 -- src/lib/path/Makefile | 60 - src/lib/path/path.go | 136 -- src/lib/path/path_test.go | 136 -- src/lib/rand/Makefile | 60 - src/lib/rand/rand.go | 318 ----- src/lib/reflect/Makefile | 78 -- src/lib/reflect/all_test.go | 613 ---------- src/lib/reflect/deepequal.go | 83 -- src/lib/reflect/tostring.go | 234 ---- src/lib/reflect/type.go | 1047 ---------------- src/lib/reflect/typestring.c | 37 - src/lib/reflect/value.go | 996 --------------- src/lib/regexp/Makefile | 60 - src/lib/regexp/all_test.go | 235 ---- src/lib/regexp/regexp.go | 764 ------------ src/lib/runtime/386/asm.s | 217 ---- src/lib/runtime/386/closure.c | 104 -- src/lib/runtime/386/traceback.c | 148 --- src/lib/runtime/386/vlop.s | 48 - src/lib/runtime/386/vlrt.c | 815 ------------ src/lib/runtime/Makefile | 125 -- src/lib/runtime/amd64/asm.s | 207 ---- src/lib/runtime/amd64/closure.c | 121 -- src/lib/runtime/amd64/traceback.c | 146 --- src/lib/runtime/arm/asm.s | 83 -- src/lib/runtime/arm/closure.c | 4 - src/lib/runtime/arm/traceback.s | 0 src/lib/runtime/array.c | 175 --- src/lib/runtime/cgo2c.c | 602 --------- src/lib/runtime/chan.c | 1024 ---------------- src/lib/runtime/darwin/386/defs.h | 229 ---- src/lib/runtime/darwin/386/rt0.s | 8 - src/lib/runtime/darwin/386/signal.c | 103 -- src/lib/runtime/darwin/386/sys.s | 278 ----- src/lib/runtime/darwin/amd64/defs.h | 244 ---- src/lib/runtime/darwin/amd64/rt0.s | 9 - src/lib/runtime/darwin/amd64/signal.c | 111 -- src/lib/runtime/darwin/amd64/sys.s | 263 ---- src/lib/runtime/darwin/defs.c | 104 -- src/lib/runtime/darwin/os.h | 24 - src/lib/runtime/darwin/signals.h | 48 - src/lib/runtime/darwin/thread.c | 441 ------- src/lib/runtime/extern.go | 28 - src/lib/runtime/float.c | 173 --- src/lib/runtime/float_go.cgo | 52 - src/lib/runtime/hashmap.c | 954 --------------- src/lib/runtime/hashmap.h | 161 --- src/lib/runtime/iface.c | 906 -------------- src/lib/runtime/linux/386/defs.h | 136 -- src/lib/runtime/linux/386/rt0.s | 8 - src/lib/runtime/linux/386/signal.c | 102 -- src/lib/runtime/linux/386/sys.s | 222 ---- src/lib/runtime/linux/amd64/defs.h | 175 --- src/lib/runtime/linux/amd64/rt0.s | 9 - src/lib/runtime/linux/amd64/signal.c | 112 -- src/lib/runtime/linux/amd64/sys.s | 193 --- src/lib/runtime/linux/arm/defs.h | 27 - src/lib/runtime/linux/arm/rt0.s | 6 - src/lib/runtime/linux/arm/signal.c | 4 - src/lib/runtime/linux/arm/sys.s | 15 - src/lib/runtime/linux/defs.c | 40 - src/lib/runtime/linux/defs1.c | 25 - src/lib/runtime/linux/defs2.c | 51 - src/lib/runtime/linux/defs_arm.c | 54 - src/lib/runtime/linux/os.h | 10 - src/lib/runtime/linux/signals.h | 48 - src/lib/runtime/linux/thread.c | 282 ----- src/lib/runtime/malloc.c | 308 ----- src/lib/runtime/malloc.h | 308 ----- src/lib/runtime/malloc_go.cgo | 28 - src/lib/runtime/mcache.c | 105 -- src/lib/runtime/mcentral.c | 192 --- src/lib/runtime/mem.c | 75 -- src/lib/runtime/mfixalloc.c | 56 - src/lib/runtime/mgc0.c | 231 ---- src/lib/runtime/mheap.c | 333 ----- src/lib/runtime/mheapmap32.c | 96 -- src/lib/runtime/mheapmap32.h | 76 -- src/lib/runtime/mheapmap64.c | 117 -- src/lib/runtime/mheapmap64.h | 96 -- src/lib/runtime/msize.c | 165 --- src/lib/runtime/print.c | 268 ---- src/lib/runtime/proc.c | 858 ------------- src/lib/runtime/rune.c | 238 ---- src/lib/runtime/runtime.c | 462 ------- src/lib/runtime/runtime.h | 464 ------- src/lib/runtime/sema.c | 176 --- src/lib/runtime/sema_go.cgo | 15 - src/lib/runtime/string.c | 263 ---- src/lib/runtime/symtab.c | 377 ------ src/lib/sort/Makefile | 60 - src/lib/sort/sort.go | 187 --- src/lib/sort/sort_test.go | 229 ---- src/lib/strconv/Makefile | 79 -- src/lib/strconv/atof.go | 372 ------ src/lib/strconv/atof_test.go | 133 -- src/lib/strconv/atoi.go | 166 --- src/lib/strconv/atoi_test.go | 188 --- src/lib/strconv/decimal.go | 392 ------ src/lib/strconv/decimal_test.go | 119 -- src/lib/strconv/fp_test.go | 149 --- src/lib/strconv/ftoa.go | 418 ------- src/lib/strconv/ftoa_test.go | 119 -- src/lib/strconv/itoa.go | 49 - src/lib/strconv/itoa_test.go | 111 -- src/lib/strconv/quote.go | 229 ---- src/lib/strconv/quote_test.go | 170 --- src/lib/strconv/testfp.txt | 181 --- src/lib/strings/Makefile | 60 - src/lib/strings/strings.go | 178 --- src/lib/strings/strings_test.go | 133 -- src/lib/sync/Makefile | 61 - src/lib/sync/asm_386.s | 23 - src/lib/sync/asm_amd64.s | 23 - src/lib/sync/mutex.go | 114 -- src/lib/sync/mutex_test.go | 53 - src/lib/syscall/Makefile | 97 -- src/lib/syscall/PORT | 124 -- src/lib/syscall/asm_darwin_386.s | 83 -- src/lib/syscall/asm_darwin_amd64.s | 74 -- src/lib/syscall/asm_linux_386.s | 108 -- src/lib/syscall/asm_linux_amd64.s | 78 -- src/lib/syscall/errstr.go | 30 - src/lib/syscall/exec.go | 305 ----- src/lib/syscall/mkerrors | 94 -- src/lib/syscall/mksyscall | 170 --- src/lib/syscall/mksysnum_darwin | 38 - src/lib/syscall/mksysnum_linux | 31 - src/lib/syscall/syscall.go | 37 - src/lib/syscall/syscall_darwin.go | 663 ---------- src/lib/syscall/syscall_darwin_386.go | 49 - src/lib/syscall/syscall_darwin_amd64.go | 49 - src/lib/syscall/syscall_linux.go | 636 ---------- src/lib/syscall/syscall_linux_386.go | 100 -- src/lib/syscall/syscall_linux_amd64.go | 41 - src/lib/syscall/types_darwin.c | 226 ---- src/lib/syscall/types_darwin_386.c | 5 - src/lib/syscall/types_darwin_amd64.c | 5 - src/lib/syscall/types_linux.c | 217 ---- src/lib/syscall/types_linux_386.c | 5 - src/lib/syscall/types_linux_amd64.c | 5 - src/lib/syscall/zerrors_darwin_386.go | 260 ---- src/lib/syscall/zerrors_darwin_amd64.go | 260 ---- src/lib/syscall/zerrors_linux_386.go | 316 ----- src/lib/syscall/zerrors_linux_amd64.go | 316 ----- src/lib/syscall/zsyscall_darwin_386.go | 624 ---------- src/lib/syscall/zsyscall_darwin_amd64.go | 624 ---------- src/lib/syscall/zsyscall_linux_386.go | 720 ----------- src/lib/syscall/zsyscall_linux_amd64.go | 764 ------------ src/lib/syscall/zsysnum_darwin_386.go | 485 -------- src/lib/syscall/zsysnum_darwin_amd64.go | 485 -------- src/lib/syscall/zsysnum_linux_386.go | 319 ----- src/lib/syscall/zsysnum_linux_amd64.go | 296 ----- src/lib/syscall/ztypes_darwin_386.go | 246 ---- src/lib/syscall/ztypes_darwin_amd64.go | 248 ---- src/lib/syscall/ztypes_linux_386.go | 297 ----- src/lib/syscall/ztypes_linux_amd64.go | 300 ----- src/lib/tabwriter/Makefile | 60 - src/lib/tabwriter/tabwriter.go | 437 ------- src/lib/tabwriter/tabwriter_test.go | 380 ------ src/lib/template/Makefile | 68 - src/lib/template/format.go | 54 - src/lib/template/template.go | 808 ------------ src/lib/template/template_test.go | 331 ----- src/lib/testing/Makefile | 60 - src/lib/testing/iotest/Makefile | 61 - src/lib/testing/iotest/logger.go | 55 - src/lib/testing/iotest/reader.go | 44 - src/lib/testing/testing.go | 155 --- src/lib/time/Makefile | 77 -- src/lib/time/sleep.go | 17 - src/lib/time/tick.go | 62 - src/lib/time/tick_test.go | 29 - src/lib/time/time.go | 372 ------ src/lib/time/time_test.go | 85 -- src/lib/time/zoneinfo.go | 285 ----- src/lib/unicode/Makefile | 68 - src/lib/unicode/decimaldigit.go | 52 - src/lib/unicode/decimaldigit_test.go | 375 ------ src/lib/unicode/letter.go | 578 --------- src/lib/unicode/letter_test.go | 129 -- src/lib/unsafe/unsafe.go | 44 - src/lib/utf8/Makefile | 60 - src/lib/utf8/utf8.go | 291 ----- src/lib/utf8/utf8_test.go | 168 --- src/lib/xml/xml.go | 426 ------- src/make.bash | 2 +- src/pkg/Make.deps | 52 + src/pkg/Makefile | 139 +++ src/pkg/archive/tar/Makefile | 60 + src/pkg/archive/tar/testdata/small.txt | 1 + src/pkg/archive/tar/testdata/small2.txt | 1 + src/pkg/archive/tar/testdata/test.tar | Bin 0 -> 3072 bytes src/pkg/archive/tar/untar.go | 242 ++++ src/pkg/archive/tar/untar_test.go | 69 ++ src/pkg/bignum/Makefile | 60 + src/pkg/bignum/bignum.go | 1464 ++++++++++++++++++++++ src/pkg/bignum/bignum_test.go | 482 ++++++++ src/pkg/bufio/Makefile | 60 + src/pkg/bufio/bufio.go | 515 ++++++++ src/pkg/bufio/bufio_test.go | 298 +++++ src/pkg/bytes/Makefile | 60 + src/pkg/bytes/bytes.go | 164 +++ src/pkg/bytes/bytes_test.go | 157 +++ src/pkg/compress/flate/Makefile | 60 + src/pkg/compress/flate/flate_test.go | 131 ++ src/pkg/compress/flate/inflate.go | 673 ++++++++++ src/pkg/compress/gzip/Makefile | 60 + src/pkg/compress/gzip/gunzip.go | 236 ++++ src/pkg/compress/gzip/gunzip_test.go | 268 ++++ src/pkg/container/list/Makefile | 60 + src/pkg/container/list/list.go | 130 ++ src/pkg/container/list/list_test.go | 91 ++ src/pkg/container/vector/Makefile | 69 ++ src/pkg/container/vector/intvector.go | 118 ++ src/pkg/container/vector/stringvector.go | 118 ++ src/pkg/container/vector/vector.go | 244 ++++ src/pkg/container/vector/vector_test.go | 209 ++++ src/pkg/crypto/aes/Makefile | 76 ++ src/pkg/crypto/aes/aes_test.go | 353 ++++++ src/pkg/crypto/aes/block.go | 182 +++ src/pkg/crypto/aes/cipher.go | 71 ++ src/pkg/crypto/aes/const.go | 363 ++++++ src/pkg/crypto/block/Makefile | 82 ++ src/pkg/crypto/block/cbc.go | 75 ++ src/pkg/crypto/block/cbc_aes_test.go | 107 ++ src/pkg/crypto/block/cfb.go | 100 ++ src/pkg/crypto/block/cfb_aes_test.go | 316 +++++ src/pkg/crypto/block/cipher.go | 74 ++ src/pkg/crypto/block/cmac.go | 105 ++ src/pkg/crypto/block/cmac_aes_test.go | 165 +++ src/pkg/crypto/block/ctr.go | 69 ++ src/pkg/crypto/block/ctr_aes_test.go | 115 ++ src/pkg/crypto/block/eax.go | 254 ++++ src/pkg/crypto/block/eax_aes_test.go | 239 ++++ src/pkg/crypto/block/ecb.go | 271 ++++ src/pkg/crypto/block/ecb_aes_test.go | 136 ++ src/pkg/crypto/block/ecb_test.go | 183 +++ src/pkg/crypto/block/ofb.go | 61 + src/pkg/crypto/block/ofb_aes_test.go | 113 ++ src/pkg/crypto/block/xor.go | 126 ++ src/pkg/crypto/block/xor_test.go | 169 +++ src/pkg/crypto/hmac/Makefile | 60 + src/pkg/crypto/hmac/hmac.go | 104 ++ src/pkg/crypto/hmac/hmac_test.go | 100 ++ src/pkg/crypto/md5/Makefile | 68 + src/pkg/crypto/md5/md5.go | 117 ++ src/pkg/crypto/md5/md5_test.go | 68 + src/pkg/crypto/md5/md5block.go | 178 +++ src/pkg/crypto/sha1/Makefile | 68 + src/pkg/crypto/sha1/sha1.go | 119 ++ src/pkg/crypto/sha1/sha1_test.go | 70 ++ src/pkg/crypto/sha1/sha1block.go | 86 ++ src/pkg/datafmt/Makefile | 68 + src/pkg/datafmt/datafmt.go | 789 ++++++++++++ src/pkg/datafmt/datafmt_test.go | 375 ++++++ src/pkg/datafmt/parser.go | 447 +++++++ src/pkg/exec/Makefile | 60 + src/pkg/exec/exec.go | 228 ++++ src/pkg/exec/exec_test.go | 51 + src/pkg/exvar/Makefile | 60 + src/pkg/exvar/exvar.go | 214 ++++ src/pkg/exvar/exvar_test.go | 93 ++ src/pkg/flag/Makefile | 60 + src/pkg/flag/flag.go | 486 ++++++++ src/pkg/flag/flag_test.go | 77 ++ src/pkg/fmt/Makefile | 68 + src/pkg/fmt/fmt_test.go | 247 ++++ src/pkg/fmt/format.go | 533 ++++++++ src/pkg/fmt/print.go | 705 +++++++++++ src/pkg/go/ast/Makefile | 68 + src/pkg/go/ast/ast.go | 772 ++++++++++++ src/pkg/go/ast/format.go | 123 ++ src/pkg/go/doc/Makefile | 68 + src/pkg/go/doc/comment.go | 310 +++++ src/pkg/go/doc/doc.go | 486 ++++++++ src/pkg/go/parser/Makefile | 60 + src/pkg/go/parser/parser.go | 1975 ++++++++++++++++++++++++++++++ src/pkg/go/parser/parser_test.go | 68 + src/pkg/go/scanner/Makefile | 60 + src/pkg/go/scanner/scanner.go | 501 ++++++++ src/pkg/go/scanner/scanner_test.go | 276 +++++ src/pkg/go/token/Makefile | 60 + src/pkg/go/token/token.go | 347 ++++++ src/pkg/hash/Makefile | 60 + src/pkg/hash/adler32/Makefile | 60 + src/pkg/hash/adler32/adler32.go | 96 ++ src/pkg/hash/adler32/adler32_test.go | 65 + src/pkg/hash/crc32/Makefile | 60 + src/pkg/hash/crc32/crc32.go | 120 ++ src/pkg/hash/crc32/crc32_test.go | 64 + src/pkg/hash/hash.go | 24 + src/pkg/hash/test_cases.txt | 31 + src/pkg/hash/test_gen.awk | 14 + src/pkg/http/Makefile | 85 ++ src/pkg/http/fs.go | 184 +++ src/pkg/http/request.go | 413 +++++++ src/pkg/http/server.go | 575 +++++++++ src/pkg/http/status.go | 101 ++ src/pkg/http/triv.go | 159 +++ src/pkg/http/url.go | 303 +++++ src/pkg/http/url_test.go | 348 ++++++ src/pkg/io/Makefile | 70 ++ src/pkg/io/bytebuffer.go | 109 ++ src/pkg/io/bytebuffer_test.go | 158 +++ src/pkg/io/io.go | 223 ++++ src/pkg/io/pipe.go | 226 ++++ src/pkg/io/pipe_test.go | 225 ++++ src/pkg/io/utils.go | 29 + src/pkg/io/utils_test.go | 37 + src/pkg/json/Makefile | 69 ++ src/pkg/json/generic.go | 331 +++++ src/pkg/json/generic_test.go | 76 ++ src/pkg/json/parse.go | 419 +++++++ src/pkg/json/struct.go | 269 ++++ src/pkg/json/struct_test.go | 82 ++ src/pkg/log/Makefile | 60 + src/pkg/log/log.go | 195 +++ src/pkg/log/log_test.go | 82 ++ src/pkg/malloc/Makefile | 60 + src/pkg/malloc/malloc.go | 24 + src/pkg/math/Makefile | 98 ++ src/pkg/math/all_test.go | 278 +++++ src/pkg/math/asin.go | 46 + src/pkg/math/atan.go | 67 + src/pkg/math/atan2.go | 28 + src/pkg/math/const.go | 26 + src/pkg/math/exp.go | 141 +++ src/pkg/math/fabs.go | 14 + src/pkg/math/floor.go | 25 + src/pkg/math/fmod.go | 41 + src/pkg/math/hypot.go | 49 + src/pkg/math/log.go | 131 ++ src/pkg/math/pow.go | 80 ++ src/pkg/math/pow10.go | 37 + src/pkg/math/runtime.go | 52 + src/pkg/math/sin.go | 65 + src/pkg/math/sinh.go | 70 ++ src/pkg/math/sqrt.go | 66 + src/pkg/math/tan.go | 67 + src/pkg/math/tanh.go | 30 + src/pkg/net/Makefile | 96 ++ src/pkg/net/dialgoogle_test.go | 100 ++ src/pkg/net/dnsclient.go | 227 ++++ src/pkg/net/dnsconfig.go | 113 ++ src/pkg/net/dnsmsg.go | 679 ++++++++++ src/pkg/net/fd.go | 429 +++++++ src/pkg/net/fd_darwin.go | 115 ++ src/pkg/net/fd_linux.go | 150 +++ src/pkg/net/ip.go | 421 +++++++ src/pkg/net/ip_test.go | 50 + src/pkg/net/net.go | 862 +++++++++++++ src/pkg/net/parse.go | 160 +++ src/pkg/net/parse_test.go | 44 + src/pkg/net/port.go | 77 ++ src/pkg/net/port_test.go | 59 + src/pkg/net/server_test.go | 93 ++ src/pkg/net/timeout_test.go | 42 + src/pkg/once/Makefile | 60 + src/pkg/once/once.go | 46 + src/pkg/once/once_test.go | 31 + src/pkg/os/Makefile | 91 ++ src/pkg/os/dir_darwin_386.go | 76 ++ src/pkg/os/dir_darwin_amd64.go | 76 ++ src/pkg/os/dir_linux_386.go | 83 ++ src/pkg/os/dir_linux_amd64.go | 79 ++ src/pkg/os/env.go | 80 ++ src/pkg/os/error.go | 83 ++ src/pkg/os/exec.go | 101 ++ src/pkg/os/file.go | 383 ++++++ src/pkg/os/getwd.go | 94 ++ src/pkg/os/os_test.go | 549 +++++++++ src/pkg/os/path.go | 121 ++ src/pkg/os/path_test.go | 152 +++ src/pkg/os/proc.go | 50 + src/pkg/os/proc_linux.go | 20 + src/pkg/os/stat_darwin_386.go | 41 + src/pkg/os/stat_darwin_amd64.go | 41 + src/pkg/os/stat_linux_386.go | 47 + src/pkg/os/stat_linux_amd64.go | 41 + src/pkg/os/time.go | 24 + src/pkg/os/types.go | 75 ++ src/pkg/path/Makefile | 60 + src/pkg/path/path.go | 136 ++ src/pkg/path/path_test.go | 136 ++ src/pkg/rand/Makefile | 60 + src/pkg/rand/rand.go | 318 +++++ src/pkg/reflect/Makefile | 78 ++ src/pkg/reflect/all_test.go | 613 ++++++++++ src/pkg/reflect/deepequal.go | 83 ++ src/pkg/reflect/tostring.go | 234 ++++ src/pkg/reflect/type.go | 1047 ++++++++++++++++ src/pkg/reflect/typestring.c | 37 + src/pkg/reflect/value.go | 996 +++++++++++++++ src/pkg/regexp/Makefile | 60 + src/pkg/regexp/all_test.go | 235 ++++ src/pkg/regexp/regexp.go | 764 ++++++++++++ src/pkg/runtime/386/asm.s | 217 ++++ src/pkg/runtime/386/closure.c | 104 ++ src/pkg/runtime/386/traceback.c | 148 +++ src/pkg/runtime/386/vlop.s | 48 + src/pkg/runtime/386/vlrt.c | 815 ++++++++++++ src/pkg/runtime/Makefile | 125 ++ src/pkg/runtime/amd64/asm.s | 207 ++++ src/pkg/runtime/amd64/closure.c | 121 ++ src/pkg/runtime/amd64/traceback.c | 146 +++ src/pkg/runtime/arm/asm.s | 83 ++ src/pkg/runtime/arm/closure.c | 3 + src/pkg/runtime/arm/traceback.s | 0 src/pkg/runtime/array.c | 175 +++ src/pkg/runtime/cgo2c.c | 602 +++++++++ src/pkg/runtime/chan.c | 1024 ++++++++++++++++ src/pkg/runtime/darwin/386/defs.h | 229 ++++ src/pkg/runtime/darwin/386/rt0.s | 8 + src/pkg/runtime/darwin/386/signal.c | 103 ++ src/pkg/runtime/darwin/386/sys.s | 278 +++++ src/pkg/runtime/darwin/amd64/defs.h | 244 ++++ src/pkg/runtime/darwin/amd64/rt0.s | 9 + src/pkg/runtime/darwin/amd64/signal.c | 111 ++ src/pkg/runtime/darwin/amd64/sys.s | 263 ++++ src/pkg/runtime/darwin/defs.c | 104 ++ src/pkg/runtime/darwin/os.h | 24 + src/pkg/runtime/darwin/signals.h | 47 + src/pkg/runtime/darwin/thread.c | 441 +++++++ src/pkg/runtime/extern.go | 28 + src/pkg/runtime/float.c | 173 +++ src/pkg/runtime/float_go.cgo | 52 + src/pkg/runtime/hashmap.c | 954 +++++++++++++++ src/pkg/runtime/hashmap.h | 160 +++ src/pkg/runtime/iface.c | 906 ++++++++++++++ src/pkg/runtime/linux/386/defs.h | 136 ++ src/pkg/runtime/linux/386/rt0.s | 8 + src/pkg/runtime/linux/386/signal.c | 102 ++ src/pkg/runtime/linux/386/sys.s | 222 ++++ src/pkg/runtime/linux/amd64/defs.h | 175 +++ src/pkg/runtime/linux/amd64/rt0.s | 9 + src/pkg/runtime/linux/amd64/signal.c | 112 ++ src/pkg/runtime/linux/amd64/sys.s | 193 +++ src/pkg/runtime/linux/arm/defs.h | 27 + src/pkg/runtime/linux/arm/rt0.s | 6 + src/pkg/runtime/linux/arm/signal.c | 4 + src/pkg/runtime/linux/arm/sys.s | 15 + src/pkg/runtime/linux/defs.c | 40 + src/pkg/runtime/linux/defs1.c | 25 + src/pkg/runtime/linux/defs2.c | 51 + src/pkg/runtime/linux/defs_arm.c | 54 + src/pkg/runtime/linux/os.h | 10 + src/pkg/runtime/linux/signals.h | 47 + src/pkg/runtime/linux/thread.c | 282 +++++ src/pkg/runtime/malloc.c | 308 +++++ src/pkg/runtime/malloc.h | 308 +++++ src/pkg/runtime/malloc_go.cgo | 28 + src/pkg/runtime/mcache.c | 105 ++ src/pkg/runtime/mcentral.c | 192 +++ src/pkg/runtime/mem.c | 75 ++ src/pkg/runtime/mfixalloc.c | 56 + src/pkg/runtime/mgc0.c | 231 ++++ src/pkg/runtime/mheap.c | 333 +++++ src/pkg/runtime/mheapmap32.c | 96 ++ src/pkg/runtime/mheapmap32.h | 76 ++ src/pkg/runtime/mheapmap64.c | 117 ++ src/pkg/runtime/mheapmap64.h | 96 ++ src/pkg/runtime/msize.c | 165 +++ src/pkg/runtime/print.c | 268 ++++ src/pkg/runtime/proc.c | 858 +++++++++++++ src/pkg/runtime/rune.c | 224 ++++ src/pkg/runtime/runtime.c | 462 +++++++ src/pkg/runtime/runtime.h | 464 +++++++ src/pkg/runtime/sema.c | 176 +++ src/pkg/runtime/sema_go.cgo | 15 + src/pkg/runtime/string.c | 263 ++++ src/pkg/runtime/symtab.c | 377 ++++++ src/pkg/sort/Makefile | 60 + src/pkg/sort/sort.go | 187 +++ src/pkg/sort/sort_test.go | 229 ++++ src/pkg/strconv/Makefile | 79 ++ src/pkg/strconv/atof.go | 372 ++++++ src/pkg/strconv/atof_test.go | 133 ++ src/pkg/strconv/atoi.go | 166 +++ src/pkg/strconv/atoi_test.go | 188 +++ src/pkg/strconv/decimal.go | 392 ++++++ src/pkg/strconv/decimal_test.go | 119 ++ src/pkg/strconv/fp_test.go | 149 +++ src/pkg/strconv/ftoa.go | 418 +++++++ src/pkg/strconv/ftoa_test.go | 119 ++ src/pkg/strconv/itoa.go | 49 + src/pkg/strconv/itoa_test.go | 111 ++ src/pkg/strconv/quote.go | 229 ++++ src/pkg/strconv/quote_test.go | 170 +++ src/pkg/strconv/testfp.txt | 181 +++ src/pkg/strings/Makefile | 60 + src/pkg/strings/strings.go | 178 +++ src/pkg/strings/strings_test.go | 133 ++ src/pkg/sync/Makefile | 61 + src/pkg/sync/asm_386.s | 23 + src/pkg/sync/asm_amd64.s | 23 + src/pkg/sync/mutex.go | 114 ++ src/pkg/sync/mutex_test.go | 53 + src/pkg/syscall/Makefile | 97 ++ src/pkg/syscall/PORT | 124 ++ src/pkg/syscall/asm_darwin_386.s | 83 ++ src/pkg/syscall/asm_darwin_amd64.s | 74 ++ src/pkg/syscall/asm_linux_386.s | 108 ++ src/pkg/syscall/asm_linux_amd64.s | 78 ++ src/pkg/syscall/errstr.go | 30 + src/pkg/syscall/exec.go | 305 +++++ src/pkg/syscall/mkerrors | 94 ++ src/pkg/syscall/mksyscall | 170 +++ src/pkg/syscall/mksysnum_darwin | 38 + src/pkg/syscall/mksysnum_linux | 31 + src/pkg/syscall/syscall.go | 37 + src/pkg/syscall/syscall_darwin.go | 663 ++++++++++ src/pkg/syscall/syscall_darwin_386.go | 49 + src/pkg/syscall/syscall_darwin_amd64.go | 49 + src/pkg/syscall/syscall_linux.go | 636 ++++++++++ src/pkg/syscall/syscall_linux_386.go | 100 ++ src/pkg/syscall/syscall_linux_amd64.go | 41 + src/pkg/syscall/types_darwin.c | 226 ++++ src/pkg/syscall/types_darwin_386.c | 1 + src/pkg/syscall/types_darwin_amd64.c | 1 + src/pkg/syscall/types_linux.c | 217 ++++ src/pkg/syscall/types_linux_386.c | 1 + src/pkg/syscall/types_linux_amd64.c | 1 + src/pkg/syscall/zerrors_darwin_386.go | 260 ++++ src/pkg/syscall/zerrors_darwin_amd64.go | 260 ++++ src/pkg/syscall/zerrors_linux_386.go | 316 +++++ src/pkg/syscall/zerrors_linux_amd64.go | 316 +++++ src/pkg/syscall/zsyscall_darwin_386.go | 624 ++++++++++ src/pkg/syscall/zsyscall_darwin_amd64.go | 624 ++++++++++ src/pkg/syscall/zsyscall_linux_386.go | 720 +++++++++++ src/pkg/syscall/zsyscall_linux_amd64.go | 764 ++++++++++++ src/pkg/syscall/zsysnum_darwin_386.go | 485 ++++++++ src/pkg/syscall/zsysnum_darwin_amd64.go | 485 ++++++++ src/pkg/syscall/zsysnum_linux_386.go | 319 +++++ src/pkg/syscall/zsysnum_linux_amd64.go | 296 +++++ src/pkg/syscall/ztypes_darwin_386.go | 246 ++++ src/pkg/syscall/ztypes_darwin_amd64.go | 248 ++++ src/pkg/syscall/ztypes_linux_386.go | 297 +++++ src/pkg/syscall/ztypes_linux_amd64.go | 300 +++++ src/pkg/tabwriter/Makefile | 60 + src/pkg/tabwriter/tabwriter.go | 437 +++++++ src/pkg/tabwriter/tabwriter_test.go | 380 ++++++ src/pkg/template/Makefile | 68 + src/pkg/template/format.go | 54 + src/pkg/template/template.go | 808 ++++++++++++ src/pkg/template/template_test.go | 331 +++++ src/pkg/testing/Makefile | 60 + src/pkg/testing/iotest/Makefile | 61 + src/pkg/testing/iotest/logger.go | 55 + src/pkg/testing/iotest/reader.go | 44 + src/pkg/testing/testing.go | 155 +++ src/pkg/time/Makefile | 77 ++ src/pkg/time/sleep.go | 17 + src/pkg/time/tick.go | 62 + src/pkg/time/tick_test.go | 29 + src/pkg/time/time.go | 372 ++++++ src/pkg/time/time_test.go | 85 ++ src/pkg/time/zoneinfo.go | 285 +++++ src/pkg/unicode/Makefile | 68 + src/pkg/unicode/decimaldigit.go | 52 + src/pkg/unicode/decimaldigit_test.go | 375 ++++++ src/pkg/unicode/letter.go | 578 +++++++++ src/pkg/unicode/letter_test.go | 129 ++ src/pkg/unsafe/unsafe.go | 44 + src/pkg/utf8/Makefile | 60 + src/pkg/utf8/utf8.go | 291 +++++ src/pkg/utf8/utf8_test.go | 168 +++ src/pkg/xml/xml.go | 426 +++++++ src/run.bash | 4 +- usr/gri/pretty/astprinter.go | 2 +- usr/gri/pretty/godoc.go | 2 +- 768 files changed, 73016 insertions(+), 73050 deletions(-) delete mode 100644 src/lib/Make.deps delete mode 100644 src/lib/Makefile delete mode 100644 src/lib/archive/tar/Makefile delete mode 100644 src/lib/archive/tar/testdata/small.txt delete mode 100644 src/lib/archive/tar/testdata/small2.txt delete mode 100644 src/lib/archive/tar/testdata/test.tar delete mode 100644 src/lib/archive/tar/untar.go delete mode 100644 src/lib/archive/tar/untar_test.go delete mode 100644 src/lib/bignum/Makefile delete mode 100755 src/lib/bignum/bignum.go delete mode 100644 src/lib/bignum/bignum_test.go delete mode 100644 src/lib/bufio/Makefile delete mode 100644 src/lib/bufio/bufio.go delete mode 100644 src/lib/bufio/bufio_test.go delete mode 100644 src/lib/bytes/Makefile delete mode 100644 src/lib/bytes/bytes.go delete mode 100644 src/lib/bytes/bytes_test.go delete mode 100644 src/lib/compress/flate/Makefile delete mode 100644 src/lib/compress/flate/flate_test.go delete mode 100644 src/lib/compress/flate/inflate.go delete mode 100644 src/lib/compress/gzip/Makefile delete mode 100644 src/lib/compress/gzip/gunzip.go delete mode 100644 src/lib/compress/gzip/gunzip_test.go delete mode 100644 src/lib/container/list/Makefile delete mode 100755 src/lib/container/list/list.go delete mode 100755 src/lib/container/list/list_test.go delete mode 100644 src/lib/container/vector/Makefile delete mode 100644 src/lib/container/vector/intvector.go delete mode 100644 src/lib/container/vector/stringvector.go delete mode 100644 src/lib/container/vector/vector.go delete mode 100644 src/lib/container/vector/vector_test.go delete mode 100644 src/lib/crypto/aes/Makefile delete mode 100644 src/lib/crypto/aes/aes_test.go delete mode 100644 src/lib/crypto/aes/block.go delete mode 100644 src/lib/crypto/aes/cipher.go delete mode 100644 src/lib/crypto/aes/const.go delete mode 100644 src/lib/crypto/block/Makefile delete mode 100644 src/lib/crypto/block/cbc.go delete mode 100644 src/lib/crypto/block/cbc_aes_test.go delete mode 100644 src/lib/crypto/block/cfb.go delete mode 100644 src/lib/crypto/block/cfb_aes_test.go delete mode 100644 src/lib/crypto/block/cipher.go delete mode 100644 src/lib/crypto/block/cmac.go delete mode 100644 src/lib/crypto/block/cmac_aes_test.go delete mode 100644 src/lib/crypto/block/ctr.go delete mode 100644 src/lib/crypto/block/ctr_aes_test.go delete mode 100644 src/lib/crypto/block/eax.go delete mode 100644 src/lib/crypto/block/eax_aes_test.go delete mode 100644 src/lib/crypto/block/ecb.go delete mode 100644 src/lib/crypto/block/ecb_aes_test.go delete mode 100644 src/lib/crypto/block/ecb_test.go delete mode 100644 src/lib/crypto/block/ofb.go delete mode 100644 src/lib/crypto/block/ofb_aes_test.go delete mode 100644 src/lib/crypto/block/xor.go delete mode 100644 src/lib/crypto/block/xor_test.go delete mode 100644 src/lib/crypto/hmac/Makefile delete mode 100644 src/lib/crypto/hmac/hmac.go delete mode 100644 src/lib/crypto/hmac/hmac_test.go delete mode 100644 src/lib/crypto/md5/Makefile delete mode 100644 src/lib/crypto/md5/md5.go delete mode 100644 src/lib/crypto/md5/md5_test.go delete mode 100644 src/lib/crypto/md5/md5block.go delete mode 100644 src/lib/crypto/sha1/Makefile delete mode 100644 src/lib/crypto/sha1/sha1.go delete mode 100644 src/lib/crypto/sha1/sha1_test.go delete mode 100644 src/lib/crypto/sha1/sha1block.go delete mode 100644 src/lib/datafmt/Makefile delete mode 100644 src/lib/datafmt/datafmt.go delete mode 100644 src/lib/datafmt/datafmt_test.go delete mode 100644 src/lib/datafmt/parser.go delete mode 100644 src/lib/exec/Makefile delete mode 100644 src/lib/exec/exec.go delete mode 100644 src/lib/exec/exec_test.go delete mode 100644 src/lib/exvar/Makefile delete mode 100644 src/lib/exvar/exvar.go delete mode 100644 src/lib/exvar/exvar_test.go delete mode 100644 src/lib/flag/Makefile delete mode 100644 src/lib/flag/flag.go delete mode 100644 src/lib/flag/flag_test.go delete mode 100644 src/lib/fmt/Makefile delete mode 100644 src/lib/fmt/fmt_test.go delete mode 100644 src/lib/fmt/format.go delete mode 100644 src/lib/fmt/print.go delete mode 100644 src/lib/go/ast/Makefile delete mode 100644 src/lib/go/ast/ast.go delete mode 100644 src/lib/go/ast/format.go delete mode 100644 src/lib/go/doc/Makefile delete mode 100644 src/lib/go/doc/comment.go delete mode 100644 src/lib/go/doc/doc.go delete mode 100644 src/lib/go/parser/Makefile delete mode 100644 src/lib/go/parser/parser.go delete mode 100644 src/lib/go/parser/parser_test.go delete mode 100644 src/lib/go/scanner/Makefile delete mode 100644 src/lib/go/scanner/scanner.go delete mode 100644 src/lib/go/scanner/scanner_test.go delete mode 100644 src/lib/go/token/Makefile delete mode 100644 src/lib/go/token/token.go delete mode 100644 src/lib/hash/Makefile delete mode 100644 src/lib/hash/adler32/Makefile delete mode 100644 src/lib/hash/adler32/adler32.go delete mode 100644 src/lib/hash/adler32/adler32_test.go delete mode 100644 src/lib/hash/crc32/Makefile delete mode 100644 src/lib/hash/crc32/crc32.go delete mode 100644 src/lib/hash/crc32/crc32_test.go delete mode 100644 src/lib/hash/hash.go delete mode 100644 src/lib/hash/test_cases.txt delete mode 100644 src/lib/hash/test_gen.awk delete mode 100644 src/lib/http/Makefile delete mode 100644 src/lib/http/fs.go delete mode 100644 src/lib/http/request.go delete mode 100644 src/lib/http/server.go delete mode 100644 src/lib/http/status.go delete mode 100644 src/lib/http/triv.go delete mode 100644 src/lib/http/url.go delete mode 100644 src/lib/http/url_test.go delete mode 100644 src/lib/io/Makefile delete mode 100644 src/lib/io/bytebuffer.go delete mode 100644 src/lib/io/bytebuffer_test.go delete mode 100644 src/lib/io/io.go delete mode 100644 src/lib/io/pipe.go delete mode 100644 src/lib/io/pipe_test.go delete mode 100644 src/lib/io/utils.go delete mode 100644 src/lib/io/utils_test.go delete mode 100644 src/lib/json/Makefile delete mode 100644 src/lib/json/generic.go delete mode 100644 src/lib/json/generic_test.go delete mode 100644 src/lib/json/parse.go delete mode 100644 src/lib/json/struct.go delete mode 100644 src/lib/json/struct_test.go delete mode 100644 src/lib/log/Makefile delete mode 100644 src/lib/log/log.go delete mode 100644 src/lib/log/log_test.go delete mode 100644 src/lib/malloc/Makefile delete mode 100644 src/lib/malloc/malloc.go delete mode 100644 src/lib/math/Makefile delete mode 100644 src/lib/math/all_test.go delete mode 100644 src/lib/math/asin.go delete mode 100644 src/lib/math/atan.go delete mode 100644 src/lib/math/atan2.go delete mode 100644 src/lib/math/const.go delete mode 100644 src/lib/math/exp.go delete mode 100644 src/lib/math/fabs.go delete mode 100644 src/lib/math/floor.go delete mode 100644 src/lib/math/fmod.go delete mode 100644 src/lib/math/hypot.go delete mode 100644 src/lib/math/log.go delete mode 100644 src/lib/math/pow.go delete mode 100644 src/lib/math/pow10.go delete mode 100644 src/lib/math/runtime.go delete mode 100644 src/lib/math/sin.go delete mode 100644 src/lib/math/sinh.go delete mode 100644 src/lib/math/sqrt.go delete mode 100644 src/lib/math/tan.go delete mode 100644 src/lib/math/tanh.go delete mode 100644 src/lib/net/Makefile delete mode 100644 src/lib/net/dialgoogle_test.go delete mode 100644 src/lib/net/dnsclient.go delete mode 100644 src/lib/net/dnsconfig.go delete mode 100644 src/lib/net/dnsmsg.go delete mode 100644 src/lib/net/fd.go delete mode 100644 src/lib/net/fd_darwin.go delete mode 100644 src/lib/net/fd_linux.go delete mode 100644 src/lib/net/ip.go delete mode 100644 src/lib/net/ip_test.go delete mode 100644 src/lib/net/net.go delete mode 100644 src/lib/net/parse.go delete mode 100644 src/lib/net/parse_test.go delete mode 100644 src/lib/net/port.go delete mode 100644 src/lib/net/port_test.go delete mode 100644 src/lib/net/server_test.go delete mode 100644 src/lib/net/timeout_test.go delete mode 100644 src/lib/once/Makefile delete mode 100644 src/lib/once/once.go delete mode 100644 src/lib/once/once_test.go delete mode 100644 src/lib/os/Makefile delete mode 100644 src/lib/os/dir_darwin_386.go delete mode 100644 src/lib/os/dir_darwin_amd64.go delete mode 100644 src/lib/os/dir_linux_386.go delete mode 100644 src/lib/os/dir_linux_amd64.go delete mode 100644 src/lib/os/env.go delete mode 100644 src/lib/os/error.go delete mode 100644 src/lib/os/exec.go delete mode 100644 src/lib/os/file.go delete mode 100644 src/lib/os/getwd.go delete mode 100644 src/lib/os/os_test.go delete mode 100644 src/lib/os/path.go delete mode 100644 src/lib/os/path_test.go delete mode 100644 src/lib/os/proc.go delete mode 100644 src/lib/os/proc_linux.go delete mode 100644 src/lib/os/stat_darwin_386.go delete mode 100644 src/lib/os/stat_darwin_amd64.go delete mode 100644 src/lib/os/stat_linux_386.go delete mode 100644 src/lib/os/stat_linux_amd64.go delete mode 100644 src/lib/os/time.go delete mode 100644 src/lib/os/types.go delete mode 100644 src/lib/path/Makefile delete mode 100644 src/lib/path/path.go delete mode 100644 src/lib/path/path_test.go delete mode 100644 src/lib/rand/Makefile delete mode 100644 src/lib/rand/rand.go delete mode 100644 src/lib/reflect/Makefile delete mode 100644 src/lib/reflect/all_test.go delete mode 100644 src/lib/reflect/deepequal.go delete mode 100644 src/lib/reflect/tostring.go delete mode 100644 src/lib/reflect/type.go delete mode 100644 src/lib/reflect/typestring.c delete mode 100644 src/lib/reflect/value.go delete mode 100644 src/lib/regexp/Makefile delete mode 100644 src/lib/regexp/all_test.go delete mode 100644 src/lib/regexp/regexp.go delete mode 100644 src/lib/runtime/386/asm.s delete mode 100644 src/lib/runtime/386/closure.c delete mode 100644 src/lib/runtime/386/traceback.c delete mode 100755 src/lib/runtime/386/vlop.s delete mode 100755 src/lib/runtime/386/vlrt.c delete mode 100644 src/lib/runtime/Makefile delete mode 100644 src/lib/runtime/amd64/asm.s delete mode 100644 src/lib/runtime/amd64/closure.c delete mode 100644 src/lib/runtime/amd64/traceback.c delete mode 100644 src/lib/runtime/arm/asm.s delete mode 100644 src/lib/runtime/arm/closure.c delete mode 100644 src/lib/runtime/arm/traceback.s delete mode 100644 src/lib/runtime/array.c delete mode 100644 src/lib/runtime/cgo2c.c delete mode 100644 src/lib/runtime/chan.c delete mode 100644 src/lib/runtime/darwin/386/defs.h delete mode 100755 src/lib/runtime/darwin/386/rt0.s delete mode 100644 src/lib/runtime/darwin/386/signal.c delete mode 100644 src/lib/runtime/darwin/386/sys.s delete mode 100644 src/lib/runtime/darwin/amd64/defs.h delete mode 100644 src/lib/runtime/darwin/amd64/rt0.s delete mode 100644 src/lib/runtime/darwin/amd64/signal.c delete mode 100644 src/lib/runtime/darwin/amd64/sys.s delete mode 100644 src/lib/runtime/darwin/defs.c delete mode 100644 src/lib/runtime/darwin/os.h delete mode 100644 src/lib/runtime/darwin/signals.h delete mode 100644 src/lib/runtime/darwin/thread.c delete mode 100644 src/lib/runtime/extern.go delete mode 100644 src/lib/runtime/float.c delete mode 100644 src/lib/runtime/float_go.cgo delete mode 100644 src/lib/runtime/hashmap.c delete mode 100644 src/lib/runtime/hashmap.h delete mode 100644 src/lib/runtime/iface.c delete mode 100755 src/lib/runtime/linux/386/defs.h delete mode 100755 src/lib/runtime/linux/386/rt0.s delete mode 100644 src/lib/runtime/linux/386/signal.c delete mode 100755 src/lib/runtime/linux/386/sys.s delete mode 100644 src/lib/runtime/linux/amd64/defs.h delete mode 100644 src/lib/runtime/linux/amd64/rt0.s delete mode 100644 src/lib/runtime/linux/amd64/signal.c delete mode 100644 src/lib/runtime/linux/amd64/sys.s delete mode 100644 src/lib/runtime/linux/arm/defs.h delete mode 100644 src/lib/runtime/linux/arm/rt0.s delete mode 100644 src/lib/runtime/linux/arm/signal.c delete mode 100644 src/lib/runtime/linux/arm/sys.s delete mode 100644 src/lib/runtime/linux/defs.c delete mode 100644 src/lib/runtime/linux/defs1.c delete mode 100644 src/lib/runtime/linux/defs2.c delete mode 100644 src/lib/runtime/linux/defs_arm.c delete mode 100644 src/lib/runtime/linux/os.h delete mode 100644 src/lib/runtime/linux/signals.h delete mode 100644 src/lib/runtime/linux/thread.c delete mode 100644 src/lib/runtime/malloc.c delete mode 100644 src/lib/runtime/malloc.h delete mode 100644 src/lib/runtime/malloc_go.cgo delete mode 100644 src/lib/runtime/mcache.c delete mode 100644 src/lib/runtime/mcentral.c delete mode 100644 src/lib/runtime/mem.c delete mode 100644 src/lib/runtime/mfixalloc.c delete mode 100644 src/lib/runtime/mgc0.c delete mode 100644 src/lib/runtime/mheap.c delete mode 100644 src/lib/runtime/mheapmap32.c delete mode 100644 src/lib/runtime/mheapmap32.h delete mode 100644 src/lib/runtime/mheapmap64.c delete mode 100644 src/lib/runtime/mheapmap64.h delete mode 100644 src/lib/runtime/msize.c delete mode 100644 src/lib/runtime/print.c delete mode 100644 src/lib/runtime/proc.c delete mode 100644 src/lib/runtime/rune.c delete mode 100644 src/lib/runtime/runtime.c delete mode 100644 src/lib/runtime/runtime.h delete mode 100644 src/lib/runtime/sema.c delete mode 100644 src/lib/runtime/sema_go.cgo delete mode 100644 src/lib/runtime/string.c delete mode 100644 src/lib/runtime/symtab.c delete mode 100644 src/lib/sort/Makefile delete mode 100644 src/lib/sort/sort.go delete mode 100644 src/lib/sort/sort_test.go delete mode 100644 src/lib/strconv/Makefile delete mode 100644 src/lib/strconv/atof.go delete mode 100644 src/lib/strconv/atof_test.go delete mode 100644 src/lib/strconv/atoi.go delete mode 100644 src/lib/strconv/atoi_test.go delete mode 100644 src/lib/strconv/decimal.go delete mode 100644 src/lib/strconv/decimal_test.go delete mode 100644 src/lib/strconv/fp_test.go delete mode 100644 src/lib/strconv/ftoa.go delete mode 100644 src/lib/strconv/ftoa_test.go delete mode 100644 src/lib/strconv/itoa.go delete mode 100644 src/lib/strconv/itoa_test.go delete mode 100644 src/lib/strconv/quote.go delete mode 100644 src/lib/strconv/quote_test.go delete mode 100644 src/lib/strconv/testfp.txt delete mode 100644 src/lib/strings/Makefile delete mode 100644 src/lib/strings/strings.go delete mode 100644 src/lib/strings/strings_test.go delete mode 100644 src/lib/sync/Makefile delete mode 100644 src/lib/sync/asm_386.s delete mode 100644 src/lib/sync/asm_amd64.s delete mode 100644 src/lib/sync/mutex.go delete mode 100644 src/lib/sync/mutex_test.go delete mode 100644 src/lib/syscall/Makefile delete mode 100755 src/lib/syscall/PORT delete mode 100644 src/lib/syscall/asm_darwin_386.s delete mode 100644 src/lib/syscall/asm_darwin_amd64.s delete mode 100644 src/lib/syscall/asm_linux_386.s delete mode 100644 src/lib/syscall/asm_linux_amd64.s delete mode 100644 src/lib/syscall/errstr.go delete mode 100644 src/lib/syscall/exec.go delete mode 100755 src/lib/syscall/mkerrors delete mode 100755 src/lib/syscall/mksyscall delete mode 100755 src/lib/syscall/mksysnum_darwin delete mode 100755 src/lib/syscall/mksysnum_linux delete mode 100644 src/lib/syscall/syscall.go delete mode 100644 src/lib/syscall/syscall_darwin.go delete mode 100644 src/lib/syscall/syscall_darwin_386.go delete mode 100644 src/lib/syscall/syscall_darwin_amd64.go delete mode 100644 src/lib/syscall/syscall_linux.go delete mode 100644 src/lib/syscall/syscall_linux_386.go delete mode 100644 src/lib/syscall/syscall_linux_amd64.go delete mode 100644 src/lib/syscall/types_darwin.c delete mode 100644 src/lib/syscall/types_darwin_386.c delete mode 100644 src/lib/syscall/types_darwin_amd64.c delete mode 100644 src/lib/syscall/types_linux.c delete mode 100644 src/lib/syscall/types_linux_386.c delete mode 100644 src/lib/syscall/types_linux_amd64.c delete mode 100644 src/lib/syscall/zerrors_darwin_386.go delete mode 100644 src/lib/syscall/zerrors_darwin_amd64.go delete mode 100644 src/lib/syscall/zerrors_linux_386.go delete mode 100644 src/lib/syscall/zerrors_linux_amd64.go delete mode 100644 src/lib/syscall/zsyscall_darwin_386.go delete mode 100644 src/lib/syscall/zsyscall_darwin_amd64.go delete mode 100644 src/lib/syscall/zsyscall_linux_386.go delete mode 100644 src/lib/syscall/zsyscall_linux_amd64.go delete mode 100644 src/lib/syscall/zsysnum_darwin_386.go delete mode 100644 src/lib/syscall/zsysnum_darwin_amd64.go delete mode 100644 src/lib/syscall/zsysnum_linux_386.go delete mode 100644 src/lib/syscall/zsysnum_linux_amd64.go delete mode 100644 src/lib/syscall/ztypes_darwin_386.go delete mode 100644 src/lib/syscall/ztypes_darwin_amd64.go delete mode 100644 src/lib/syscall/ztypes_linux_386.go delete mode 100644 src/lib/syscall/ztypes_linux_amd64.go delete mode 100644 src/lib/tabwriter/Makefile delete mode 100644 src/lib/tabwriter/tabwriter.go delete mode 100644 src/lib/tabwriter/tabwriter_test.go delete mode 100644 src/lib/template/Makefile delete mode 100644 src/lib/template/format.go delete mode 100644 src/lib/template/template.go delete mode 100644 src/lib/template/template_test.go delete mode 100644 src/lib/testing/Makefile delete mode 100644 src/lib/testing/iotest/Makefile delete mode 100644 src/lib/testing/iotest/logger.go delete mode 100644 src/lib/testing/iotest/reader.go delete mode 100644 src/lib/testing/testing.go delete mode 100644 src/lib/time/Makefile delete mode 100644 src/lib/time/sleep.go delete mode 100644 src/lib/time/tick.go delete mode 100644 src/lib/time/tick_test.go delete mode 100644 src/lib/time/time.go delete mode 100644 src/lib/time/time_test.go delete mode 100644 src/lib/time/zoneinfo.go delete mode 100644 src/lib/unicode/Makefile delete mode 100644 src/lib/unicode/decimaldigit.go delete mode 100644 src/lib/unicode/decimaldigit_test.go delete mode 100644 src/lib/unicode/letter.go delete mode 100644 src/lib/unicode/letter_test.go delete mode 100644 src/lib/unsafe/unsafe.go delete mode 100644 src/lib/utf8/Makefile delete mode 100644 src/lib/utf8/utf8.go delete mode 100644 src/lib/utf8/utf8_test.go delete mode 100644 src/lib/xml/xml.go create mode 100644 src/pkg/Make.deps create mode 100644 src/pkg/Makefile create mode 100644 src/pkg/archive/tar/Makefile create mode 100644 src/pkg/archive/tar/testdata/small.txt create mode 100644 src/pkg/archive/tar/testdata/small2.txt create mode 100644 src/pkg/archive/tar/testdata/test.tar create mode 100644 src/pkg/archive/tar/untar.go create mode 100644 src/pkg/archive/tar/untar_test.go create mode 100644 src/pkg/bignum/Makefile create mode 100755 src/pkg/bignum/bignum.go create mode 100644 src/pkg/bignum/bignum_test.go create mode 100644 src/pkg/bufio/Makefile create mode 100644 src/pkg/bufio/bufio.go create mode 100644 src/pkg/bufio/bufio_test.go create mode 100644 src/pkg/bytes/Makefile create mode 100644 src/pkg/bytes/bytes.go create mode 100644 src/pkg/bytes/bytes_test.go create mode 100644 src/pkg/compress/flate/Makefile create mode 100644 src/pkg/compress/flate/flate_test.go create mode 100644 src/pkg/compress/flate/inflate.go create mode 100644 src/pkg/compress/gzip/Makefile create mode 100644 src/pkg/compress/gzip/gunzip.go create mode 100644 src/pkg/compress/gzip/gunzip_test.go create mode 100644 src/pkg/container/list/Makefile create mode 100755 src/pkg/container/list/list.go create mode 100755 src/pkg/container/list/list_test.go create mode 100644 src/pkg/container/vector/Makefile create mode 100644 src/pkg/container/vector/intvector.go create mode 100644 src/pkg/container/vector/stringvector.go create mode 100644 src/pkg/container/vector/vector.go create mode 100644 src/pkg/container/vector/vector_test.go create mode 100644 src/pkg/crypto/aes/Makefile create mode 100644 src/pkg/crypto/aes/aes_test.go create mode 100644 src/pkg/crypto/aes/block.go create mode 100644 src/pkg/crypto/aes/cipher.go create mode 100644 src/pkg/crypto/aes/const.go create mode 100644 src/pkg/crypto/block/Makefile create mode 100644 src/pkg/crypto/block/cbc.go create mode 100644 src/pkg/crypto/block/cbc_aes_test.go create mode 100644 src/pkg/crypto/block/cfb.go create mode 100644 src/pkg/crypto/block/cfb_aes_test.go create mode 100644 src/pkg/crypto/block/cipher.go create mode 100644 src/pkg/crypto/block/cmac.go create mode 100644 src/pkg/crypto/block/cmac_aes_test.go create mode 100644 src/pkg/crypto/block/ctr.go create mode 100644 src/pkg/crypto/block/ctr_aes_test.go create mode 100644 src/pkg/crypto/block/eax.go create mode 100644 src/pkg/crypto/block/eax_aes_test.go create mode 100644 src/pkg/crypto/block/ecb.go create mode 100644 src/pkg/crypto/block/ecb_aes_test.go create mode 100644 src/pkg/crypto/block/ecb_test.go create mode 100644 src/pkg/crypto/block/ofb.go create mode 100644 src/pkg/crypto/block/ofb_aes_test.go create mode 100644 src/pkg/crypto/block/xor.go create mode 100644 src/pkg/crypto/block/xor_test.go create mode 100644 src/pkg/crypto/hmac/Makefile create mode 100644 src/pkg/crypto/hmac/hmac.go create mode 100644 src/pkg/crypto/hmac/hmac_test.go create mode 100644 src/pkg/crypto/md5/Makefile create mode 100644 src/pkg/crypto/md5/md5.go create mode 100644 src/pkg/crypto/md5/md5_test.go create mode 100644 src/pkg/crypto/md5/md5block.go create mode 100644 src/pkg/crypto/sha1/Makefile create mode 100644 src/pkg/crypto/sha1/sha1.go create mode 100644 src/pkg/crypto/sha1/sha1_test.go create mode 100644 src/pkg/crypto/sha1/sha1block.go create mode 100644 src/pkg/datafmt/Makefile create mode 100644 src/pkg/datafmt/datafmt.go create mode 100644 src/pkg/datafmt/datafmt_test.go create mode 100644 src/pkg/datafmt/parser.go create mode 100644 src/pkg/exec/Makefile create mode 100644 src/pkg/exec/exec.go create mode 100644 src/pkg/exec/exec_test.go create mode 100644 src/pkg/exvar/Makefile create mode 100644 src/pkg/exvar/exvar.go create mode 100644 src/pkg/exvar/exvar_test.go create mode 100644 src/pkg/flag/Makefile create mode 100644 src/pkg/flag/flag.go create mode 100644 src/pkg/flag/flag_test.go create mode 100644 src/pkg/fmt/Makefile create mode 100644 src/pkg/fmt/fmt_test.go create mode 100644 src/pkg/fmt/format.go create mode 100644 src/pkg/fmt/print.go create mode 100644 src/pkg/go/ast/Makefile create mode 100644 src/pkg/go/ast/ast.go create mode 100644 src/pkg/go/ast/format.go create mode 100644 src/pkg/go/doc/Makefile create mode 100644 src/pkg/go/doc/comment.go create mode 100644 src/pkg/go/doc/doc.go create mode 100644 src/pkg/go/parser/Makefile create mode 100644 src/pkg/go/parser/parser.go create mode 100644 src/pkg/go/parser/parser_test.go create mode 100644 src/pkg/go/scanner/Makefile create mode 100644 src/pkg/go/scanner/scanner.go create mode 100644 src/pkg/go/scanner/scanner_test.go create mode 100644 src/pkg/go/token/Makefile create mode 100644 src/pkg/go/token/token.go create mode 100644 src/pkg/hash/Makefile create mode 100644 src/pkg/hash/adler32/Makefile create mode 100644 src/pkg/hash/adler32/adler32.go create mode 100644 src/pkg/hash/adler32/adler32_test.go create mode 100644 src/pkg/hash/crc32/Makefile create mode 100644 src/pkg/hash/crc32/crc32.go create mode 100644 src/pkg/hash/crc32/crc32_test.go create mode 100644 src/pkg/hash/hash.go create mode 100644 src/pkg/hash/test_cases.txt create mode 100644 src/pkg/hash/test_gen.awk create mode 100644 src/pkg/http/Makefile create mode 100644 src/pkg/http/fs.go create mode 100644 src/pkg/http/request.go create mode 100644 src/pkg/http/server.go create mode 100644 src/pkg/http/status.go create mode 100644 src/pkg/http/triv.go create mode 100644 src/pkg/http/url.go create mode 100644 src/pkg/http/url_test.go create mode 100644 src/pkg/io/Makefile create mode 100644 src/pkg/io/bytebuffer.go create mode 100644 src/pkg/io/bytebuffer_test.go create mode 100644 src/pkg/io/io.go create mode 100644 src/pkg/io/pipe.go create mode 100644 src/pkg/io/pipe_test.go create mode 100644 src/pkg/io/utils.go create mode 100644 src/pkg/io/utils_test.go create mode 100644 src/pkg/json/Makefile create mode 100644 src/pkg/json/generic.go create mode 100644 src/pkg/json/generic_test.go create mode 100644 src/pkg/json/parse.go create mode 100644 src/pkg/json/struct.go create mode 100644 src/pkg/json/struct_test.go create mode 100644 src/pkg/log/Makefile create mode 100644 src/pkg/log/log.go create mode 100644 src/pkg/log/log_test.go create mode 100644 src/pkg/malloc/Makefile create mode 100644 src/pkg/malloc/malloc.go create mode 100644 src/pkg/math/Makefile create mode 100644 src/pkg/math/all_test.go create mode 100644 src/pkg/math/asin.go create mode 100644 src/pkg/math/atan.go create mode 100644 src/pkg/math/atan2.go create mode 100644 src/pkg/math/const.go create mode 100644 src/pkg/math/exp.go create mode 100644 src/pkg/math/fabs.go create mode 100644 src/pkg/math/floor.go create mode 100644 src/pkg/math/fmod.go create mode 100644 src/pkg/math/hypot.go create mode 100644 src/pkg/math/log.go create mode 100644 src/pkg/math/pow.go create mode 100644 src/pkg/math/pow10.go create mode 100644 src/pkg/math/runtime.go create mode 100644 src/pkg/math/sin.go create mode 100644 src/pkg/math/sinh.go create mode 100644 src/pkg/math/sqrt.go create mode 100644 src/pkg/math/tan.go create mode 100644 src/pkg/math/tanh.go create mode 100644 src/pkg/net/Makefile create mode 100644 src/pkg/net/dialgoogle_test.go create mode 100644 src/pkg/net/dnsclient.go create mode 100644 src/pkg/net/dnsconfig.go create mode 100644 src/pkg/net/dnsmsg.go create mode 100644 src/pkg/net/fd.go create mode 100644 src/pkg/net/fd_darwin.go create mode 100644 src/pkg/net/fd_linux.go create mode 100644 src/pkg/net/ip.go create mode 100644 src/pkg/net/ip_test.go create mode 100644 src/pkg/net/net.go create mode 100644 src/pkg/net/parse.go create mode 100644 src/pkg/net/parse_test.go create mode 100644 src/pkg/net/port.go create mode 100644 src/pkg/net/port_test.go create mode 100644 src/pkg/net/server_test.go create mode 100644 src/pkg/net/timeout_test.go create mode 100644 src/pkg/once/Makefile create mode 100644 src/pkg/once/once.go create mode 100644 src/pkg/once/once_test.go create mode 100644 src/pkg/os/Makefile create mode 100644 src/pkg/os/dir_darwin_386.go create mode 100644 src/pkg/os/dir_darwin_amd64.go create mode 100644 src/pkg/os/dir_linux_386.go create mode 100644 src/pkg/os/dir_linux_amd64.go create mode 100644 src/pkg/os/env.go create mode 100644 src/pkg/os/error.go create mode 100644 src/pkg/os/exec.go create mode 100644 src/pkg/os/file.go create mode 100644 src/pkg/os/getwd.go create mode 100644 src/pkg/os/os_test.go create mode 100644 src/pkg/os/path.go create mode 100644 src/pkg/os/path_test.go create mode 100644 src/pkg/os/proc.go create mode 100644 src/pkg/os/proc_linux.go create mode 100644 src/pkg/os/stat_darwin_386.go create mode 100644 src/pkg/os/stat_darwin_amd64.go create mode 100644 src/pkg/os/stat_linux_386.go create mode 100644 src/pkg/os/stat_linux_amd64.go create mode 100644 src/pkg/os/time.go create mode 100644 src/pkg/os/types.go create mode 100644 src/pkg/path/Makefile create mode 100644 src/pkg/path/path.go create mode 100644 src/pkg/path/path_test.go create mode 100644 src/pkg/rand/Makefile create mode 100644 src/pkg/rand/rand.go create mode 100644 src/pkg/reflect/Makefile create mode 100644 src/pkg/reflect/all_test.go create mode 100644 src/pkg/reflect/deepequal.go create mode 100644 src/pkg/reflect/tostring.go create mode 100644 src/pkg/reflect/type.go create mode 100644 src/pkg/reflect/typestring.c create mode 100644 src/pkg/reflect/value.go create mode 100644 src/pkg/regexp/Makefile create mode 100644 src/pkg/regexp/all_test.go create mode 100644 src/pkg/regexp/regexp.go create mode 100644 src/pkg/runtime/386/asm.s create mode 100644 src/pkg/runtime/386/closure.c create mode 100644 src/pkg/runtime/386/traceback.c create mode 100755 src/pkg/runtime/386/vlop.s create mode 100755 src/pkg/runtime/386/vlrt.c create mode 100644 src/pkg/runtime/Makefile create mode 100644 src/pkg/runtime/amd64/asm.s create mode 100644 src/pkg/runtime/amd64/closure.c create mode 100644 src/pkg/runtime/amd64/traceback.c create mode 100644 src/pkg/runtime/arm/asm.s create mode 100644 src/pkg/runtime/arm/closure.c create mode 100644 src/pkg/runtime/arm/traceback.s create mode 100644 src/pkg/runtime/array.c create mode 100644 src/pkg/runtime/cgo2c.c create mode 100644 src/pkg/runtime/chan.c create mode 100644 src/pkg/runtime/darwin/386/defs.h create mode 100755 src/pkg/runtime/darwin/386/rt0.s create mode 100644 src/pkg/runtime/darwin/386/signal.c create mode 100644 src/pkg/runtime/darwin/386/sys.s create mode 100644 src/pkg/runtime/darwin/amd64/defs.h create mode 100644 src/pkg/runtime/darwin/amd64/rt0.s create mode 100644 src/pkg/runtime/darwin/amd64/signal.c create mode 100644 src/pkg/runtime/darwin/amd64/sys.s create mode 100644 src/pkg/runtime/darwin/defs.c create mode 100644 src/pkg/runtime/darwin/os.h create mode 100644 src/pkg/runtime/darwin/signals.h create mode 100644 src/pkg/runtime/darwin/thread.c create mode 100644 src/pkg/runtime/extern.go create mode 100644 src/pkg/runtime/float.c create mode 100644 src/pkg/runtime/float_go.cgo create mode 100644 src/pkg/runtime/hashmap.c create mode 100644 src/pkg/runtime/hashmap.h create mode 100644 src/pkg/runtime/iface.c create mode 100755 src/pkg/runtime/linux/386/defs.h create mode 100755 src/pkg/runtime/linux/386/rt0.s create mode 100644 src/pkg/runtime/linux/386/signal.c create mode 100755 src/pkg/runtime/linux/386/sys.s create mode 100644 src/pkg/runtime/linux/amd64/defs.h create mode 100644 src/pkg/runtime/linux/amd64/rt0.s create mode 100644 src/pkg/runtime/linux/amd64/signal.c create mode 100644 src/pkg/runtime/linux/amd64/sys.s create mode 100644 src/pkg/runtime/linux/arm/defs.h create mode 100644 src/pkg/runtime/linux/arm/rt0.s create mode 100644 src/pkg/runtime/linux/arm/signal.c create mode 100644 src/pkg/runtime/linux/arm/sys.s create mode 100644 src/pkg/runtime/linux/defs.c create mode 100644 src/pkg/runtime/linux/defs1.c create mode 100644 src/pkg/runtime/linux/defs2.c create mode 100644 src/pkg/runtime/linux/defs_arm.c create mode 100644 src/pkg/runtime/linux/os.h create mode 100644 src/pkg/runtime/linux/signals.h create mode 100644 src/pkg/runtime/linux/thread.c create mode 100644 src/pkg/runtime/malloc.c create mode 100644 src/pkg/runtime/malloc.h create mode 100644 src/pkg/runtime/malloc_go.cgo create mode 100644 src/pkg/runtime/mcache.c create mode 100644 src/pkg/runtime/mcentral.c create mode 100644 src/pkg/runtime/mem.c create mode 100644 src/pkg/runtime/mfixalloc.c create mode 100644 src/pkg/runtime/mgc0.c create mode 100644 src/pkg/runtime/mheap.c create mode 100644 src/pkg/runtime/mheapmap32.c create mode 100644 src/pkg/runtime/mheapmap32.h create mode 100644 src/pkg/runtime/mheapmap64.c create mode 100644 src/pkg/runtime/mheapmap64.h create mode 100644 src/pkg/runtime/msize.c create mode 100644 src/pkg/runtime/print.c create mode 100644 src/pkg/runtime/proc.c create mode 100644 src/pkg/runtime/rune.c create mode 100644 src/pkg/runtime/runtime.c create mode 100644 src/pkg/runtime/runtime.h create mode 100644 src/pkg/runtime/sema.c create mode 100644 src/pkg/runtime/sema_go.cgo create mode 100644 src/pkg/runtime/string.c create mode 100644 src/pkg/runtime/symtab.c create mode 100644 src/pkg/sort/Makefile create mode 100644 src/pkg/sort/sort.go create mode 100644 src/pkg/sort/sort_test.go create mode 100644 src/pkg/strconv/Makefile create mode 100644 src/pkg/strconv/atof.go create mode 100644 src/pkg/strconv/atof_test.go create mode 100644 src/pkg/strconv/atoi.go create mode 100644 src/pkg/strconv/atoi_test.go create mode 100644 src/pkg/strconv/decimal.go create mode 100644 src/pkg/strconv/decimal_test.go create mode 100644 src/pkg/strconv/fp_test.go create mode 100644 src/pkg/strconv/ftoa.go create mode 100644 src/pkg/strconv/ftoa_test.go create mode 100644 src/pkg/strconv/itoa.go create mode 100644 src/pkg/strconv/itoa_test.go create mode 100644 src/pkg/strconv/quote.go create mode 100644 src/pkg/strconv/quote_test.go create mode 100644 src/pkg/strconv/testfp.txt create mode 100644 src/pkg/strings/Makefile create mode 100644 src/pkg/strings/strings.go create mode 100644 src/pkg/strings/strings_test.go create mode 100644 src/pkg/sync/Makefile create mode 100644 src/pkg/sync/asm_386.s create mode 100644 src/pkg/sync/asm_amd64.s create mode 100644 src/pkg/sync/mutex.go create mode 100644 src/pkg/sync/mutex_test.go create mode 100644 src/pkg/syscall/Makefile create mode 100755 src/pkg/syscall/PORT create mode 100644 src/pkg/syscall/asm_darwin_386.s create mode 100644 src/pkg/syscall/asm_darwin_amd64.s create mode 100644 src/pkg/syscall/asm_linux_386.s create mode 100644 src/pkg/syscall/asm_linux_amd64.s create mode 100644 src/pkg/syscall/errstr.go create mode 100644 src/pkg/syscall/exec.go create mode 100755 src/pkg/syscall/mkerrors create mode 100755 src/pkg/syscall/mksyscall create mode 100755 src/pkg/syscall/mksysnum_darwin create mode 100755 src/pkg/syscall/mksysnum_linux create mode 100644 src/pkg/syscall/syscall.go create mode 100644 src/pkg/syscall/syscall_darwin.go create mode 100644 src/pkg/syscall/syscall_darwin_386.go create mode 100644 src/pkg/syscall/syscall_darwin_amd64.go create mode 100644 src/pkg/syscall/syscall_linux.go create mode 100644 src/pkg/syscall/syscall_linux_386.go create mode 100644 src/pkg/syscall/syscall_linux_amd64.go create mode 100644 src/pkg/syscall/types_darwin.c create mode 100644 src/pkg/syscall/types_darwin_386.c create mode 100644 src/pkg/syscall/types_darwin_amd64.c create mode 100644 src/pkg/syscall/types_linux.c create mode 100644 src/pkg/syscall/types_linux_386.c create mode 100644 src/pkg/syscall/types_linux_amd64.c create mode 100644 src/pkg/syscall/zerrors_darwin_386.go create mode 100644 src/pkg/syscall/zerrors_darwin_amd64.go create mode 100644 src/pkg/syscall/zerrors_linux_386.go create mode 100644 src/pkg/syscall/zerrors_linux_amd64.go create mode 100644 src/pkg/syscall/zsyscall_darwin_386.go create mode 100644 src/pkg/syscall/zsyscall_darwin_amd64.go create mode 100644 src/pkg/syscall/zsyscall_linux_386.go create mode 100644 src/pkg/syscall/zsyscall_linux_amd64.go create mode 100644 src/pkg/syscall/zsysnum_darwin_386.go create mode 100644 src/pkg/syscall/zsysnum_darwin_amd64.go create mode 100644 src/pkg/syscall/zsysnum_linux_386.go create mode 100644 src/pkg/syscall/zsysnum_linux_amd64.go create mode 100644 src/pkg/syscall/ztypes_darwin_386.go create mode 100644 src/pkg/syscall/ztypes_darwin_amd64.go create mode 100644 src/pkg/syscall/ztypes_linux_386.go create mode 100644 src/pkg/syscall/ztypes_linux_amd64.go create mode 100644 src/pkg/tabwriter/Makefile create mode 100644 src/pkg/tabwriter/tabwriter.go create mode 100644 src/pkg/tabwriter/tabwriter_test.go create mode 100644 src/pkg/template/Makefile create mode 100644 src/pkg/template/format.go create mode 100644 src/pkg/template/template.go create mode 100644 src/pkg/template/template_test.go create mode 100644 src/pkg/testing/Makefile create mode 100644 src/pkg/testing/iotest/Makefile create mode 100644 src/pkg/testing/iotest/logger.go create mode 100644 src/pkg/testing/iotest/reader.go create mode 100644 src/pkg/testing/testing.go create mode 100644 src/pkg/time/Makefile create mode 100644 src/pkg/time/sleep.go create mode 100644 src/pkg/time/tick.go create mode 100644 src/pkg/time/tick_test.go create mode 100644 src/pkg/time/time.go create mode 100644 src/pkg/time/time_test.go create mode 100644 src/pkg/time/zoneinfo.go create mode 100644 src/pkg/unicode/Makefile create mode 100644 src/pkg/unicode/decimaldigit.go create mode 100644 src/pkg/unicode/decimaldigit_test.go create mode 100644 src/pkg/unicode/letter.go create mode 100644 src/pkg/unicode/letter_test.go create mode 100644 src/pkg/unsafe/unsafe.go create mode 100644 src/pkg/utf8/Makefile create mode 100644 src/pkg/utf8/utf8.go create mode 100644 src/pkg/utf8/utf8_test.go create mode 100644 src/pkg/xml/xml.go diff --git a/src/clean.bash b/src/clean.bash index 15a46a76a..e67fe1403 100755 --- a/src/clean.bash +++ b/src/clean.bash @@ -5,7 +5,7 @@ rm -rf $GOROOT/pkg/[0-9a-zA-Z_]* rm -f $GOROOT/lib/*.[6a] -for i in lib9 libbio libmach_amd64 libregexp cmd lib +for i in lib9 libbio libmach_amd64 libregexp cmd pkg do cd $i case $i in diff --git a/src/cmd/gobuild/gobuild.go b/src/cmd/gobuild/gobuild.go index c84c7e927..d7e9de8ff 100644 --- a/src/cmd/gobuild/gobuild.go +++ b/src/cmd/gobuild/gobuild.go @@ -103,14 +103,14 @@ func (a FileArray) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -// If current directory is under $GOROOT/src/lib, return the +// If current directory is under $GOROOT/src/pkg, return the // path relative to there. Otherwise return "". func PkgDir() string { goroot, err := os.Getenv("GOROOT"); if err != nil || goroot == "" { return "" } - srcroot := path.Clean(goroot + "/src/lib/"); + srcroot := path.Clean(goroot + "/src/pkg/"); pwd, err1 := os.Getenv("PWD"); // TODO(rsc): real pwd if err1 != nil || pwd == "" { return "" diff --git a/src/lib/Make.deps b/src/lib/Make.deps deleted file mode 100644 index dd83e8b1c..000000000 --- a/src/lib/Make.deps +++ /dev/null @@ -1,52 +0,0 @@ -archive/tar.install: bufio.install bytes.install io.install os.install strconv.install -bignum.install: fmt.install -bufio.install: io.install os.install utf8.install -bytes.install: utf8.install -compress/flate.install: bufio.install io.install os.install strconv.install -compress/gzip.install: bufio.install compress/flate.install hash.install hash/crc32.install io.install os.install -container/list.install: -container/vector.install: -crypto/aes.install: os.install -crypto/block.install: fmt.install io.install os.install -crypto/hmac.install: crypto/md5.install crypto/sha1.install hash.install os.install -crypto/md5.install: hash.install os.install -crypto/sha1.install: hash.install os.install -datafmt.install: container/vector.install fmt.install go/scanner.install go/token.install io.install os.install reflect.install runtime.install strconv.install strings.install -exec.install: os.install strings.install -exvar.install: fmt.install http.install io.install log.install strconv.install sync.install -flag.install: fmt.install os.install strconv.install -fmt.install: io.install os.install reflect.install strconv.install utf8.install -go/ast.install: datafmt.install go/token.install io.install os.install unicode.install utf8.install -go/doc.install: container/vector.install fmt.install go/ast.install go/token.install io.install once.install regexp.install sort.install strings.install template.install -go/parser.install: container/vector.install fmt.install go/ast.install go/scanner.install go/token.install io.install os.install -go/scanner.install: go/token.install strconv.install unicode.install utf8.install -go/token.install: strconv.install -hash.install: io.install -hash/adler32.install: hash.install os.install -hash/crc32.install: hash.install os.install -http.install: bufio.install fmt.install io.install log.install net.install os.install path.install strconv.install strings.install utf8.install -io.install: bytes.install os.install sync.install -json.install: container/vector.install fmt.install io.install math.install reflect.install strconv.install strings.install utf8.install -log.install: fmt.install io.install os.install runtime.install time.install -malloc.install: -math.install: -net.install: fmt.install io.install once.install os.install reflect.install strconv.install strings.install sync.install syscall.install -once.install: sync.install -os.install: once.install syscall.install -path.install: io.install -rand.install: -reflect.install: strconv.install sync.install utf8.install -regexp.install: container/vector.install os.install runtime.install utf8.install -runtime.install: -sort.install: -strconv.install: bytes.install math.install os.install utf8.install -strings.install: utf8.install -sync.install: -syscall.install: sync.install -tabwriter.install: container/vector.install io.install os.install utf8.install -template.install: container/vector.install fmt.install io.install os.install reflect.install runtime.install strings.install -testing.install: flag.install fmt.install os.install regexp.install runtime.install -testing/iotest.install: io.install log.install os.install -time.install: io.install once.install os.install syscall.install -unicode.install: -utf8.install: diff --git a/src/lib/Makefile b/src/lib/Makefile deleted file mode 100644 index 036a82e38..000000000 --- a/src/lib/Makefile +++ /dev/null @@ -1,139 +0,0 @@ -# Copyright 2009 The Go 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. - -all: install - -DIRS=\ - archive/tar\ - bignum\ - bufio\ - bytes\ - compress/flate\ - compress/gzip\ - container/list\ - container/vector\ - crypto/aes\ - crypto/block\ - crypto/hmac\ - crypto/md5\ - crypto/sha1\ - datafmt\ - exec\ - exvar\ - flag\ - fmt\ - go/ast\ - go/doc\ - go/parser\ - go/scanner\ - go/token\ - hash\ - hash/adler32\ - hash/crc32\ - http\ - io\ - json\ - log\ - malloc\ - math\ - net\ - once\ - os\ - path\ - rand\ - reflect\ - regexp\ - runtime\ - sort\ - strconv\ - strings\ - sync\ - syscall\ - tabwriter\ - template\ - testing\ - testing/iotest\ - time\ - unicode\ - utf8\ - -TEST=\ - archive/tar\ - bignum\ - bufio\ - compress/flate\ - compress/gzip\ - container/list\ - container/vector\ - crypto/aes\ - crypto/block\ - crypto/md5\ - crypto/sha1\ - datafmt\ - exec\ - exvar\ - flag\ - fmt\ - go/parser\ - go/scanner\ - hash/adler32\ - hash/crc32\ - http\ - io\ - json\ - log\ - math\ - net\ - once\ - os\ - path\ - reflect\ - regexp\ - sort\ - strconv\ - strings\ - sync\ - tabwriter\ - template\ - time\ - unicode\ - utf8\ - -clean.dirs: $(addsuffix .clean, $(DIRS)) -install.dirs: $(addsuffix .install, $(DIRS)) -nuke.dirs: $(addsuffix .nuke, $(DIRS)) -test.dirs: $(addsuffix .test, $(TEST)) - -%.clean: - +cd $* && make clean - -%.install: - +cd $* && make install - -%.nuke: - +cd $* && make nuke - -%.test: - +cd $* && make test - -clean: clean.dirs - -install: install.dirs - -test: test.dirs - -nuke: nuke.dirs - rm -rf $(GOROOT)/pkg/* - -deps: - ./deps.bash - -include Make.deps diff --git a/src/lib/archive/tar/Makefile b/src/lib/archive/tar/Makefile deleted file mode 100644 index 579ed4c35..000000000 --- a/src/lib/archive/tar/Makefile +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m >Makefile - -D=/archive/ - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - untar.$O\ - - -phases: a1 -_obj$D/tar.a: phases - -a1: $(O1) - $(AR) grc _obj$D/tar.a untar.$O - rm -f $(O1) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/tar.a - -$(O1): newpkg -$(O2): a1 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/tar.a - -packages: _obj$D/tar.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/tar.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/tar.a diff --git a/src/lib/archive/tar/testdata/small.txt b/src/lib/archive/tar/testdata/small.txt deleted file mode 100644 index b249bfc51..000000000 --- a/src/lib/archive/tar/testdata/small.txt +++ /dev/null @@ -1 +0,0 @@ -Kilts \ No newline at end of file diff --git a/src/lib/archive/tar/testdata/small2.txt b/src/lib/archive/tar/testdata/small2.txt deleted file mode 100644 index 394ee3ecd..000000000 --- a/src/lib/archive/tar/testdata/small2.txt +++ /dev/null @@ -1 +0,0 @@ -Google.com diff --git a/src/lib/archive/tar/testdata/test.tar b/src/lib/archive/tar/testdata/test.tar deleted file mode 100644 index fc899dc8d..000000000 Binary files a/src/lib/archive/tar/testdata/test.tar and /dev/null differ diff --git a/src/lib/archive/tar/untar.go b/src/lib/archive/tar/untar.go deleted file mode 100644 index 300c0f932..000000000 --- a/src/lib/archive/tar/untar.go +++ /dev/null @@ -1,242 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// The tar package implements access to tar archives. -// It aims to cover most of the variations, including those produced -// by GNU and BSD tars (not yet started). -// -// 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 - -// TODO(dsymonds): -// - Make it seekable. -// - Extensions. - -import ( - "bufio"; - "bytes"; - "io"; - "os"; - "strconv"; -) - -var ( - HeaderError os.Error = os.ErrorString("invalid tar header"); -) - -// A tar archive consists of a sequence of files. -// A Reader provides sequential access to the contents of a tar archive. -// 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 := NewTarReader(r); -// for { -// hdr, err := tr.Next(); -// if err != nil { -// // handle error -// } -// if hdr == nil { -// // end of tar archive -// break -// } -// io.Copy(tr, somewhere); -// } -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 -} - -// A Header represents a single header in a tar archive. -// Only some fields may be populated. -type Header struct { - Name string; - Mode int64; - Uid int64; - Gid int64; - Size int64; - Mtime int64; - Typeflag byte; - Linkname string; - Uname string; - Gname string; - Devmajor int64; - Devminor int64; -} - -func (tr *Reader) skipUnread() -func (tr *Reader) readHeader() *Header - -// NewReader creates a new Reader reading the given io.Reader. -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 -} - -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'; -) - -var zeroBlock = make([]byte, blockSize); - -// 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) octalNumber(b []byte) int64 { - x, err := strconv.Btoui64(cString(b), 8); - if err != nil { - tr.err = err; - } - return int64(x) -} - -type ignoreWriter struct {} -func (ignoreWriter) Write(b []byte) (n int, err os.Error) { - return len(b), nil -} - -type seeker interface { - Seek(offset int64, whence int) (ret int64, err os.Error); -} - -// 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 - - var n int64; - if sr, ok := tr.r.(seeker); ok { - n, tr.err = sr.Seek(nr, 1); - } else { - n, tr.err = io.Copyn(tr.r, ignoreWriter{}, nr); - } - tr.nb, tr.pad = 0, 0; -} - -func (tr *Reader) verifyChecksum(header []byte) bool { - given := tr.octalNumber(header[148:156]); - if tr.err != nil { - return false - } - - var computed int64; - for i := 0; i < len(header); i++ { - if i == 148 { - // The chksum field is special: it should be treated as space bytes. - computed += ' ' * 8; - i += 7; - continue - } - computed += int64(header[i]); - } - - return given == computed -} - -type slicer []byte -func (s *slicer) next(n int) (b []byte) { - b, *s = s[0:n], s[n:len(s)]; - return -} - -func (tr *Reader) readHeader() *Header { - header := make([]byte, blockSize); - var n int; - if n, tr.err = io.FullRead(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 n, tr.err = io.FullRead(tr.r, header); tr.err != nil { - return nil - } - if !bytes.Equal(header, zeroBlock[0:blockSize]) { - tr.err = HeaderError; - } - return nil - } - - if !tr.verifyChecksum(header) { - tr.err = HeaderError; - return nil - } - - // Unpack - hdr := new(Header); - s := slicer(header); - - // TODO(dsymonds): The format of the header depends on the value of magic (hdr[257:262]), - // so use that value to do the correct parsing below. - - hdr.Name = cString(s.next(100)); - hdr.Mode = tr.octalNumber(s.next(8)); - hdr.Uid = tr.octalNumber(s.next(8)); - hdr.Gid = tr.octalNumber(s.next(8)); - hdr.Size = tr.octalNumber(s.next(12)); - hdr.Mtime = tr.octalNumber(s.next(12)); - s.next(8); // chksum - hdr.Typeflag = s.next(1)[0]; - hdr.Linkname = cString(s.next(100)); - s.next(8); // magic, version - - 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, nil when it reaches the end of that entry, -// until Next is called to advance to the next entry. -func (tr *Reader) Read(b []uint8) (n int, err os.Error) { - if int64(len(b)) > tr.nb { - b = b[0:tr.nb]; - } - n, err = tr.r.Read(b); - tr.nb -= int64(n); - tr.err = err; - return -} diff --git a/src/lib/archive/tar/untar_test.go b/src/lib/archive/tar/untar_test.go deleted file mode 100644 index a9c92dbf0..000000000 --- a/src/lib/archive/tar/untar_test.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package tar - -import ( - "archive/tar"; - "bytes"; - "fmt"; - "io"; - "os"; - "testing"; -) - -func TestUntar(t *testing.T) { - f, err := os.Open("testdata/test.tar", os.O_RDONLY, 0444); - if err != nil { - t.Fatalf("Unexpected error: %v", err); - } - defer f.Close(); - - tr := NewReader(f); - - // First file - hdr, err := tr.Next(); - if err != nil || hdr == nil { - t.Fatalf("Didn't get first file: %v", err); - } - if hdr.Name != "small.txt" { - t.Errorf(`hdr.Name = %q, want "small.txt"`, hdr.Name); - } - if hdr.Mode != 0640 { - t.Errorf("hdr.Mode = %v, want 0640", hdr.Mode); - } - if hdr.Size != 5 { - t.Errorf("hdr.Size = %v, want 5", hdr.Size); - } - - // Read the first four bytes; Next() should skip the last one. - buf := make([]byte, 4); - if n, err := io.FullRead(tr, buf); err != nil { - t.Fatalf("Unexpected error: %v", err); - } - if expected := io.StringBytes("Kilt"); !bytes.Equal(buf, expected) { - t.Errorf("Contents = %v, want %v", buf, expected); - } - - // Second file - hdr, err = tr.Next(); - if err != nil { - t.Fatalf("Didn't get second file: %v", err); - } - if hdr.Name != "small2.txt" { - t.Errorf(`hdr.Name = %q, want "small2.txt"`, hdr.Name); - } - if hdr.Mode != 0640 { - t.Errorf("hdr.Mode = %v, want 0640", hdr.Mode); - } - if hdr.Size != 11 { - t.Errorf("hdr.Size = %v, want 11", hdr.Size); - } - - - hdr, err = tr.Next(); - if hdr != nil || err != nil { - t.Fatalf("Unexpected third file or error: %v", err); - } -} diff --git a/src/lib/bignum/Makefile b/src/lib/bignum/Makefile deleted file mode 100644 index 098b90975..000000000 --- a/src/lib/bignum/Makefile +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m >Makefile - -D= - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - bignum.$O\ - - -phases: a1 -_obj$D/bignum.a: phases - -a1: $(O1) - $(AR) grc _obj$D/bignum.a bignum.$O - rm -f $(O1) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/bignum.a - -$(O1): newpkg -$(O2): a1 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/bignum.a - -packages: _obj$D/bignum.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/bignum.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/bignum.a diff --git a/src/lib/bignum/bignum.go b/src/lib/bignum/bignum.go deleted file mode 100755 index b9ea66587..000000000 --- a/src/lib/bignum/bignum.go +++ /dev/null @@ -1,1464 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// A package for arbitrary precision arithmethic. -// It implements the following numeric types: -// -// - Natural unsigned integers -// - Integer signed integers -// - Rational rational numbers -// -package bignum - -import "fmt" - - -// ---------------------------------------------------------------------------- -// Internal representation -// -// A natural number of the form -// -// x = x[n-1]*B^(n-1) + x[n-2]*B^(n-2) + ... + x[1]*B + x[0] -// -// with 0 <= x[i] < B and 0 <= i < n is stored in a slice of length n, -// with the digits x[i] as the slice elements. -// -// A natural number is normalized if the slice contains no leading 0 digits. -// During arithmetic operations, denormalized values may occur but are -// always normalized before returning the final result. The normalized -// representation of 0 is the empty slice (length = 0). -// -// The operations for all other numeric types are implemented on top of -// the operations for natural numbers. -// -// The base B is chosen as large as possible on a given platform but there -// are a few constraints besides the size of the largest unsigned integer -// type available: -// -// 1) To improve conversion speed between strings and numbers, the base B -// is chosen such that division and multiplication by 10 (for decimal -// string representation) can be done without using extended-precision -// arithmetic. This makes addition, subtraction, and conversion routines -// twice as fast. It requires a ``buffer'' of 4 bits per operand digit. -// That is, the size of B must be 4 bits smaller then the size of the -// type (digit) in which these operations are performed. Having this -// buffer also allows for trivial (single-bit) carry computation in -// addition and subtraction (optimization suggested by Ken Thompson). -// -// 2) Long division requires extended-precision (2-digit) division per digit. -// Instead of sacrificing the largest base type for all other operations, -// for division the operands are unpacked into ``half-digits'', and the -// results are packed again. For faster unpacking/packing, the base size -// in bits must be even. - -type ( - digit uint64; - digit2 uint32; // half-digits for division -) - - -const ( - _LogW = 64; - _LogH = 4; // bits for a hex digit (= small number) - _LogB = _LogW - _LogH; // largest bit-width available - - // half-digits - _W2 = _LogB / 2; // width - _B2 = 1 << _W2; // base - _M2 = _B2 - 1; // mask - - // full digits - _W = _W2 * 2; // width - _B = 1 << _W; // base - _M = _B - 1; // mask -) - - -// ---------------------------------------------------------------------------- -// Support functions - -func assert(p bool) { - if !p { - panic("assert failed"); - } -} - - -func isSmall(x digit) bool { - return x < 1<<_LogH; -} - - -// For debugging. -func dump(x []digit) { - print("[", len(x), "]"); - for i := len(x) - 1; i >= 0; i-- { - print(" ", x[i]); - } - println(); -} - - -// ---------------------------------------------------------------------------- -// Natural numbers - -// Natural represents an unsigned integer value of arbitrary precision. -// -type Natural []digit; - -var ( - natZero Natural = Natural{}; - natOne Natural = Natural{1}; - natTwo Natural = Natural{2}; - natTen Natural = Natural{10}; -) - - -// Nat creates a small natural number with value x. -// Implementation restriction: At the moment, only values -// x < (1<<60) are supported. -// -func Nat(x uint) Natural { - switch x { - case 0: return natZero; - case 1: return natOne; - case 2: return natTwo; - case 10: return natTen; - } - assert(digit(x) < _B); - return Natural{digit(x)}; -} - - -// IsEven returns true iff x is divisible by 2. -// -func (x Natural) IsEven() bool { - return len(x) == 0 || x[0]&1 == 0; -} - - -// IsOdd returns true iff x is not divisible by 2. -// -func (x Natural) IsOdd() bool { - return len(x) > 0 && x[0]&1 != 0; -} - - -// IsZero returns true iff x == 0. -// -func (x Natural) IsZero() bool { - return len(x) == 0; -} - - -// Operations -// -// Naming conventions -// -// c carry -// x, y operands -// z result -// n, m len(x), len(y) - -func normalize(x Natural) Natural { - n := len(x); - for n > 0 && x[n - 1] == 0 { n-- } - if n < len(x) { - x = x[0 : n]; // trim leading 0's - } - return x; -} - - -// Add returns the sum x + y. -// -func (x Natural) Add(y Natural) Natural { - n := len(x); - m := len(y); - if n < m { - return y.Add(x); - } - - c := digit(0); - z := make(Natural, n + 1); - i := 0; - for i < m { - t := c + x[i] + y[i]; - c, z[i] = t>>_W, t&_M; - i++; - } - for i < n { - t := c + x[i]; - c, z[i] = t>>_W, t&_M; - i++; - } - if c != 0 { - z[i] = c; - i++; - } - - return z[0 : i]; -} - - -// Sub returns the difference x - y for x >= y. -// If x < y, an underflow run-time error occurs (use Cmp to test if x >= y). -// -func (x Natural) Sub(y Natural) Natural { - n := len(x); - m := len(y); - if n < m { - panic("underflow") - } - - c := digit(0); - z := make(Natural, n); - i := 0; - for i < m { - t := c + x[i] - y[i]; - c, z[i] = digit(int64(t)>>_W), t&_M; // requires arithmetic shift! - i++; - } - for i < n { - t := c + x[i]; - c, z[i] = digit(int64(t)>>_W), t&_M; // requires arithmetic shift! - i++; - } - for i > 0 && z[i - 1] == 0 { // normalize - i--; - } - - return z[0 : i]; -} - - -// Returns c = x*y div B, z = x*y mod B. -// -func mul11(x, y digit) (digit, digit) { - // Split x and y into 2 sub-digits each, - // multiply the digits separately while avoiding overflow, - // and return the product as two separate digits. - - // This code also works for non-even bit widths W - // which is why there are separate constants below - // for half-digits. - const W2 = (_W + 1)/2; - const DW = W2*2 - _W; // 0 or 1 - const B2 = 1<>W2, x&M2; - y1, y0 := y>>W2, y&M2; - - // x*y = t2*B2^2 + t1*B2 + t0 - t0 := x0*y0; - t1 := x1*y0 + x0*y1; - t2 := x1*y1; - - // compute the result digits but avoid overflow - // z = z1*B + z0 = x*y - z0 := (t1<>W2)>>(_W-W2); - - return z1, z0; -} - - -// Mul returns the product x * y. -// -func (x Natural) Mul(y Natural) Natural { - n := len(x); - m := len(y); - - z := make(Natural, n + m); - for j := 0; j < m; j++ { - d := y[j]; - if d != 0 { - c := digit(0); - for i := 0; i < n; i++ { - // z[i+j] += c + x[i]*d; - z1, z0 := mul11(x[i], d); - t := c + z[i+j] + z0; - c, z[i+j] = t>>_W, t&_M; - c += z1; - } - z[n+j] = c; - } - } - - return normalize(z); -} - - -// DivMod needs multi-precision division, which is not available if digit -// is already using the largest uint size. Instead, unpack each operand -// into operands with twice as many digits of half the size (digit2), do -// DivMod, and then pack the results again. - -func unpack(x Natural) []digit2 { - n := len(x); - z := make([]digit2, n*2 + 1); // add space for extra digit (used by DivMod) - for i := 0; i < n; i++ { - t := x[i]; - z[i*2] = digit2(t & _M2); - z[i*2 + 1] = digit2(t >> _W2 & _M2); - } - - // normalize result - k := 2*n; - for k > 0 && z[k - 1] == 0 { k-- } - return z[0 : k]; // trim leading 0's -} - - -func pack(x []digit2) Natural { - n := (len(x) + 1) / 2; - z := make(Natural, n); - if len(x) & 1 == 1 { - // handle odd len(x) - n--; - z[n] = digit(x[n*2]); - } - for i := 0; i < n; i++ { - z[i] = digit(x[i*2 + 1]) << _W2 | digit(x[i*2]); - } - return normalize(z); -} - - -func mul1(z, x []digit2, y digit2) digit2 { - n := len(x); - c := digit(0); - f := digit(y); - for i := 0; i < n; i++ { - t := c + digit(x[i])*f; - c, z[i] = t>>_W2, digit2(t&_M2); - } - return digit2(c); -} - - -func div1(z, x []digit2, y digit2) digit2 { - n := len(x); - c := digit(0); - d := digit(y); - for i := n-1; i >= 0; i-- { - t := c*_B2 + digit(x[i]); - c, z[i] = t%d, digit2(t/d); - } - return digit2(c); -} - - -// divmod returns q and r with x = y*q + r and 0 <= r < y. -// x and y are destroyed in the process. -// -// The algorithm used here is based on 1). 2) describes the same algorithm -// in C. A discussion and summary of the relevant theorems can be found in -// 3). 3) also describes an easier way to obtain the trial digit - however -// it relies on tripple-precision arithmetic which is why Knuth's method is -// used here. -// -// 1) D. Knuth, The Art of Computer Programming. Volume 2. Seminumerical -// Algorithms. Addison-Wesley, Reading, 1969. -// (Algorithm D, Sec. 4.3.1) -// -// 2) Henry S. Warren, Jr., Hacker's Delight. Addison-Wesley, 2003. -// (9-2 Multiword Division, p.140ff) -// -// 3) P. Brinch Hansen, ``Multiple-length division revisited: A tour of the -// minefield''. Software - Practice and Experience 24, (June 1994), -// 579-601. John Wiley & Sons, Ltd. - -func divmod(x, y []digit2) ([]digit2, []digit2) { - n := len(x); - m := len(y); - if m == 0 { - panic("division by zero"); - } - assert(n+1 <= cap(x)); // space for one extra digit - x = x[0 : n + 1]; - assert(x[n] == 0); - - if m == 1 { - // division by single digit - // result is shifted left by 1 in place! - x[0] = div1(x[1 : n+1], x[0 : n], y[0]); - - } else if m > n { - // y > x => quotient = 0, remainder = x - // TODO in this case we shouldn't even unpack x and y - m = n; - - } else { - // general case - assert(2 <= m && m <= n); - - // normalize x and y - // TODO Instead of multiplying, it would be sufficient to - // shift y such that the normalization condition is - // satisfied (as done in Hacker's Delight). - f := _B2 / (digit(y[m-1]) + 1); - if f != 1 { - mul1(x, x, digit2(f)); - mul1(y, y, digit2(f)); - } - assert(_B2/2 <= y[m-1] && y[m-1] < _B2); // incorrect scaling - - y1, y2 := digit(y[m-1]), digit(y[m-2]); - d2 := digit(y1)<<_W2 + digit(y2); - for i := n-m; i >= 0; i-- { - k := i+m; - - // compute trial digit (Knuth) - var q digit; - { x0, x1, x2 := digit(x[k]), digit(x[k-1]), digit(x[k-2]); - if x0 != y1 { - q = (x0<<_W2 + x1)/y1; - } else { - q = _B2 - 1; - } - for y2*q > (x0<<_W2 + x1 - y1*q)<<_W2 + x2 { - q-- - } - } - - // subtract y*q - c := digit(0); - for j := 0; j < m; j++ { - t := c + digit(x[i+j]) - digit(y[j])*q; - c, x[i+j] = digit(int64(t) >> _W2), digit2(t & _M2); // requires arithmetic shift! - } - - // correct if trial digit was too large - if c + digit(x[k]) != 0 { - // add y - c := digit(0); - for j := 0; j < m; j++ { - t := c + digit(x[i+j]) + digit(y[j]); - c, x[i+j] = t >> _W2, digit2(t & _M2) - } - assert(c + digit(x[k]) == 0); - // correct trial digit - q--; - } - - x[k] = digit2(q); - } - - // undo normalization for remainder - if f != 1 { - c := div1(x[0 : m], x[0 : m], digit2(f)); - assert(c == 0); - } - } - - return x[m : n+1], x[0 : m]; -} - - -// Div returns the quotient q = x / y for y > 0, -// with x = y*q + r and 0 <= r < y. -// If y == 0, a division-by-zero run-time error occurs. -// -func (x Natural) Div(y Natural) Natural { - q, r := divmod(unpack(x), unpack(y)); - return pack(q); -} - - -// Mod returns the modulus r of the division x / y for y > 0, -// with x = y*q + r and 0 <= r < y. -// If y == 0, a division-by-zero run-time error occurs. -// -func (x Natural) Mod(y Natural) Natural { - q, r := divmod(unpack(x), unpack(y)); - return pack(r); -} - - -// DivMod returns the pair (x.Div(y), x.Mod(y)) for y > 0. -// If y == 0, a division-by-zero run-time error occurs. -// -func (x Natural) DivMod(y Natural) (Natural, Natural) { - q, r := divmod(unpack(x), unpack(y)); - return pack(q), pack(r); -} - - -func shl(z, x []digit, s uint) digit { - assert(s <= _W); - n := len(x); - c := digit(0); - for i := 0; i < n; i++ { - c, z[i] = x[i] >> (_W-s), x[i] << s & _M | c; - } - return c; -} - - -// Shl implements ``shift left'' x << s. It returns x * 2^s. -// -func (x Natural) Shl(s uint) Natural { - n := uint(len(x)); - m := n + s/_W; - z := make(Natural, m+1); - - z[m] = shl(z[m-n : m], x, s%_W); - - return normalize(z); -} - - -func shr(z, x []digit, s uint) digit { - assert(s <= _W); - n := len(x); - c := digit(0); - for i := n - 1; i >= 0; i-- { - c, z[i] = x[i] << (_W-s) & _M, x[i] >> s | c; - } - return c; -} - - -// Shr implements ``shift right'' x >> s. It returns x / 2^s. -// -func (x Natural) Shr(s uint) Natural { - n := uint(len(x)); - m := n - s/_W; - if m > n { // check for underflow - m = 0; - } - z := make(Natural, m); - - shr(z, x[n-m : n], s%_W); - - return normalize(z); -} - - -// And returns the ``bitwise and'' x & y for the binary representation of x and y. -// -func (x Natural) And(y Natural) Natural { - n := len(x); - m := len(y); - if n < m { - return y.And(x); - } - - z := make(Natural, m); - for i := 0; i < m; i++ { - z[i] = x[i] & y[i]; - } - // upper bits are 0 - - return normalize(z); -} - - -func copy(z, x []digit) { - for i, e := range x { - z[i] = e - } -} - - -// Or returns the ``bitwise or'' x | y for the binary representation of x and y. -// -func (x Natural) Or(y Natural) Natural { - n := len(x); - m := len(y); - if n < m { - return y.Or(x); - } - - z := make(Natural, n); - for i := 0; i < m; i++ { - z[i] = x[i] | y[i]; - } - copy(z[m : n], x[m : n]); - - return z; -} - - -// Xor returns the ``bitwise exclusive or'' x ^ y for the binary representation of x and y. -// -func (x Natural) Xor(y Natural) Natural { - n := len(x); - m := len(y); - if n < m { - return y.Xor(x); - } - - z := make(Natural, n); - for i := 0; i < m; i++ { - z[i] = x[i] ^ y[i]; - } - copy(z[m : n], x[m : n]); - - return normalize(z); -} - - -// Cmp compares x and y. The result is an int value -// -// < 0 if x < y -// == 0 if x == y -// > 0 if x > y -// -func (x Natural) Cmp(y Natural) int { - n := len(x); - m := len(y); - - if n != m || n == 0 { - return n - m; - } - - i := n - 1; - for i > 0 && x[i] == y[i] { i--; } - - d := 0; - switch { - case x[i] < y[i]: d = -1; - case x[i] > y[i]: d = 1; - } - - return d; -} - - -func log2(x digit) uint { - assert(x > 0); - n := uint(0); - for x > 0 { - x >>= 1; - n++; - } - return n - 1; -} - - -// Log2 computes the binary logarithm of x for x > 0. -// The result is the integer n for which 2^n <= x < 2^(n+1). -// If x == 0 a run-time error occurs. -// -func (x Natural) Log2() uint { - n := len(x); - if n > 0 { - return (uint(n) - 1)*_W + log2(x[n - 1]); - } - panic("Log2(0)"); -} - - -// Computes x = x div d in place (modifies x) for small d's. -// Returns updated x and x mod d. -// -func divmod1(x Natural, d digit) (Natural, digit) { - assert(0 < d && isSmall(d - 1)); - - c := digit(0); - for i := len(x) - 1; i >= 0; i-- { - t := c<<_W + x[i]; - c, x[i] = t%d, t/d; - } - - return normalize(x), c; -} - - -// ToString converts x to a string for a given base, with 2 <= base <= 16. -// -func (x Natural) ToString(base uint) string { - if len(x) == 0 { - return "0"; - } - - // allocate buffer for conversion - assert(2 <= base && base <= 16); - n := (x.Log2() + 1) / log2(digit(base)) + 1; // +1: round up - s := make([]byte, n); - - // don't destroy x - t := make(Natural, len(x)); - copy(t, x); - - // convert - i := n; - for !t.IsZero() { - i--; - var d digit; - t, d = divmod1(t, digit(base)); - s[i] = "0123456789abcdef"[d]; - }; - - return string(s[i : n]); -} - - -// String converts x to its decimal string representation. -// x.String() is the same as x.ToString(10). -// -func (x Natural) String() string { - return x.ToString(10); -} - - -func fmtbase(c int) uint { - switch c { - case 'b': return 2; - case 'o': return 8; - case 'x': return 16; - } - return 10; -} - - -// Format is a support routine for fmt.Formatter. It accepts -// the formats 'b' (binary), 'o' (octal), and 'x' (hexadecimal). -// -func (x Natural) Format(h fmt.Formatter, c int) { - fmt.Fprintf(h, "%s", x.ToString(fmtbase(c))); -} - - -func hexvalue(ch byte) uint { - d := uint(1 << _LogH); - switch { - case '0' <= ch && ch <= '9': d = uint(ch - '0'); - case 'a' <= ch && ch <= 'f': d = uint(ch - 'a') + 10; - case 'A' <= ch && ch <= 'F': d = uint(ch - 'A') + 10; - } - return d; -} - - -// Computes x = x*d + c for small d's. -// -func muladd1(x Natural, d, c digit) Natural { - assert(isSmall(d-1) && isSmall(c)); - n := len(x); - z := make(Natural, n + 1); - - for i := 0; i < n; i++ { - t := c + x[i]*d; - c, z[i] = t>>_W, t&_M; - } - z[n] = c; - - return normalize(z); -} - - -// NatFromString returns the natural number corresponding to the -// longest possible prefix of s representing a natural number in a -// given conversion base, the actual conversion base used, and the -// prefix length. -// -// If the base argument is 0, the string prefix determines the actual -// conversion base. A prefix of ``0x'' or ``0X'' selects base 16; the -// ``0'' prefix selects base 8. Otherwise the selected base is 10. -// -func NatFromString(s string, base uint) (Natural, uint, int) { - // determine base if necessary - i, n := 0, len(s); - if base == 0 { - base = 10; - if n > 0 && s[0] == '0' { - if n > 1 && (s[1] == 'x' || s[1] == 'X') { - base, i = 16, 2; - } else { - base, i = 8, 1; - } - } - } - - // convert string - assert(2 <= base && base <= 16); - x := Nat(0); - for ; i < n; i++ { - d := hexvalue(s[i]); - if d < base { - x = muladd1(x, digit(base), digit(d)); - } else { - break; - } - } - - return x, base, i; -} - - -// Natural number functions - -func pop1(x digit) uint { - n := uint(0); - for x != 0 { - x &= x-1; - n++; - } - return n; -} - - -// Pop computes the ``population count'' of (the number of 1 bits in) x. -// -func (x Natural) Pop() uint { - n := uint(0); - for i := len(x) - 1; i >= 0; i-- { - n += pop1(x[i]); - } - return n; -} - - -// Pow computes x to the power of n. -// -func (xp Natural) Pow(n uint) Natural { - z := Nat(1); - x := xp; - for n > 0 { - // z * x^n == x^n0 - if n&1 == 1 { - z = z.Mul(x); - } - x, n = x.Mul(x), n/2; - } - return z; -} - - -// MulRange computes the product of all the unsigned integers -// in the range [a, b] inclusively. -// -func MulRange(a, b uint) Natural { - switch { - case a > b: return Nat(1); - case a == b: return Nat(a); - case a + 1 == b: return Nat(a).Mul(Nat(b)); - } - m := (a + b)>>1; - assert(a <= m && m < b); - return MulRange(a, m).Mul(MulRange(m + 1, b)); -} - - -// Fact computes the factorial of n (Fact(n) == MulRange(2, n)). -// -func Fact(n uint) Natural { - // Using MulRange() instead of the basic for-loop - // lead to faster factorial computation. - return MulRange(2, n); -} - - -// Binomial computes the binomial coefficient of (n, k). -// -func Binomial(n, k uint) Natural { - return MulRange(n-k+1, n).Div(MulRange(1, k)); -} - - -// Gcd computes the gcd of x and y. -// -func (x Natural) Gcd(y Natural) Natural { - // Euclidean algorithm. - a, b := x, y; - for !b.IsZero() { - a, b = b, a.Mod(b); - } - return a; -} - - -// ---------------------------------------------------------------------------- -// Integer numbers -// -// Integers are normalized if the mantissa is normalized and the sign is -// false for mant == 0. Use MakeInt to create normalized Integers. - -// Integer represents a signed integer value of arbitrary precision. -// -type Integer struct { - sign bool; - mant Natural; -} - - -// MakeInt makes an integer given a sign and a mantissa. -// The number is positive (>= 0) if sign is false or the -// mantissa is zero; it is negative otherwise. -// -func MakeInt(sign bool, mant Natural) *Integer { - if mant.IsZero() { - sign = false; // normalize - } - return &Integer{sign, mant}; -} - - -// Int creates a small integer with value x. -// Implementation restriction: At the moment, only values -// with an absolute value |x| < (1<<60) are supported. -// -func Int(x int) *Integer { - sign := false; - var ux uint; - if x < 0 { - sign = true; - if -x == x { - // smallest negative integer - t := ^0; - ux = ^(uint(t) >> 1); - } else { - ux = uint(-x); - } - } else { - ux = uint(x); - } - return MakeInt(sign, Nat(ux)); -} - - -// Predicates - -// IsEven returns true iff x is divisible by 2. -// -func (x *Integer) IsEven() bool { - return x.mant.IsEven(); -} - - -// IsOdd returns true iff x is not divisible by 2. -// -func (x *Integer) IsOdd() bool { - return x.mant.IsOdd(); -} - - -// IsZero returns true iff x == 0. -// -func (x *Integer) IsZero() bool { - return x.mant.IsZero(); -} - - -// IsNeg returns true iff x < 0. -// -func (x *Integer) IsNeg() bool { - return x.sign && !x.mant.IsZero() -} - - -// IsPos returns true iff x >= 0. -// -func (x *Integer) IsPos() bool { - return !x.sign && !x.mant.IsZero() -} - - -// Operations - -// Neg returns the negated value of x. -// -func (x *Integer) Neg() *Integer { - return MakeInt(!x.sign, x.mant); -} - - -// Add returns the sum x + y. -// -func (x *Integer) Add(y *Integer) *Integer { - var z *Integer; - if x.sign == y.sign { - // x + y == x + y - // (-x) + (-y) == -(x + y) - z = MakeInt(x.sign, x.mant.Add(y.mant)); - } else { - // x + (-y) == x - y == -(y - x) - // (-x) + y == y - x == -(x - y) - if x.mant.Cmp(y.mant) >= 0 { - z = MakeInt(false, x.mant.Sub(y.mant)); - } else { - z = MakeInt(true, y.mant.Sub(x.mant)); - } - } - if x.sign { - z.sign = !z.sign; - } - return z; -} - - -// Sub returns the difference x - y. -// -func (x *Integer) Sub(y *Integer) *Integer { - var z *Integer; - if x.sign != y.sign { - // x - (-y) == x + y - // (-x) - y == -(x + y) - z = MakeInt(false, x.mant.Add(y.mant)); - } else { - // x - y == x - y == -(y - x) - // (-x) - (-y) == y - x == -(x - y) - if x.mant.Cmp(y.mant) >= 0 { - z = MakeInt(false, x.mant.Sub(y.mant)); - } else { - z = MakeInt(true, y.mant.Sub(x.mant)); - } - } - if x.sign { - z.sign = !z.sign; - } - return z; -} - - -// Mul returns the product x * y. -// -func (x *Integer) Mul(y *Integer) *Integer { - // x * y == x * y - // x * (-y) == -(x * y) - // (-x) * y == -(x * y) - // (-x) * (-y) == x * y - return MakeInt(x.sign != y.sign, x.mant.Mul(y.mant)); -} - - -// MulNat returns the product x * y, where y is a (unsigned) natural number. -// -func (x *Integer) MulNat(y Natural) *Integer { - // x * y == x * y - // (-x) * y == -(x * y) - return MakeInt(x.sign, x.mant.Mul(y)); -} - - -// Quo returns the quotient q = x / y for y != 0. -// If y == 0, a division-by-zero run-time error occurs. -// -// Quo and Rem implement T-division and modulus (like C99): -// -// q = x.Quo(y) = trunc(x/y) (truncation towards zero) -// r = x.Rem(y) = x - y*q -// -// (Daan Leijen, ``Division and Modulus for Computer Scientists''.) -// -func (x *Integer) Quo(y *Integer) *Integer { - // x / y == x / y - // x / (-y) == -(x / y) - // (-x) / y == -(x / y) - // (-x) / (-y) == x / y - return MakeInt(x.sign != y.sign, x.mant.Div(y.mant)); -} - - -// Rem returns the remainder r of the division x / y for y != 0, -// with r = x - y*x.Quo(y). Unless r is zero, its sign corresponds -// to the sign of x. -// If y == 0, a division-by-zero run-time error occurs. -// -func (x *Integer) Rem(y *Integer) *Integer { - // x % y == x % y - // x % (-y) == x % y - // (-x) % y == -(x % y) - // (-x) % (-y) == -(x % y) - return MakeInt(x.sign, x.mant.Mod(y.mant)); -} - - -// QuoRem returns the pair (x.Quo(y), x.Rem(y)) for y != 0. -// If y == 0, a division-by-zero run-time error occurs. -// -func (x *Integer) QuoRem(y *Integer) (*Integer, *Integer) { - q, r := x.mant.DivMod(y.mant); - return MakeInt(x.sign != y.sign, q), MakeInt(x.sign, r); -} - - -// Div returns the quotient q = x / y for y != 0. -// If y == 0, a division-by-zero run-time error occurs. -// -// Div and Mod implement Euclidian division and modulus: -// -// q = x.Div(y) -// r = x.Mod(y) with: 0 <= r < |q| and: y = x*q + r -// -// (Raymond T. Boute, ``The Euclidian definition of the functions -// div and mod''. ACM Transactions on Programming Languages and -// Systems (TOPLAS), 14(2):127-144, New York, NY, USA, 4/1992. -// ACM press.) -// -func (x *Integer) Div(y *Integer) *Integer { - q, r := x.QuoRem(y); - if r.IsNeg() { - if y.IsPos() { - q = q.Sub(Int(1)); - } else { - q = q.Add(Int(1)); - } - } - return q; -} - - -// Mod returns the modulus r of the division x / y for y != 0, -// with r = x - y*x.Div(y). r is always positive. -// If y == 0, a division-by-zero run-time error occurs. -// -func (x *Integer) Mod(y *Integer) *Integer { - r := x.Rem(y); - if r.IsNeg() { - if y.IsPos() { - r = r.Add(y); - } else { - r = r.Sub(y); - } - } - return r; -} - - -// DivMod returns the pair (x.Div(y), x.Mod(y)). -// -func (x *Integer) DivMod(y *Integer) (*Integer, *Integer) { - q, r := x.QuoRem(y); - if r.IsNeg() { - if y.IsPos() { - q = q.Sub(Int(1)); - r = r.Add(y); - } else { - q = q.Add(Int(1)); - r = r.Sub(y); - } - } - return q, r; -} - - -// Shl implements ``shift left'' x << s. It returns x * 2^s. -// -func (x *Integer) Shl(s uint) *Integer { - return MakeInt(x.sign, x.mant.Shl(s)); -} - - -// Shr implements ``shift right'' x >> s. It returns x / 2^s. -// Implementation restriction: Shl is not yet implemented for negative x. -// -func (x *Integer) Shr(s uint) *Integer { - z := MakeInt(x.sign, x.mant.Shr(s)); - if x.IsNeg() { - panic("UNIMPLEMENTED Integer.Shr of negative values"); - } - return z; -} - - -// And returns the ``bitwise and'' x & y for the binary representation of x and y. -// Implementation restriction: And is not implemented for negative x. -// -func (x *Integer) And(y *Integer) *Integer { - var z *Integer; - if !x.sign && !y.sign { - z = MakeInt(false, x.mant.And(y.mant)); - } else { - panic("UNIMPLEMENTED Integer.And of negative values"); - } - return z; -} - - -// Or returns the ``bitwise or'' x | y for the binary representation of x and y. -// Implementation restriction: Or is not implemented for negative x. -// -func (x *Integer) Or(y *Integer) *Integer { - var z *Integer; - if !x.sign && !y.sign { - z = MakeInt(false, x.mant.Or(y.mant)); - } else { - panic("UNIMPLEMENTED Integer.Or of negative values"); - } - return z; -} - - -// Xor returns the ``bitwise xor'' x | y for the binary representation of x and y. -// Implementation restriction: Xor is not implemented for negative integers. -// -func (x *Integer) Xor(y *Integer) *Integer { - var z *Integer; - if !x.sign && !y.sign { - z = MakeInt(false, x.mant.Xor(y.mant)); - } else { - panic("UNIMPLEMENTED Integer.Xor of negative values"); - } - return z; -} - - -// Cmp compares x and y. The result is an int value -// -// < 0 if x < y -// == 0 if x == y -// > 0 if x > y -// -func (x *Integer) Cmp(y *Integer) int { - // x cmp y == x cmp y - // x cmp (-y) == x - // (-x) cmp y == y - // (-x) cmp (-y) == -(x cmp y) - var r int; - switch { - case x.sign == y.sign: - r = x.mant.Cmp(y.mant); - if x.sign { - r = -r; - } - case x.sign: r = -1; - case y.sign: r = 1; - } - return r; -} - - -// ToString converts x to a string for a given base, with 2 <= base <= 16. -// -func (x *Integer) ToString(base uint) string { - if x.mant.IsZero() { - return "0"; - } - var s string; - if x.sign { - s = "-"; - } - return s + x.mant.ToString(base); -} - - -// String converts x to its decimal string representation. -// x.String() is the same as x.ToString(10). -// -func (x *Integer) String() string { - return x.ToString(10); -} - - -// Format is a support routine for fmt.Formatter. It accepts -// the formats 'b' (binary), 'o' (octal), and 'x' (hexadecimal). -// -func (x *Integer) Format(h fmt.Formatter, c int) { - fmt.Fprintf(h, "%s", x.ToString(fmtbase(c))); -} - - -// IntFromString returns the integer corresponding to the -// longest possible prefix of s representing an integer in a -// given conversion base, the actual conversion base used, and -// the prefix length. -// -// If the base argument is 0, the string prefix determines the actual -// conversion base. A prefix of ``0x'' or ``0X'' selects base 16; the -// ``0'' prefix selects base 8. Otherwise the selected base is 10. -// -func IntFromString(s string, base uint) (*Integer, uint, int) { - // skip sign, if any - i0 := 0; - if len(s) > 0 && (s[0] == '-' || s[0] == '+') { - i0 = 1; - } - - mant, base, slen := NatFromString(s[i0 : len(s)], base); - - return MakeInt(i0 > 0 && s[0] == '-', mant), base, i0 + slen; -} - - -// ---------------------------------------------------------------------------- -// Rational numbers - -// Rational represents a quotient a/b of arbitrary precision. -// -type Rational struct { - a *Integer; // numerator - b Natural; // denominator -} - - -// MakeRat makes a rational number given a numerator a and a denominator b. -// -func MakeRat(a *Integer, b Natural) *Rational { - f := a.mant.Gcd(b); // f > 0 - if f.Cmp(Nat(1)) != 0 { - a = MakeInt(a.sign, a.mant.Div(f)); - b = b.Div(f); - } - return &Rational{a, b}; -} - - -// Rat creates a small rational number with value a0/b0. -// Implementation restriction: At the moment, only values a0, b0 -// with an absolute value |a0|, |b0| < (1<<60) are supported. -// -func Rat(a0 int, b0 int) *Rational { - a, b := Int(a0), Int(b0); - if b.sign { - a = a.Neg(); - } - return MakeRat(a, b.mant); -} - - -// Predicates - -// IsZero returns true iff x == 0. -// -func (x *Rational) IsZero() bool { - return x.a.IsZero(); -} - - -// IsNeg returns true iff x < 0. -// -func (x *Rational) IsNeg() bool { - return x.a.IsNeg(); -} - - -// IsPos returns true iff x > 0. -// -func (x *Rational) IsPos() bool { - return x.a.IsPos(); -} - - -// IsInt returns true iff x can be written with a denominator 1 -// in the form x == x'/1; i.e., if x is an integer value. -// -func (x *Rational) IsInt() bool { - return x.b.Cmp(Nat(1)) == 0; -} - - -// Operations - -// Neg returns the negated value of x. -// -func (x *Rational) Neg() *Rational { - return MakeRat(x.a.Neg(), x.b); -} - - -// Add returns the sum x + y. -// -func (x *Rational) Add(y *Rational) *Rational { - return MakeRat((x.a.MulNat(y.b)).Add(y.a.MulNat(x.b)), x.b.Mul(y.b)); -} - - -// Sub returns the difference x - y. -// -func (x *Rational) Sub(y *Rational) *Rational { - return MakeRat((x.a.MulNat(y.b)).Sub(y.a.MulNat(x.b)), x.b.Mul(y.b)); -} - - -// Mul returns the product x * y. -// -func (x *Rational) Mul(y *Rational) *Rational { - return MakeRat(x.a.Mul(y.a), x.b.Mul(y.b)); -} - - -// Quo returns the quotient x / y for y != 0. -// If y == 0, a division-by-zero run-time error occurs. -// -func (x *Rational) Quo(y *Rational) *Rational { - a := x.a.MulNat(y.b); - b := y.a.MulNat(x.b); - if b.IsNeg() { - a = a.Neg(); - } - return MakeRat(a, b.mant); -} - - -// Cmp compares x and y. The result is an int value -// -// < 0 if x < y -// == 0 if x == y -// > 0 if x > y -// -func (x *Rational) Cmp(y *Rational) int { - return (x.a.MulNat(y.b)).Cmp(y.a.MulNat(x.b)); -} - - -// ToString converts x to a string for a given base, with 2 <= base <= 16. -// The string representation is of the form "n" if x is an integer; otherwise -// it is of form "n/d". -// -func (x *Rational) ToString(base uint) string { - s := x.a.ToString(base); - if !x.IsInt() { - s += "/" + x.b.ToString(base); - } - return s; -} - - -// String converts x to its decimal string representation. -// x.String() is the same as x.ToString(10). -// -func (x *Rational) String() string { - return x.ToString(10); -} - - -// Format is a support routine for fmt.Formatter. It accepts -// the formats 'b' (binary), 'o' (octal), and 'x' (hexadecimal). -// -func (x *Rational) Format(h fmt.Formatter, c int) { - fmt.Fprintf(h, "%s", x.ToString(fmtbase(c))); -} - - -// RatFromString returns the rational number corresponding to the -// longest possible prefix of s representing a rational number in a -// given conversion base, the actual conversion base used, and the -// prefix length. -// -// If the base argument is 0, the string prefix determines the actual -// conversion base. A prefix of ``0x'' or ``0X'' selects base 16; the -// ``0'' prefix selects base 8. Otherwise the selected base is 10. -// -func RatFromString(s string, base uint) (*Rational, uint, int) { - // read nominator - a, abase, alen := IntFromString(s, base); - b := Nat(1); - - // read denominator or fraction, if any - var blen int; - if alen < len(s) { - ch := s[alen]; - if ch == '/' { - alen++; - b, base, blen = NatFromString(s[alen : len(s)], base); - } else if ch == '.' { - alen++; - b, base, blen = NatFromString(s[alen : len(s)], abase); - assert(base == abase); - f := Nat(base).Pow(uint(blen)); - a = MakeInt(a.sign, a.mant.Mul(f).Add(b)); - b = f; - } - } - - return MakeRat(a, b), base, alen + blen; -} diff --git a/src/lib/bignum/bignum_test.go b/src/lib/bignum/bignum_test.go deleted file mode 100644 index 9351c2ebf..000000000 --- a/src/lib/bignum/bignum_test.go +++ /dev/null @@ -1,482 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package bignum_test - -import ( - bignum "bignum"; - fmt "fmt"; - testing "testing"; -) - -const ( - sa = "991"; - sb = "2432902008176640000"; // 20! - sc = "933262154439441526816992388562667004907159682643816214685929" - "638952175999932299156089414639761565182862536979208272237582" - "51185210916864000000000000000000000000"; // 100! - sp = "170141183460469231731687303715884105727"; // prime -) - -func natFromString(s string, base uint, slen *int) bignum.Natural { - x, _, len := bignum.NatFromString(s, base); - if slen != nil { - *slen = len; - } - return x; -} - - -func intFromString(s string, base uint, slen *int) *bignum.Integer { - x, _, len := bignum.IntFromString(s, base); - if slen != nil { - *slen = len; - } - return x; -} - - -func ratFromString(s string, base uint, slen *int) *bignum.Rational { - x, _, len := bignum.RatFromString(s, base); - if slen != nil { - *slen = len; - } - return x; -} - - -var ( - nat_zero = bignum.Nat(0); - nat_one = bignum.Nat(1); - nat_two = bignum.Nat(2); - - a = natFromString(sa, 10, nil); - b = natFromString(sb, 10, nil); - c = natFromString(sc, 10, nil); - p = natFromString(sp, 10, nil); - - int_zero = bignum.Int(0); - int_one = bignum.Int(1); - int_two = bignum.Int(2); - - ip = intFromString(sp, 10, nil); - - rat_zero = bignum.Rat(0, 1); - rat_half = bignum.Rat(1, 2); - rat_one = bignum.Rat(1, 1); - rat_two = bignum.Rat(2, 1); -) - - -var test_msg string; -var tester *testing.T; - -func test(n uint, b bool) { - if !b { - tester.Fatalf("TEST failed: %s (%d)", test_msg, n); - } -} - - -func nat_eq(n uint, x, y bignum.Natural) { - if x.Cmp(y) != 0 { - tester.Fatalf("TEST failed: %s (%d)\nx = %v\ny = %v", test_msg, n, &x, &y); - } -} - - -func int_eq(n uint, x, y *bignum.Integer) { - if x.Cmp(y) != 0 { - tester.Fatalf("TEST failed: %s (%d)\nx = %v\ny = %v", test_msg, n, x, y); - } -} - - -func rat_eq(n uint, x, y *bignum.Rational) { - if x.Cmp(y) != 0 { - tester.Fatalf("TEST failed: %s (%d)\nx = %v\ny = %v", test_msg, n, x, y); - } -} - -func TestNatConv(t *testing.T) { - tester = t; - test_msg = "NatConvA"; - nat_eq(0, a, bignum.Nat(991)); - nat_eq(1, b, bignum.Fact(20)); - nat_eq(2, c, bignum.Fact(100)); - test(3, a.String() == sa); - test(4, b.String() == sb); - test(5, c.String() == sc); - - test_msg = "NatConvB"; - var slen int; - nat_eq(10, natFromString("0", 0, nil), nat_zero); - nat_eq(11, natFromString("123", 0, nil), bignum.Nat(123)); - nat_eq(12, natFromString("077", 0, nil), bignum.Nat(7*8 + 7)); - nat_eq(13, natFromString("0x1f", 0, nil), bignum.Nat(1*16 + 15)); - nat_eq(14, natFromString("0x1fg", 0, &slen), bignum.Nat(1*16 + 15)); - test(4, slen == 4); - - test_msg = "NatConvC"; - tmp := c.Mul(c); - for base := uint(2); base <= 16; base++ { - nat_eq(base, natFromString(tmp.ToString(base), base, nil), tmp); - } - - test_msg = "NatConvD"; - x := bignum.Nat(100); - y, b, _ := bignum.NatFromString(fmt.Sprintf("%b", &x), 2); - nat_eq(100, y, x); -} - - -func TestIntConv(t *testing.T) { - tester = t; - test_msg = "IntConv"; - var slen int; - int_eq(0, intFromString("0", 0, nil), int_zero); - int_eq(1, intFromString("-0", 0, nil), int_zero); - int_eq(2, intFromString("123", 0, nil), bignum.Int(123)); - int_eq(3, intFromString("-123", 0, nil), bignum.Int(-123)); - int_eq(4, intFromString("077", 0, nil), bignum.Int(7*8 + 7)); - int_eq(5, intFromString("-077", 0, nil), bignum.Int(-(7*8 + 7))); - int_eq(6, intFromString("0x1f", 0, nil), bignum.Int(1*16 + 15)); - int_eq(7, intFromString("-0x1f", 0, &slen), bignum.Int(-(1*16 + 15))); - test(7, slen == 5); - int_eq(8, intFromString("+0x1f", 0, &slen), bignum.Int(+(1*16 + 15))); - test(8, slen == 5); - int_eq(9, intFromString("0x1fg", 0, &slen), bignum.Int(1*16 + 15)); - test(9, slen == 4); - int_eq(10, intFromString("-0x1fg", 0, &slen), bignum.Int(-(1*16 + 15))); - test(10, slen == 5); -} - - -func TestRatConv(t *testing.T) { - tester = t; - test_msg = "RatConv"; - var slen int; - rat_eq(0, ratFromString("0", 0, nil), rat_zero); - rat_eq(1, ratFromString("0/1", 0, nil), rat_zero); - rat_eq(2, ratFromString("0/01", 0, nil), rat_zero); - rat_eq(3, ratFromString("0x14/10", 0, &slen), rat_two); - test(4, slen == 7); - rat_eq(5, ratFromString("0.", 0, nil), rat_zero); - rat_eq(6, ratFromString("0.001f", 10, nil), bignum.Rat(1, 1000)); - rat_eq(7, ratFromString("10101.0101", 2, nil), bignum.Rat(0x155, 1<<4)); - rat_eq(8, ratFromString("-0003.145926", 10, &slen), bignum.Rat(-3145926, 1000000)); - test(9, slen == 12); -} - - -func add(x, y bignum.Natural) bignum.Natural { - z1 := x.Add(y); - z2 := y.Add(x); - if z1.Cmp(z2) != 0 { - tester.Fatalf("addition not symmetric:\n\tx = %v\n\ty = %t", x, y); - } - return z1; -} - - -func sum(n uint, scale bignum.Natural) bignum.Natural { - s := nat_zero; - for ; n > 0; n-- { - s = add(s, bignum.Nat(n).Mul(scale)); - } - return s; -} - - -func TestNatAdd(t *testing.T) { - tester = t; - test_msg = "NatAddA"; - nat_eq(0, add(nat_zero, nat_zero), nat_zero); - nat_eq(1, add(nat_zero, c), c); - - test_msg = "NatAddB"; - for i := uint(0); i < 100; i++ { - t := bignum.Nat(i); - nat_eq(i, sum(i, c), t.Mul(t).Add(t).Shr(1).Mul(c)); - } -} - - -func mul(x, y bignum.Natural) bignum.Natural { - z1 := x.Mul(y); - z2 := y.Mul(x); - if z1.Cmp(z2) != 0 { - tester.Fatalf("multiplication not symmetric:\n\tx = %v\n\ty = %t", x, y); - } - if !x.IsZero() && z1.Div(x).Cmp(y) != 0 { - tester.Fatalf("multiplication/division not inverse (A):\n\tx = %v\n\ty = %t", x, y); - } - if !y.IsZero() && z1.Div(y).Cmp(x) != 0 { - tester.Fatalf("multiplication/division not inverse (B):\n\tx = %v\n\ty = %t", x, y); - } - return z1; -} - - -func TestNatSub(t *testing.T) { - tester = t; - test_msg = "NatSubA"; - nat_eq(0, nat_zero.Sub(nat_zero), nat_zero); - nat_eq(1, c.Sub(nat_zero), c); - - test_msg = "NatSubB"; - for i := uint(0); i < 100; i++ { - t := sum(i, c); - for j := uint(0); j <= i; j++ { - t = t.Sub(mul(bignum.Nat(j), c)); - } - nat_eq(i, t, nat_zero); - } -} - - -func TestNatMul(t *testing.T) { - tester = t; - test_msg = "NatMulA"; - nat_eq(0, mul(c, nat_zero), nat_zero); - nat_eq(1, mul(c, nat_one), c); - - test_msg = "NatMulB"; - nat_eq(0, b.Mul(bignum.MulRange(0, 100)), nat_zero); - nat_eq(1, b.Mul(bignum.MulRange(21, 100)), c); - - test_msg = "NatMulC"; - const n = 100; - p := b.Mul(c).Shl(n); - for i := uint(0); i < n; i++ { - nat_eq(i, mul(b.Shl(i), c.Shl(n-i)), p); - } -} - - -func TestNatDiv(t *testing.T) { - tester = t; - test_msg = "NatDivA"; - nat_eq(0, c.Div(nat_one), c); - nat_eq(1, c.Div(bignum.Nat(100)), bignum.Fact(99)); - nat_eq(2, b.Div(c), nat_zero); - nat_eq(4, nat_one.Shl(100).Div(nat_one.Shl(90)), nat_one.Shl(10)); - nat_eq(5, c.Div(b), bignum.MulRange(21, 100)); - - test_msg = "NatDivB"; - const n = 100; - p := bignum.Fact(n); - for i := uint(0); i < n; i++ { - nat_eq(100+i, p.Div(bignum.MulRange(1, i)), bignum.MulRange(i+1, n)); - } -} - - -func TestIntQuoRem(t *testing.T) { - tester = t; - test_msg = "IntQuoRem"; - type T struct { x, y, q, r int }; - a := []T{ - T{+8, +3, +2, +2}, - T{+8, -3, -2, +2}, - T{-8, +3, -2, -2}, - T{-8, -3, +2, -2}, - T{+1, +2, 0, +1}, - T{+1, -2, 0, +1}, - T{-1, +2, 0, -1}, - T{-1, -2, 0, -1}, - }; - for i := uint(0); i < uint(len(a)); i++ { - e := &a[i]; - x, y := bignum.Int(e.x).Mul(ip), bignum.Int(e.y).Mul(ip); - q, r := bignum.Int(e.q), bignum.Int(e.r).Mul(ip); - qq, rr := x.QuoRem(y); - int_eq(4*i+0, x.Quo(y), q); - int_eq(4*i+1, x.Rem(y), r); - int_eq(4*i+2, qq, q); - int_eq(4*i+3, rr, r); - } -} - - -func TestIntDivMod(t *testing.T) { - tester = t; - test_msg = "IntDivMod"; - type T struct { x, y, q, r int }; - a := []T{ - T{+8, +3, +2, +2}, - T{+8, -3, -2, +2}, - T{-8, +3, -3, +1}, - T{-8, -3, +3, +1}, - T{+1, +2, 0, +1}, - T{+1, -2, 0, +1}, - T{-1, +2, -1, +1}, - T{-1, -2, +1, +1}, - }; - for i := uint(0); i < uint(len(a)); i++ { - e := &a[i]; - x, y := bignum.Int(e.x).Mul(ip), bignum.Int(e.y).Mul(ip); - q, r := bignum.Int(e.q), bignum.Int(e.r).Mul(ip); - qq, rr := x.DivMod(y); - int_eq(4*i+0, x.Div(y), q); - int_eq(4*i+1, x.Mod(y), r); - int_eq(4*i+2, qq, q); - int_eq(4*i+3, rr, r); - } -} - - -func TestNatMod(t *testing.T) { - tester = t; - test_msg = "NatModA"; - for i := uint(0); ; i++ { - d := nat_one.Shl(i); - if d.Cmp(c) < 0 { - nat_eq(i, c.Add(d).Mod(c), d); - } else { - nat_eq(i, c.Add(d).Div(c), nat_two); - nat_eq(i, c.Add(d).Mod(c), d.Sub(c)); - break; - } - } -} - - -func TestNatShift(t *testing.T) { - tester = t; - test_msg = "NatShift1L"; - test(0, b.Shl(0).Cmp(b) == 0); - test(1, c.Shl(1).Cmp(c) > 0); - - test_msg = "NatShift1R"; - test(3, b.Shr(0).Cmp(b) == 0); - test(4, c.Shr(1).Cmp(c) < 0); - - test_msg = "NatShift2"; - for i := uint(0); i < 100; i++ { - test(i, c.Shl(i).Shr(i).Cmp(c) == 0); - } - - test_msg = "NatShift3L"; - { const m = 3; - p := b; - f := bignum.Nat(1< 0); - - test_msg = "IntShift1R"; - test(0, ip.Shr(0).Cmp(ip) == 0); - test(1, ip.Shr(1).Cmp(ip) < 0); - - test_msg = "IntShift2"; - for i := uint(0); i < 100; i++ { - test(i, ip.Shl(i).Shr(i).Cmp(ip) == 0); - } - - test_msg = "IntShift3L"; - { const m = 3; - p := ip; - f := bignum.Int(1<> 1)); - //int_eq(1, ip.Neg().Shr(10), ip.Neg().Div(bignum.Int(1).Shl(10))); -} - - -func TestNatCmp(t *testing.T) { - tester = t; - test_msg = "NatCmp"; - test(0, a.Cmp(a) == 0); - test(1, a.Cmp(b) < 0); - test(2, b.Cmp(a) > 0); - test(3, a.Cmp(c) < 0); - d := c.Add(b); - test(4, c.Cmp(d) < 0); - test(5, d.Cmp(c) > 0); -} - - -func TestNatLog2(t *testing.T) { - tester = t; - test_msg = "NatLog2A"; - test(0, nat_one.Log2() == 0); - test(1, nat_two.Log2() == 1); - test(2, bignum.Nat(3).Log2() == 1); - test(3, bignum.Nat(4).Log2() == 2); - - test_msg = "NatLog2B"; - for i := uint(0); i < 100; i++ { - test(i, nat_one.Shl(i).Log2() == i); - } -} - - -func TestNatGcd(t *testing.T) { - tester = t; - test_msg = "NatGcdA"; - f := bignum.Nat(99991); - nat_eq(0, b.Mul(f).Gcd(c.Mul(f)), bignum.MulRange(1, 20).Mul(f)); -} - - -func TestNatPow(t *testing.T) { - tester = t; - test_msg = "NatPowA"; - nat_eq(0, nat_two.Pow(0), nat_one); - - test_msg = "NatPowB"; - for i := uint(0); i < 100; i++ { - nat_eq(i, nat_two.Pow(i), nat_one.Shl(i)); - } -} - - -func TestNatPop(t *testing.T) { - tester = t; - test_msg = "NatPopA"; - test(0, nat_zero.Pop() == 0); - test(1, nat_one.Pop() == 1); - test(2, bignum.Nat(10).Pop() == 2); - test(3, bignum.Nat(30).Pop() == 4); - test(4, bignum.Nat(0x1248f).Shl(33).Pop() == 8); - - test_msg = "NatPopB"; - for i := uint(0); i < 100; i++ { - test(i, nat_one.Shl(i).Sub(nat_one).Pop() == i); - } -} - diff --git a/src/lib/bufio/Makefile b/src/lib/bufio/Makefile deleted file mode 100644 index abb826e7f..000000000 --- a/src/lib/bufio/Makefile +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m >Makefile - -D= - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - bufio.$O\ - - -phases: a1 -_obj$D/bufio.a: phases - -a1: $(O1) - $(AR) grc _obj$D/bufio.a bufio.$O - rm -f $(O1) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/bufio.a - -$(O1): newpkg -$(O2): a1 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/bufio.a - -packages: _obj$D/bufio.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/bufio.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/bufio.a diff --git a/src/lib/bufio/bufio.go b/src/lib/bufio/bufio.go deleted file mode 100644 index 7bfbb089f..000000000 --- a/src/lib/bufio/bufio.go +++ /dev/null @@ -1,515 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// This package implements buffered I/O. It wraps an io.Reader or io.Writer -// object, creating another object (Reader or Writer) that also implements -// the interface but provides buffering and some help for textual I/O. -package bufio - -import ( - "io"; - "os"; - "utf8"; -) - - -// TODO: -// - maybe define an interface -// - Reader: ReadRune, UnreadRune ? -// could make ReadRune generic if we dropped UnreadRune -// - buffered output - -const ( - defaultBufSize = 4096 -) - -// Errors introduced by this package. -type Error struct { - os.ErrorString; -} - -var ( - PhaseError os.Error = &Error{"bufio: phase error"}; - BufferFull os.Error = &Error{"bufio: buffer full"}; - InternalError os.Error = &Error{"bufio: internal error"}; - BadBufSize os.Error = &Error{"bufio: bad buffer size"}; -) - -func copySlice(dst []byte, src []byte) { - for i := 0; i < len(dst); i++ { - dst[i] = src[i] - } -} - - -// 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; -} - -// 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, BadBufSize - } - // 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; - 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("bufio: NewReader: ", err.String()); - } - return b; -} - -//.fill reads a new chunk into the buffer. -func (b *Reader) fill() os.Error { - if b.err != nil { - return b.err - } - - // Slide existing data to beginning. - if b.w > b.r { - copySlice(b.buf[0:b.w-b.r], b.buf[b.r:b.w]); - b.w -= b.r; - } else { - b.w = 0 - } - b.r = 0; - - // Read new data. - n, e := b.rd.Read(b.buf[b.w:len(b.buf)]); - if e != nil { - b.err = e; - return e - } - b.w += n; - return nil -} - -// Read reads data into p. -// It returns the number of bytes read into p. -// If nn < len(p), also returns an error explaining -// why the read is short. At EOF, the count will be -// zero and err will be io.ErrEOF. -func (b *Reader) Read(p []byte) (nn int, err os.Error) { - nn = 0; - for len(p) > 0 { - n := len(p); - if b.w == b.r { - if len(p) >= len(b.buf) { - // Large read, empty buffer. - // Read directly into p to avoid copy. - n, b.err = b.rd.Read(p); - if n > 0 { - b.lastbyte = int(p[n-1]); - } - p = p[n:len(p)]; - nn += n; - if b.err != nil { - return nn, b.err - } - if n == 0 { - return nn, io.ErrEOF - } - continue; - } - b.fill(); - if b.err != nil { - return nn, b.err - } - if b.w == b.r { - return nn, io.ErrEOF - } - } - if n > b.w - b.r { - n = b.w - b.r - } - copySlice(p[0:n], b.buf[b.r:b.r+n]); - p = p[n:len(p)]; - b.r += n; - b.lastbyte = int(b.buf[b.r-1]); - nn += n - } - return nn, 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) { - if b.w == b.r { - b.fill(); - if b.err != nil { - return 0, b.err - } - if b.w == b.r { - return 0, io.ErrEOF - } - } - c = b.buf[b.r]; - b.r++; - b.lastbyte = int(c); - return c, nil -} - -// UnreadByte unreads the last byte. Only one byte may be unread at a given time. -func (b *Reader) UnreadByte() os.Error { - if b.err != nil { - return b.err - } - 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 PhaseError - } - 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]) { - n := b.w - b.r; - b.fill(); - if b.err != nil { - return 0, 0, b.err - } - if b.w - b.r == n { - // no bytes read - if b.r == b.w { - return 0, 0, io.ErrEOF - } - break; - } - } - 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]); - return rune, size, nil -} - -// Helper function: look for byte c in array p, -// returning its index or -1. -func findByte(p []byte, c byte) int { - for i := 0; i < len(p); i++ { - if p[i] == c { - return i - } - } - return -1 -} - -// Buffered returns the number of bytes that can be read from the current buffer. -func (b *Reader) Buffered() int { - return b.w - b.r; -} - -// ReadLineSlice 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. -// Fails if the line doesn't fit in the buffer. -// For internal or advanced use only; most uses should -// call ReadLineString or ReadLineBytes instead. -func (b *Reader) ReadLineSlice(delim byte) (line []byte, err os.Error) { - if b.err != nil { - return nil, b.err - } - - // Look in buffer. - if i := findByte(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 { - n := b.Buffered(); - b.fill(); - if b.err != nil { - return nil, b.err - } - if b.Buffered() == n { // no data added; end of file - line := b.buf[b.r:b.w]; - b.r = b.w; - return line, io.ErrEOF - } - - // Search new part of buffer - if i := findByte(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) { - return nil, BufferFull - } - } - - // BUG 6g bug100 - return nil, nil -} - -// ReadLineBytes reads until the first occurrence of delim in the input, -// returning a new byte array containing the line. -// If an error happens, returns the data (without a delimiter) -// and the error. (It can't leave the data in the buffer because -// it might have read more than the buffer size.) -func (b *Reader) ReadLineBytes(delim byte) (line []byte, err os.Error) { - if b.err != nil { - return nil, b.err - } - - // Use ReadLineSlice to look for array, - // accumulating full buffers. - var frag []byte; - var full [][]byte; - nfull := 0; - err = nil; - - for { - var e os.Error; - frag, e = b.ReadLineSlice(delim); - if e == nil { // got final fragment - break - } - if e != BufferFull { // unexpected error - err = e; - break - } - - // Read bytes out of buffer. - buf := make([]byte, b.Buffered()); - var n int; - n, e = b.Read(buf); - if e != nil { - frag = buf[0:n]; - err = e; - break - } - if n != len(buf) { - frag = buf[0:n]; - err = InternalError; - break - } - - // Grow list if needed. - if full == nil { - full = make([][]byte, 16); - } else if nfull >= len(full) { - newfull := make([][]byte, len(full)*2); - // BUG slice assignment - for i := 0; i < len(full); i++ { - newfull[i] = full[i]; - } - full = newfull - } - - // Save buffer - full[nfull] = buf; - nfull++; - } - - // Allocate new buffer to hold the full pieces and the fragment. - n := 0; - for i := 0; i < nfull; i++ { - n += len(full[i]) - } - n += len(frag); - - // Copy full pieces and fragment in. - buf := make([]byte, n); - n = 0; - for i := 0; i < nfull; i++ { - copySlice(buf[n:n+len(full[i])], full[i]); - n += len(full[i]) - } - copySlice(buf[n:n+len(frag)], frag); - return buf, err -} - -// ReadLineString reads until the first occurrence of delim in the input, -// returning a new string containing the line. -// If savedelim, keep delim in the result; otherwise drop it. -func (b *Reader) ReadLineString(delim byte, savedelim bool) (line string, err os.Error) { - bytes, e := b.ReadLineBytes(delim); - if e != nil { - return string(bytes), e - } - if !savedelim { - bytes = bytes[0:len(bytes)-1] - } - return string(bytes), nil -} - - -// 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, BadBufSize - } - // 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("bufio: NewWriter: ", err.String()); - } - return b; -} - -// Flush writes any buffered data to the underlying io.Writer. -func (b *Writer) Flush() os.Error { - if b.err != nil { - return b.err - } - n, e := b.wr.Write(b.buf[0:b.n]); - if n < b.n && e == nil { - e = io.ErrShortWrite; - } - if e != nil { - if n > 0 && n < b.n { - copySlice(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), also returns an error explaining -// why the write is short. -func (b *Writer) Write(p []byte) (nn int, err os.Error) { - if b.err != nil { - return 0, b.err - } - nn = 0; - for len(p) > 0 { - n := b.Available(); - if n <= 0 { - if b.Flush(); b.err != nil { - break - } - n = b.Available() - } - if b.Available() == 0 && len(p) >= len(b.buf) { - // Large write, empty buffer. - // Write directly from p to avoid copy. - n, b.err = b.wr.Write(p); - nn += n; - p = p[n:len(p)]; - if b.err != nil { - break; - } - continue; - } - if n > len(p) { - n = len(p) - } - copySlice(b.buf[b.n:b.n+n], p[0:n]); - b.n += n; - nn += n; - p = p[n:len(p)] - } - return nn, b.err -} - -// WriteByte writes a single byte. -func (b *Writer) WriteByte(c byte) os.Error { - if b.err != nil { - return b.err - } - if b.Available() <= 0 && b.Flush() != nil { - return b.err - } - b.buf[b.n] = c; - b.n++; - return nil -} - -// 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/lib/bufio/bufio_test.go b/src/lib/bufio/bufio_test.go deleted file mode 100644 index 6e5135df7..000000000 --- a/src/lib/bufio/bufio_test.go +++ /dev/null @@ -1,298 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package bufio - -import ( - "bufio"; - "fmt"; - "io"; - "os"; - "testing"; - "testing/iotest"; -) - -// 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 == io.ErrEOF { - break - } - if e != nil { - panic("Data: "+e.String()) - } - b[nb] = c; - nb++; - } - return string(b[0:nb]) -} - -func TestReaderSimple(t *testing.T) { - data := io.StringBytes("hello world"); - b := NewReader(io.NewByteReader(data)); - if s := readBytes(b); s != "hello world" { - t.Errorf("simple hello world test failed: got %q", s); - } - - b = NewReader(newRot13Reader(io.NewByteReader(data))); - if s := readBytes(b); s != "uryyb jbeyq" { - t.Error("rot13 hello world test failed: got %q", s); - } -} - - -type readMaker struct { - name string; - fn func(io.Reader) io.Reader; -} -var readMakers = []readMaker { - readMaker{ "full", func(r io.Reader) io.Reader { return r } }, - readMaker{ "byte", iotest.OneByteReader }, - readMaker{ "half", iotest.HalfReader }, -} - -// Call ReadLineString (which ends up calling everything else) -// to accumulate the text of a file. -func readLines(b *Reader) string { - s := ""; - for { - s1, e := b.ReadLineString('\n', true); - if e == io.ErrEOF { - break - } - if e != nil { - panic("GetLines: "+e.String()) - } - s += s1 - } - return s -} - -// Call Read to accumulate the text of a file -func reads(buf *Reader, m int) string { - var b [1000]byte; - nb := 0; - for { - n, e := buf.Read(b[nb:nb+m]); - nb += n; - if e == io.ErrEOF { - break - } - } - return string(b[0:nb]) -} - -type bufReader struct { - name string; - fn func(*Reader) string; -} -var bufreaders = []bufReader { - bufReader{ "1", func(b *Reader) string { return reads(b, 1) } }, - bufReader{ "2", func(b *Reader) string { return reads(b, 2) } }, - bufReader{ "3", func(b *Reader) string { return reads(b, 3) } }, - bufReader{ "4", func(b *Reader) string { return reads(b, 4) } }, - bufReader{ "5", func(b *Reader) string { return reads(b, 5) } }, - bufReader{ "7", func(b *Reader) string { return reads(b, 7) } }, - bufReader{ "bytes", readBytes }, - bufReader{ "lines", readLines }, -} - -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]; - textbytes := io.StringBytes(text); - 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(io.NewByteReader(textbytes)); - buf, e := 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); - } - } - } - } - } -} - -func TestWriter(t *testing.T) { - var data [8192]byte; - - for i := 0; i < len(data); i++ { - data[i] = byte(' '+ i%('~'-' ')); - } - w := new(io.ByteBuffer); - 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.Data(); - 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("%s: wrong bytes written"); - t.Errorf("want=%s", data[0:len(written)]); - t.Errorf("have=%s", 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 { - errorWriterTest{ 0, 1, nil, io.ErrShortWrite }, - errorWriterTest{ 1, 2, nil, io.ErrShortWrite }, - errorWriterTest{ 1, 1, nil, nil }, - errorWriterTest{ 0, 1, os.EPIPE, os.EPIPE }, - errorWriterTest{ 1, 2, os.EPIPE, os.EPIPE }, - errorWriterTest{ 1, 1, os.EPIPE, os.EPIPE }, -} - -func TestWriteErrors(t *testing.T) { - for i, w := range errorWriterTests { - buf := NewWriter(w); - n, e := buf.Write(io.StringBytes("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(io.NewByteReader(io.StringBytes("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(io.ByteBuffer), 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"); - } -} diff --git a/src/lib/bytes/Makefile b/src/lib/bytes/Makefile deleted file mode 100644 index 5220d2880..000000000 --- a/src/lib/bytes/Makefile +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m >Makefile - -D= - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - bytes.$O\ - - -phases: a1 -_obj$D/bytes.a: phases - -a1: $(O1) - $(AR) grc _obj$D/bytes.a bytes.$O - rm -f $(O1) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/bytes.a - -$(O1): newpkg -$(O2): a1 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/bytes.a - -packages: _obj$D/bytes.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/bytes.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/bytes.a diff --git a/src/lib/bytes/bytes.go b/src/lib/bytes/bytes.go deleted file mode 100644 index dd299a82e..000000000 --- a/src/lib/bytes/bytes.go +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// A package of simple functions to manipulate arrays of bytes. -// Analagous to the facilities of the strings package. -package bytes - -import "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 { - for i := 0; i < len(a) && i < len(b); i++ { - switch { - case a[i] > b[i]: - return 1 - case a[i] < b[i]: - 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 := 0; i < len(a); i++ { - if a[i] != b[i] { - return false - } - } - return true -} - -// Copy copies the source to the destination, stopping when the source -// is all transferred. The caller must guarantee that there is enough -// room in the destination. It returns the number of bytes copied -func Copy(dst, src []byte) int { - for i, x := range src { - dst[i] = x - } - return len(src) -} - -// Explode splits s into an array of UTF-8 sequences, one per Unicode character (still arrays of bytes). -// Invalid UTF-8 sequences become correct encodings of U+FFF8. -func Explode(s []byte) [][]byte { - a := make([][]byte, utf8.RuneCount(s)); - var size, rune int; - i := 0; - for len(s) > 0 { - rune, size = utf8.DecodeRune(s); - a[i] = s[0:size]; - s = s[size:len(s)]; - i++; - } - return a -} - -// 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 -} - -// Split returns the array representing the subarrays of s separated by sep. Adjacent -// occurrences of sep produce empty subarrays. If sep is empty, it is the same as Explode. -func Split(s, sep []byte) [][]byte { - if len(sep) == 0 { - return Explode(s) - } - c := sep[0]; - start := 0; - n := Count(s, sep)+1; - a := make([][]byte, n); - na := 0; - for i := 0; i+len(sep) <= len(s); i++ { - if s[i] == c && (len(sep) == 1 || Equal(s[i:i+len(sep)], sep)) { - a[na] = s[start:i]; - na++; - start = i+len(sep); - i += len(sep)-1 - } - } - a[na] = s[start:len(s)]; - return a -} - -// Join concatenates the elements of a to create a single byte array. The separator -// sep is placed between elements in the resulting array. -func Join(a [][]byte, sep []byte) []byte { - if len(a) == 0 { - return []byte{} - } - if len(a) == 1 { - return a[0] - } - n := len(sep) * (len(a)-1); - for i := 0; i < len(a); i++ { - n += len(a[i]) - } - - b := make([]byte, n); - bp := 0; - for i := 0; i < len(a); i++ { - s := a[i]; - for j := 0; j < len(s); j++ { - b[bp] = s[j]; - bp++ - } - if i + 1 < len(a) { - s = sep; - for j := 0; j < len(s); j++ { - b[bp] = s[j]; - bp++ - } - } - } - return b -} - -// HasPrefix tests whether the byte array s begins with prefix. -func HasPrefix(s, prefix []byte) bool { - return len(s) >= len(prefix) && Equal(s[0:len(prefix)], prefix) -} - -// HasSuffix tests whether the byte array s ends with suffix. -func HasSuffix(s, suffix []byte) bool { - return len(s) >= len(suffix) && Equal(s[len(s)-len(suffix):len(s)], suffix) -} diff --git a/src/lib/bytes/bytes_test.go b/src/lib/bytes/bytes_test.go deleted file mode 100644 index 4e7cdfad6..000000000 --- a/src/lib/bytes/bytes_test.go +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package bytes - -import ( - "bytes"; - "io"; - "testing"; -) - -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 CompareTest struct { - a string; - b string; - cmp int; -} -var comparetests = []CompareTest { - CompareTest{ "", "", 0 }, - CompareTest{ "a", "", 1 }, - CompareTest{ "", "a", -1 }, - CompareTest{ "abc", "abc", 0 }, - CompareTest{ "ab", "abc", -1 }, - CompareTest{ "abc", "ab", 1 }, - CompareTest{ "x", "ab", 1 }, - CompareTest{ "ab", "x", -1 }, - CompareTest{ "x", "a", 1 }, - CompareTest{ "b", "x", -1 }, -} - -func TestCompare(t *testing.T) { - for i := 0; i < len(comparetests); i++ { - tt := comparetests[i]; - a := io.StringBytes(tt.a); - b := io.StringBytes(tt.b); - cmp := Compare(a, b); - eql := Equal(a, b); - if cmp != tt.cmp { - t.Errorf(`Compare(%q, %q) = %v`, tt.a, tt.b, cmp); - } - if eql != (tt.cmp==0) { - t.Errorf(`Equal(%q, %q) = %v`, tt.a, tt.b, eql); - } - } -} - - -type ExplodeTest struct { - s string; - a []string; -} -var explodetests = []ExplodeTest { - ExplodeTest{ abcd, []string{"a", "b", "c", "d"} }, - ExplodeTest{ faces, []string{"☺", "☻", "☹" } }, -} -func TestExplode(t *testing.T) { - for i := 0; i < len(explodetests); i++ { - tt := explodetests[i]; - a := Explode(io.StringBytes(tt.s)); - result := arrayOfString(a); - if !eq(result, tt.a) { - t.Errorf(`Explode("%s") = %v; want %v`, tt.s, result, tt.a); - continue; - } - s := Join(a, []byte{}); - if string(s) != tt.s { - t.Errorf(`Join(Explode("%s"), "") = "%s"`, tt.s, s); - } - } -} - - -type SplitTest struct { - s string; - sep string; - a []string; -} -var splittests = []SplitTest { - SplitTest{ abcd, "a", []string{"", "bcd"} }, - SplitTest{ abcd, "z", []string{"abcd"} }, - SplitTest{ abcd, "", []string{"a", "b", "c", "d"} }, - SplitTest{ commas, ",", []string{"1", "2", "3", "4"} }, - SplitTest{ dots, "...", []string{"1", ".2", ".3", ".4"} }, - SplitTest{ faces, "☹", []string{"☺☻", ""} }, - SplitTest{ faces, "~", []string{faces} }, - SplitTest{ faces, "", []string{"☺", "☻", "☹"} }, -} -func TestSplit(t *testing.T) { - for i := 0; i < len(splittests); i++ { - tt := splittests[i]; - a := Split(io.StringBytes(tt.s), io.StringBytes(tt.sep)); - result := arrayOfString(a); - if !eq(result, tt.a) { - t.Errorf(`Split("%s", "%s") = %v; want %v`, tt.s, tt.sep, result, tt.a); - continue; - } - s := Join(a, io.StringBytes(tt.sep)); - if string(s) != tt.s { - t.Errorf(`Join(Split("%s", "%s"), "%s") = "%s"`, tt.s, tt.sep, tt.sep, s); - } - } -} - -type CopyTest struct { - a string; - b string; - res string; -} -var copytests = []CopyTest { - CopyTest{ "", "", "" }, - CopyTest{ "a", "", "a" }, - CopyTest{ "a", "a", "a" }, - CopyTest{ "a", "b", "b" }, - CopyTest{ "xyz", "abc", "abc" }, - CopyTest{ "wxyz", "abc", "abcz" }, -} - -func TestCopy(t *testing.T) { - for i := 0; i < len(copytests); i++ { - tt := copytests[i]; - dst := io.StringBytes(tt.a); - Copy(dst, io.StringBytes(tt.b)); - result := string(dst); - if result != tt.res { - t.Errorf(`Copy("%s", "%s") = "%s"; want "%s"`, tt.a, tt.b, result, tt.res); - continue; - } - } -} diff --git a/src/lib/compress/flate/Makefile b/src/lib/compress/flate/Makefile deleted file mode 100644 index 3f73a1932..000000000 --- a/src/lib/compress/flate/Makefile +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m >Makefile - -D=/compress/ - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - inflate.$O\ - - -phases: a1 -_obj$D/flate.a: phases - -a1: $(O1) - $(AR) grc _obj$D/flate.a inflate.$O - rm -f $(O1) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/flate.a - -$(O1): newpkg -$(O2): a1 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/flate.a - -packages: _obj$D/flate.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/flate.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/flate.a diff --git a/src/lib/compress/flate/flate_test.go b/src/lib/compress/flate/flate_test.go deleted file mode 100644 index 309606ecb..000000000 --- a/src/lib/compress/flate/flate_test.go +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2009 The Go 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 inflater. - -package flate - -import ( - "bufio"; - "compress/flate"; - "io"; - "os"; - "reflect"; - "strconv"; - "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, - 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); - } - } -} diff --git a/src/lib/compress/flate/inflate.go b/src/lib/compress/flate/inflate.go deleted file mode 100644 index c07c94c6e..000000000 --- a/src/lib/compress/flate/inflate.go +++ /dev/null @@ -1,673 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// The flate package implements the DEFLATE compressed data -// format, described in RFC 1951. The gzip and zlib packages -// implement access to DEFLATE-based file formats. -package flate - -import ( - "bufio"; - "io"; - "os"; - "strconv"; -) - -const ( - maxCodeLen = 16; // max length of Huffman code - maxHist = 32768; // max history required - maxLit = 286; - maxDist = 32; - numCodes = 19; // number of codes in Huffman meta-code -) - -// TODO(rsc): Publish in another package? -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, -} - -// A CorruptInputError reports the presence of corrupt input at a given offset. -type CorruptInputError int64 -func (e CorruptInputError) String() string { - return "flate: corrupt input at 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 Read -} - -func (e *WriteError) String() string { - return "flate: write error at offset " + strconv.Itoa64(e.Offset) - + ": " + e.Error.String(); -} - -// Huffman decoder is based on -// J. Brian Connell, ``A Huffman-Shannon-Fano Code,'' -// Proceedings of the IEEE, 61(7) (July 1973), pp 1046-1047. -type huffmanDecoder struct { - // min, max code length - min, max int; - - // limit[i] = largest code word of length i - // Given code v of length n, - // need more bits if v > limit[n]. - limit [maxCodeLen+1]int; - - // base[i] = smallest code word of length i - seq number - base [maxCodeLen+1]int; - - // codes[seq number] = output code. - // Given code v of length n, value is - // codes[v - base[n]]. - codes []int; -} - -// Initialize Huffman decoding tables from array of code lengths. -func (h *huffmanDecoder) init(bits []int) bool { - // TODO(rsc): Return false sometimes. - - // Count number of codes of each length, - // compute min and max length. - var count [maxCodeLen+1]int; - var min, max int; - for i, 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 NewInflater. -// If the passed in io.Reader does not also have ReadByte, -// the NewInflater will introduce its own buffering. -type Reader interface { - io.Reader; - ReadByte() (c byte, err os.Error); -} - -// Inflate state. -// TODO(rsc): Expose this or not? -type inflater struct { - // Input/output sources. - r Reader; - w io.Writer; - roffset int64; - woffset int64; - - // Input bits, in top of b. - b uint32; - nb uint; - - // Huffman decoders for literal/length, distance. - h1, h2 huffmanDecoder; - - // Length arrays used to define Huffman codes. - bits [maxLit+maxDist]int; - codebits [numCodes]int; - - // Output history, buffer. - hist [maxHist]byte; - hp int; // current output position in buffer - hfull bool; // buffer has filled at least once - - // Temporary buffer (avoids repeated allocation). - buf [4]byte; -} - -// TODO(rsc): This works around a 6g bug. -func (f *inflater) getRoffset() int64 { - return f.roffset; -} - -func (f *inflater) dataBlock() os.Error -func (f *inflater) readHuffman() os.Error -func (f *inflater) decodeBlock(hl, hd *huffmanDecoder) os.Error -func (f *inflater) moreBits() os.Error -func (f *inflater) huffSym(h *huffmanDecoder) (int, os.Error) -func (f *inflater) flush() os.Error - -func (f *inflater) inflate() (err os.Error) { - final := false; - for err == nil && !final { - for f.nb < 1+2 { - if err = f.moreBits(); err != nil { - return; - } - } - final = f.b & 1 == 1; - f.b >>= 1; - typ := f.b & 3; - f.b >>= 2; - f.nb -= 1+2; - switch typ { - case 0: - err = f.dataBlock(); - case 1: - // compressed, fixed Huffman tables - err = f.decodeBlock(&fixedHuffmanDecoder, nil); - case 2: - // compressed, dynamic Huffman tables - if err = f.readHuffman(); err == nil { - err = f.decodeBlock(&f.h1, &f.h2); - } - default: - // 3 is reserved. - // TODO(rsc): Works around the same 6g bug. - var i int64 = f.getRoffset(); - i--; - err = CorruptInputError(i); - } - } - return; -} - -// RFC 1951 section 3.2.7. -// Compression with dynamic Huffman codes - -var codeOrder = [...]int { - 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 -} - -func (f *inflater) 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) { - return os.ErrorString("huff and puff"); - } - - // 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.getRoffset()); - } - 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; - f.nb -= nb; - if i+rep > n { - return CorruptInputError(f.getRoffset()); - } - 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.getRoffset()); - } - - 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 assocated with fixed Huffman blocks. -func (f *inflater) decodeBlock(hl, hd *huffmanDecoder) os.Error { - for { - v, err := f.huffSym(hl); - if err != nil { - return err; - } - var n uint; // number of bits extra - var length int; - switch { - case v < 256: - f.hist[f.hp] = byte(v); - f.hp++; - if f.hp == len(f.hist) { - if err = f.flush(); err != nil { - return err; - } - } - continue; - case v == 256: - return nil; - // otherwise, reference to older data - case v < 265: - length = v - (257 - 3); - n = 0; - case v < 269: - length = v*2 - (265*2 - 11); - n = 1; - case v < 273: - length = v*4 - (269*4 - 19); - n = 2; - case v < 277: - length = v*8 - (273*8 - 35); - n = 3; - case v < 281: - length = v*16 - (277*16 - 67); - n = 4; - case v < 285: - length = v*32 - (281*32 - 131); - n = 5; - default: - length = 258; - n = 0; - } - if n > 0 { - for f.nb < n { - if err = f.moreBits(); err != nil { - return err; - } - } - length += int(f.b & uint32(1<>= n; - f.nb -= n; - } - - var dist int; - if hd == nil { - for f.nb < 5 { - if err = f.moreBits(); err != nil { - return err; - } - } - dist = int(f.b & 0x1F); - f.b >>= 5; - f.nb -= 5; - } else { - if dist, err = f.huffSym(hd); err != nil { - return err; - } - } - - switch { - case dist < 4: - dist++; - case dist >= 30: - return CorruptInputError(f.getRoffset()); - default: - nb := uint(dist - 2) >> 1; - // have 1 bit in bottom of dist, need nb more. - extra := (dist&1) << nb; - for f.nb < nb { - if err = f.moreBits(); err != nil { - return err; - } - } - extra |= int(f.b & uint32(1<>= nb; - f.nb -= nb; - dist = 1<<(nb+1) + 1 + extra; - } - - // Copy history[-dist:-dist+length] into output. - if dist > len(f.hist) { - return InternalError("bad history distance"); - } - - // No check on length; encoding can be prescient. - if !f.hfull && dist > f.hp { - return CorruptInputError(f.getRoffset()); - } - - p := f.hp - dist; - if p < 0 { - p += len(f.hist); - } - for i := 0; i < length; i++ { - f.hist[f.hp] = f.hist[p]; - f.hp++; - p++; - if f.hp == len(f.hist) { - if err = f.flush(); err != nil { - return err; - } - } - if p == len(f.hist) { - p = 0; - } - } - } - panic("unreached"); -} - -// Copy a single uncompressed data block from input to output. -func (f *inflater) dataBlock() os.Error { - // Uncompressed. - // Discard current half-byte. - f.nb = 0; - f.b = 0; - - // Length then ones-complement of length. - nr, err := f.r.Read(f.buf[0:4]); - f.roffset += int64(nr); - if nr < 4 && err == nil { - err = io.ErrEOF; - } - if err != nil { - return &ReadError{f.roffset, err}; - } - n := int(f.buf[0]) | int(f.buf[1])<<8; - nn := int(f.buf[2]) | int(f.buf[3])<<8; - if nn != ^n { - return CorruptInputError(f.getRoffset()); - } - - // Read len bytes into history, - // writing as history fills. - for n > 0 { - m := len(f.hist) - f.hp; - if m > n { - m = n; - } - m, err := f.r.Read(f.hist[f.hp:f.hp+m]); - f.roffset += int64(m); - if m == 0 && err == nil { - err = io.ErrEOF; - } - if err != nil { - return &ReadError{f.roffset, err}; - } - n -= m; - f.hp += m; - if f.hp == len(f.hist) { - if err = f.flush(); err != nil { - return err; - } - } - } - return nil; -} - -func (f *inflater) moreBits() os.Error { - c, err := f.r.ReadByte(); - if err != nil { - 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 *inflater) 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<>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.getRoffset()); -} - -// Flush any buffered output to the underlying writer. -func (f *inflater) flush() os.Error { - if f.hp == 0 { - return nil; - } - n, err := f.w.Write(f.hist[0:f.hp]); - if n != f.hp && err == nil { - err = io.ErrShortWrite; - } - if err != nil { - return &WriteError{f.woffset, err}; - } - f.woffset += int64(f.hp); - f.hp = 0; - f.hfull = true; - return nil; -} - -func makeReader(r io.Reader) Reader { - if rr, ok := r.(Reader); ok { - return rr; - } - return bufio.NewReader(r); -} - -// Inflate reads DEFLATE-compressed data from r and writes -// the uncompressed data to w. -func (f *inflater) inflater(r io.Reader, w io.Writer) os.Error { - var ok bool; // TODO(rsc): why not := on next line? - f.r = makeReader(r); - f.w = w; - f.woffset = 0; - if err := f.inflate(); err != nil { - return err; - } - if err := f.flush(); err != nil { - return err; - } - return nil; -} - -// NewInflater 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 ReadClosed when -// finished reading. -func NewInflater(r io.Reader) io.ReadCloser { - var f inflater; - pr, pw := io.Pipe(); - go func() { - pw.CloseWithError(f.inflater(r, pw)); - }(); - return pr; -} diff --git a/src/lib/compress/gzip/Makefile b/src/lib/compress/gzip/Makefile deleted file mode 100644 index 514118ae0..000000000 --- a/src/lib/compress/gzip/Makefile +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m >Makefile - -D=/compress/ - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - gunzip.$O\ - - -phases: a1 -_obj$D/gzip.a: phases - -a1: $(O1) - $(AR) grc _obj$D/gzip.a gunzip.$O - rm -f $(O1) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/gzip.a - -$(O1): newpkg -$(O2): a1 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/gzip.a - -packages: _obj$D/gzip.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/gzip.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/gzip.a diff --git a/src/lib/compress/gzip/gunzip.go b/src/lib/compress/gzip/gunzip.go deleted file mode 100644 index 32cc3ecb0..000000000 --- a/src/lib/compress/gzip/gunzip.go +++ /dev/null @@ -1,236 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// The gzip package implements reading (and eventually writing) of -// gzip format compressed files, as specified in RFC 1952. -package gzip - -import ( - "bufio"; - "compress/flate"; - "hash"; - "hash/crc32"; - "io"; - "os"; -) - -const ( - gzipID1 = 0x1f; - gzipID2 = 0x8b; - - gzipDeflate = 8; - - flagText = 1<<0; - flagHdrCrc = 1<<1; - flagExtra = 1<<2; - flagName = 1<<3; - flagComment = 1<<4; -) - -func makeReader(r io.Reader) flate.Reader { - if rr, ok := r.(flate.Reader); ok { - return rr; - } - return bufio.NewReader(r); -} - -var HeaderError os.Error = os.ErrorString("invalid gzip header") -var ChecksumError os.Error = os.ErrorString("gzip checksum error") - -// A GzipInflater is an io.Reader that can be read to retrieve -// uncompressed data from a gzip-format compressed file. -// The gzip file stores a header giving metadata about the compressed file. -// That header is exposed as the fields of the GzipInflater struct. -// -// In general, a gzip file can be a concatenation of gzip files, -// each with its own header. Reads from the GzipInflater -// return the concatenation of the uncompressed data of each. -// Only the first header is recorded in the GzipInflater fields. -// -// Gzip files store a length and checksum of the uncompressed data. -// The GzipInflater 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 GzipInflater 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 - - r flate.Reader; - inflater io.Reader; - digest hash.Hash32; - size uint32; - flg byte; - buf [512]byte; - err os.Error; - eof bool; -} - -func (z *GzipInflater) readHeader(save bool) os.Error - -// NewGzipInflater creates a new GzipInflater reading the given reader. -// The implementation buffers input and may read more data than necessary from r. -func NewGzipInflater(r io.Reader) (*GzipInflater, os.Error) { - z := new(GzipInflater); - z.r = makeReader(r); - z.digest = crc32.NewIEEE(); - if err := z.readHeader(true); err != nil { - z.err = err; - return nil, err; - } - return z, nil; -} - -func get4(p []byte) uint32 { - return uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24; -} - -func (z *GzipInflater) 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 { - return string(z.buf[0:i]), nil; - } - } - panic("not reached"); -} - -func (z *GzipInflater) read2() (uint32, os.Error) { - _, err := z.r.Read(z.buf[0:2]); - if err != nil { - return 0, err; - } - return uint32(z.buf[0]) | uint32(z.buf[1])<<8, nil; -} - -func (z *GzipInflater) readHeader(save bool) os.Error { - n, err := io.FullRead(z.r, z.buf[0:10]); - if err != nil { - if n != 0 && err == io.ErrEOF { - return HeaderError; - } - 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); - var nn int; - if nn, err = io.FullRead(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.inflater = flate.NewInflater(z.r); - return nil; -} - -func (z *GzipInflater) Read(p []byte) (n int, err os.Error) { - if z.err != nil { - return 0, z.err; - } - if z.eof || len(p) == 0 { - return 0, nil; - } - - n, err = z.inflater.Read(p); - z.digest.Write(p[0:n]); - z.size += uint32(n); - if n != 0 || err != nil { - z.err = err; - return; - } - - // Finished file; check checksum + size. - if _, err := io.FullRead(z.r, z.buf[0:8]); err != nil { - z.err = err; - return 0, err; - } - if 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? - switch err = z.readHeader(false); { - case err == io.ErrEOF: - err = nil; - z.eof = true; - return; - case err != nil: - z.err = err; - return; - } - - // Yes. Reset and read from it. - z.digest.Reset(); - z.size = 0; - return z.Read(p); -} - diff --git a/src/lib/compress/gzip/gunzip_test.go b/src/lib/compress/gzip/gunzip_test.go deleted file mode 100644 index a481de927..000000000 --- a/src/lib/compress/gzip/gunzip_test.go +++ /dev/null @@ -1,268 +0,0 @@ -// Copyright 2009 The Go Authors. 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/gzip"; - "fmt"; - "io"; - "testing"; - "os"; -) - -type gzipTest struct { - name string; - raw string; - gzip []byte; - err os.Error; -} - -var gzipTests = []gzipTest { - gzipTest { // has 1 empty fixed-huffman block - "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 - }, - gzipTest { // has 1 non-empty fixed huffman block - "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 - }, - gzipTest { // concatenation - "hello.txt", - "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 - }, - gzipTest { // has dynamic huffman blocks - "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 - }, - gzipTest { // has 1 non-empty fixed huffman block then garbage - "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, 'g', 'a', 'r', 'b', 'a', 'g', 'e', '!', - }, - HeaderError, - }, - gzipTest { // has 1 non-empty fixed huffman block but corrupt checksum - "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, 0xff, 0xff, 0xff, 0xff, 0x0c, 0x00, - 0x00, 0x00, - }, - ChecksumError, - }, - gzipTest { // has 1 non-empty fixed huffman block but corrupt size - "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, 0xff, 0x00, - 0x00, 0x00, - }, - ChecksumError, - }, -} - -func TestGzipInflater(t *testing.T) { - b := new(io.ByteBuffer); - for i, tt := range gzipTests { - in := io.NewByteReader(tt.gzip); - gzip, err := NewGzipInflater(in); - if err != nil { - t.Errorf("%s: NewGzipInflater: %s", tt.name, err); - continue; - } - if tt.name != gzip.Name { - t.Errorf("%s: got name %s", tt.name, gzip.Name); - } - b.Reset(); - n, err := io.Copy(gzip, b); - if err != tt.err { - t.Errorf("%s: io.Copy: %s want %s", tt.name, err, tt.err); - } - s := string(b.Data()); - 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/lib/container/list/Makefile b/src/lib/container/list/Makefile deleted file mode 100644 index 2a647eb2a..000000000 --- a/src/lib/container/list/Makefile +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m >Makefile - -D=/container/ - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - list.$O\ - - -phases: a1 -_obj$D/list.a: phases - -a1: $(O1) - $(AR) grc _obj$D/list.a list.$O - rm -f $(O1) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/list.a - -$(O1): newpkg -$(O2): a1 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/list.a - -packages: _obj$D/list.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/list.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/list.a diff --git a/src/lib/container/list/list.go b/src/lib/container/list/list.go deleted file mode 100755 index 7e8daa65a..000000000 --- a/src/lib/container/list/list.go +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// The list package implements a doubly linked list. -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 contents of this list element. - Value interface {}; -} - -// List represents a doubly linked list. -type List struct { - front, back *Element; -} - -// Init initializes or clears a List. -func (l *List) Init() *List { - l.front = nil; - l.back = nil; - return l -} - -// New returns an initialized list. -func New() *List { - return new(List).Init() -} - -// 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. -func (l *List) Remove(e *Element) { - 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; -} - -func (l *List) insertFront(e *Element) { - e.prev = nil; - e.next = l.front; - l.front = e; - if e.next != nil { - e.next.prev = e; - } else { - l.back = e; - } -} - -func (l *List) insertBack(e *Element) { - e.next = nil; - e.prev = l.back; - l.back = e; - if e.prev != nil { - e.prev.next = e; - } else { - l.front = e; - } -} - -// PushFront inserts the value at the front of the list, and returns a new Element containing it. -func (l *List) PushFront(value interface {}) *Element { - e := &Element{ nil, nil, value }; - l.insertFront(e); - return e -} - -// PushBack inserts the value at the back of the list, and returns a new Element containing it. -func (l *List) PushBack(value interface {}) *Element { - e := &Element{ nil, nil, value }; - l.insertBack(e); - return e -} - -// MoveToFront moves the element to the front of the list. -func (l *List) MoveToFront(e *Element) { - if 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 l.back == e { - return - } - l.Remove(e); - l.insertBack(e); -} - -func (l *List) iterate(c chan <- *Element) { - var next *Element; - for e := l.front; e != nil; e = next { - // Save next in case reader of c changes e. - next = e.next; - c <- e; - } - close(c); -} - -func (l *List) Iter() <-chan *Element { - c := make(chan *Element); - go l.iterate(c); - return c -} diff --git a/src/lib/container/list/list_test.go b/src/lib/container/list/list_test.go deleted file mode 100755 index d5b2672e0..000000000 --- a/src/lib/container/list/list_test.go +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package list - -import ( - "container/list"; - "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 := 0; i < len(es); i++ { - e := es[i]; - 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 TestList(t *testing.T) { - l := New(); - checkListPointers(t, l, []*Element{}); - - // Single element list - e := l.PushFront("a"); - checkListPointers(t, l, []*Element{ e }); - l.MoveToFront(e); - checkListPointers(t, l, []*Element{ e }); - l.MoveToBack(e); - checkListPointers(t, l, []*Element{ e }); - l.Remove(e); - checkListPointers(t, l, []*Element{}); - - // 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 }); - - l.Remove(e2); - checkListPointers(t, l, []*Element{ e1, e3, e4 }); - - 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 }); - - // Clear all elements by iterating - for e := range l.Iter() { - l.Remove(e); - } - checkListPointers(t, l, []*Element{}); -} diff --git a/src/lib/container/vector/Makefile b/src/lib/container/vector/Makefile deleted file mode 100644 index 20490549d..000000000 --- a/src/lib/container/vector/Makefile +++ /dev/null @@ -1,69 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m >Makefile - -D=/container/ - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - vector.$O\ - -O2=\ - intvector.$O\ - stringvector.$O\ - - -phases: a1 a2 -_obj$D/vector.a: phases - -a1: $(O1) - $(AR) grc _obj$D/vector.a vector.$O - rm -f $(O1) - -a2: $(O2) - $(AR) grc _obj$D/vector.a intvector.$O stringvector.$O - rm -f $(O2) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/vector.a - -$(O1): newpkg -$(O2): a1 -$(O3): a2 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/vector.a - -packages: _obj$D/vector.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/vector.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/vector.a diff --git a/src/lib/container/vector/intvector.go b/src/lib/container/vector/intvector.go deleted file mode 100644 index c3b62f256..000000000 --- a/src/lib/container/vector/intvector.go +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2009 The Go Authors. 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 "container/vector" - -// IntVector is a specialization of Vector that hides the wrapping of Elements around ints. -type IntVector struct { - vector.Vector; -} - - -// Init initializes a new or resized vector. The initial length may be <= 0 to -// request a default length. If initial_len is shorter than the current -// length of the IntVector, trailing elements of the IntVector will be cleared. -func (p *IntVector) Init(len int) *IntVector { - p.Vector.Init(len); - return p; -} - - -// NewIntVector returns an initialized new IntVector with length at least len. -func NewIntVector(len int) *IntVector { - return new(IntVector).Init(len) -} - - -// At returns the i'th element of the vector. -func (p *IntVector) At(i int) int { - return p.Vector.At(i).(int) -} - - -// Set sets the i'th element of the vector to value x. -func (p *IntVector) Set(i int, x int) { - p.a[i] = x -} - - -// Last returns the element in the vector of highest index. -func (p *IntVector) Last() int { - return p.Vector.Last().(int) -} - - -// Data returns all the elements as a slice. -func (p *IntVector) Data() []int { - arr := make([]int, p.Len()); - for i, v := range p.a { - arr[i] = v.(int) - } - 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.Vector.Insert(i, x) -} - - -// 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) { - p.Vector.InsertVector(i, &x.Vector) -} - - -// Slice returns a new IntVector 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 { - return &IntVector{ *p.Vector.Slice(i, j) }; -} - - -// Push appends x to the end of the vector. -func (p *IntVector) Push(x int) { - p.Vector.Push(x) -} - - -// Pop deletes and returns the last element of the vector. -func (p *IntVector) Pop() int { - return p.Vector.Pop().(int) -} - - -// AppendVector appends the entire IntVector x to the end of this vector. -func (p *IntVector) AppendVector(x *IntVector) { - p.Vector.InsertVector(len(p.a), &x.Vector); -} - - -// SortInterface 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.At(i) < p.At(j) -} - - -// Iterate over all elements; driver for range -func (p *IntVector) iterate(c chan int) { - for i, v := range p.a { - c <- v.(int) - } - close(c); -} - - -// Channel iterator for range. -func (p *IntVector) Iter() chan int { - c := make(chan int); - go p.iterate(c); - return c; -} diff --git a/src/lib/container/vector/stringvector.go b/src/lib/container/vector/stringvector.go deleted file mode 100644 index 18ca11a3f..000000000 --- a/src/lib/container/vector/stringvector.go +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2009 The Go Authors. 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 "container/vector" - -// StringVector is a specialization of Vector that hides the wrapping of Elements around strings. -type StringVector struct { - vector.Vector; -} - - -// Init initializes a new or resized vector. The initial length may be <= 0 to -// request a default length. If initial_len is shorter than the current -// length of the StringVector, trailing elements of the StringVector will be cleared. -func (p *StringVector) Init(len int) *StringVector { - p.Vector.Init(len); - return p; -} - - -// NewStringVector returns an initialized new StringVector with length at least len. -func NewStringVector(len int) *StringVector { - return new(StringVector).Init(len) -} - - -// At returns the i'th element of the vector. -func (p *StringVector) At(i int) string { - return p.Vector.At(i).(string) -} - - -// Set sets the i'th element of the vector to value x. -func (p *StringVector) Set(i int, x string) { - p.a[i] = x -} - - -// Last returns the element in the vector of highest index. -func (p *StringVector) Last() string { - return p.Vector.Last().(string) -} - - -// Data returns all the elements as a slice. -func (p *StringVector) Data() []string { - arr := make([]string, p.Len()); - for i, v := range p.a { - arr[i] = v.(string) - } - 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.Vector.Insert(i, x) -} - - -// 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) { - p.Vector.InsertVector(i, &x.Vector) -} - - -// Slice returns a new StringVector 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 { - return &StringVector{ *p.Vector.Slice(i, j) }; -} - - -// Push appends x to the end of the vector. -func (p *StringVector) Push(x string) { - p.Vector.Push(x) -} - - -// Pop deletes and returns the last element of the vector. -func (p *StringVector) Pop() string { - return p.Vector.Pop().(string) -} - - -// AppendVector appends the entire StringVector x to the end of this vector. -func (p *StringVector) AppendVector(x *StringVector) { - p.Vector.InsertVector(len(p.a), &x.Vector); -} - - -// SortInterface support -// 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.At(i) < p.At(j) -} - - -// Iterate over all elements; driver for range -func (p *StringVector) iterate(c chan string) { - for i, v := range p.a { - c <- v.(string) - } - close(c); -} - - -// Channel iterator for range. -func (p *StringVector) Iter() chan string { - c := make(chan string); - go p.iterate(c); - return c; -} diff --git a/src/lib/container/vector/vector.go b/src/lib/container/vector/vector.go deleted file mode 100644 index 5b5cad21c..000000000 --- a/src/lib/container/vector/vector.go +++ /dev/null @@ -1,244 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// The vector package implements an efficient container for managing -// linear arrays of elements. Unlike arrays, vectors can change size dynamically. -package vector - -// Element is an empty-interface object representing the contents of -// a cell in the vector. -type Element interface {} - - -// Vector is the container itself. -type Vector struct { - a []Element -} - - -func copy(dst, src []Element) { - for i := 0; i < len(src); i++ { - dst[i] = src[i] - } -} - - -// Insert n elements at position i. -func expand(a []Element, i, n int) []Element { - // 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 - b := make([]Element, len1, capb); - copy(b, a); - a = b - } - - // make a hole - for j := len0-1; j >= i ; j-- { - a[j+n] = a[j] - } - return a -} - - -// Init initializes a new or resized vector. The initial_len may be <= 0 to -// request a default length. If initial_len is shorter than the current -// length of the Vector, trailing elements of the Vector will be cleared. -func (p *Vector) Init(initial_len int) *Vector { - a := p.a; - - if cap(a) == 0 || cap(a) < initial_len { - n := 8; // initial capacity - if initial_len > n { - n = initial_len - } - a = make([]Element, n); - } else { - // nil out entries - for j := len(a) - 1; j >= 0; j-- { - a[j] = nil - } - } - - p.a = a[0 : initial_len]; - return p -} - - -// New returns an initialized new Vector with length at least len. -func New(len int) *Vector { - return new(Vector).Init(len) -} - - -// Len returns the number of elements in the vector. -// Len is 0 if p == nil. -func (p *Vector) Len() int { - if p == nil { - return 0; - } - return len(p.a) -} - - -// At returns the i'th element of the vector. -func (p *Vector) At(i int) Element { - return p.a[i] -} - - -// Set sets the i'th element of the vector to value x. -func (p *Vector) Set(i int, x Element) { - p.a[i] = x -} - - -// Last returns the element in the vector of highest index. -func (p *Vector) Last() Element { - return p.a[len(p.a) - 1] -} - - -// Data returns all the elements as a slice. -func (p *Vector) Data() []Element { - arr := make([]Element, p.Len()); - for i, v := range p.a { - arr[i] = v - } - 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 Element) { - p.a = expand(p.a, i, 1); - p.a[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.a; - n := len(a); - - copy(a[i : n-1], a[i+1 : n]); - a[n-1] = nil; // support GC, nil out entry - p.a = 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) { - p.a = expand(p.a, i, len(x.a)); - copy(p.a[i : i + len(x.a)], x.a); -} - - -// Cut deletes elements i through j-1, inclusive. -func (p *Vector) Cut(i, j int) { - a := p.a; - n := len(a); - m := n - (j - i); - - copy(a[i : m], a[j : n]); - for k := m; k < n; k++ { - a[k] = nil // support GC, nil out entries - } - - p.a = a[0 : m]; -} - - -// Slice returns a new 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 { - s := New(j - i); // will fail in Init() if j < j - copy(s.a, p.a[i : j]); - return s; -} - - -// Do calls function f for each element of the vector, in order. -// The function should not change the indexing of the vector underfoot. -func (p *Vector) Do(f func(elem Element)) { - for i := 0; i < len(p.a); i++ { - f(p.a[i]) // not too safe if f changes the Vector - } -} - - -// Convenience wrappers - -// Push appends x to the end of the vector. -func (p *Vector) Push(x Element) { - p.Insert(len(p.a), x) -} - - -// Pop deletes the last element of the vector. -func (p *Vector) Pop() Element { - i := len(p.a) - 1; - x := p.a[i]; - p.a[i] = nil; // support GC, nil out entry - p.a = 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.a), x); -} - - -// Partial SortInterface support - -// LessInterface provides partial support of the SortInterface. -type LessInterface interface { - Less(y Element) 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.a[i].(LessInterface).Less(p.a[j]) -} - - -// Swap exchanges the elements at indexes i and j. -func (p *Vector) Swap(i, j int) { - a := p.a; - a[i], a[j] = a[j], a[i] -} - - -// Iterate over all elements; driver for range -func (p *Vector) iterate(c chan Element) { - for i, v := range p.a { - c <- v - } - close(c); -} - - -// Channel iterator for range. -func (p *Vector) Iter() chan Element { - c := make(chan Element); - go p.iterate(c); - return c; -} diff --git a/src/lib/container/vector/vector_test.go b/src/lib/container/vector/vector_test.go deleted file mode 100644 index 2a9819394..000000000 --- a/src/lib/container/vector/vector_test.go +++ /dev/null @@ -1,209 +0,0 @@ -// Copyright 2009 The Go Authors. 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 "container/vector" -import "testing" -import "sort" -import "fmt" - - -func TestZeroLen(t *testing.T) { - var a *vector.Vector; - if a.Len() != 0 { t.Errorf("A) expected 0, got %d", a.Len()); } - a = vector.New(0); - if a.Len() != 0 { t.Errorf("B) expected 0, got %d", a.Len()); } -} - - -func TestInit(t *testing.T) { - var a vector.Vector; - if a.Init(0).Len() != 0 { t.Error("A") } - if a.Init(1).Len() != 1 { t.Error("B") } - if a.Init(10).Len() != 10 { t.Error("C") } -} - - -func TestNew(t *testing.T) { - if vector.New(0).Len() != 0 { t.Error("A") } - if vector.New(1).Len() != 1 { t.Error("B") } - if vector.New(10).Len() != 10 { t.Error("C") } -} - - -func val(i int) int { - return i*991 - 1234 -} - - -func TestAccess(t *testing.T) { - const n = 100; - var a vector.Vector; - a.Init(n); - for i := 0; i < n; i++ { - a.Set(i, val(i)); - } - for i := 0; i < n; i++ { - if a.At(i).(int) != val(i) { t.Error(i) } - } -} - - -func TestInsertDeleteClear(t *testing.T) { - const n = 100; - a := vector.New(0); - - for i := 0; i < n; i++ { - if a.Len() != i { t.Errorf("A) wrong len %d (expected %d)", a.Len(), i) } - a.Insert(0, val(i)); - if a.Last().(int) != val(0) { t.Error("B") } - } - for i := n-1; i >= 0; i-- { - if a.Last().(int) != val(0) { t.Error("C") } - if a.At(0).(int) != val(i) { t.Error("D") } - a.Delete(0); - if a.Len() != i { t.Errorf("E) wrong len %d (expected %d)", a.Len(), i) } - } - - if a.Len() != 0 { t.Errorf("F) wrong len %d (expected 0)", a.Len()) } - for i := 0; i < n; i++ { - a.Push(val(i)); - if a.Len() != i+1 { t.Errorf("G) wrong len %d (expected %d)", a.Len(), i+1) } - if a.Last().(int) != val(i) { t.Error("H") } - } - a.Init(0); - if a.Len() != 0 { t.Errorf("I wrong len %d (expected 0)", a.Len()) } - - const m = 5; - for j := 0; j < m; j++ { - a.Push(j); - for i := 0; i < n; i++ { - x := val(i); - a.Push(x); - if a.Pop().(int) != x { t.Error("J") } - if a.Len() != j+1 { t.Errorf("K) wrong len %d (expected %d)", a.Len(), j+1) } - } - } - if a.Len() != m { t.Errorf("L) wrong len %d (expected %d)", a.Len(), m) } -} - - -func verify_slice(t *testing.T, x *vector.Vector, elt, i, j int) { - for k := i; k < j; k++ { - if x.At(k).(int) != elt { - t.Errorf("M) wrong [%d] element %d (expected %d)", k, x.At(k).(int), elt) - } - } - - s := x.Slice(i, j); - for k, n := 0, j-i; k < n; k++ { - if s.At(k).(int) != elt { - t.Errorf("N) wrong [%d] element %d (expected %d)", k, x.At(k).(int), elt) - } - } -} - - -func verify_pattern(t *testing.T, x *vector.Vector, a, b, c int) { - n := a + b + c; - if x.Len() != n { - t.Errorf("O) wrong len %d (expected %d)", x.Len(), 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.Vector { - x := vector.New(len); - for i := 0; i < len; i++ { - x.Set(i, 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); -} - - -// This also tests IntVector and StringVector -func TestSorting(t *testing.T) { - const n = 100; - - a := vector.NewIntVector(n); - for i := n-1; i >= 0; i-- { - a.Set(i, n-1-i); - } - if sort.IsSorted(a) { t.Error("int vector not sorted") } - - b := vector.NewStringVector(n); - 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 TestDo(t *testing.T) { - const n = 25; - const salt = 17; - a := vector.NewIntVector(n); - for i := 0; i < n; i++ { - a.Set(i, salt * i); - } - count := 0; - a.Do( - func(e vector.Element) { - i := e.(int); - if i != count*salt { - t.Error("value at", count, "should be", count*salt, "not", i) - } - count++; - } - ); - if count != n { - t.Error("should visit", n, "values; did visit", count) - } -} - -func TestIter(t *testing.T) { - const Len = 100; - x := vector.New(Len); - for i := 0; i < Len; i++ { - x.Set(i, i*i); - } - i := 0; - for v := range x.Iter() { - if v.(int) != i*i { - t.Error("Iter expected", i*i, "got", v.(int)) - } - i++; - } - if i != Len { - t.Error("Iter stopped at", i, "not", Len) - } -} diff --git a/src/lib/crypto/aes/Makefile b/src/lib/crypto/aes/Makefile deleted file mode 100644 index c62275b3c..000000000 --- a/src/lib/crypto/aes/Makefile +++ /dev/null @@ -1,76 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m >Makefile - -D=/crypto/ - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - const.$O\ - -O2=\ - block.$O\ - -O3=\ - cipher.$O\ - - -phases: a1 a2 a3 -_obj$D/aes.a: phases - -a1: $(O1) - $(AR) grc _obj$D/aes.a const.$O - rm -f $(O1) - -a2: $(O2) - $(AR) grc _obj$D/aes.a block.$O - rm -f $(O2) - -a3: $(O3) - $(AR) grc _obj$D/aes.a cipher.$O - rm -f $(O3) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/aes.a - -$(O1): newpkg -$(O2): a1 -$(O3): a2 -$(O4): a3 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/aes.a - -packages: _obj$D/aes.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/aes.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/aes.a diff --git a/src/lib/crypto/aes/aes_test.go b/src/lib/crypto/aes/aes_test.go deleted file mode 100644 index 2f6cb4a92..000000000 --- a/src/lib/crypto/aes/aes_test.go +++ /dev/null @@ -1,353 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package aes - -import ( - "crypto/aes"; - "fmt"; - "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<>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 { - 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, - }, - }, - KeyTest { - // A.2. Expansion of a 192-bit Cipher Key - []byte { - 0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5, - 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, - }, - KeyTest { - // A.3. Expansion of a 256-bit Cipher Key - []byte { - 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, - 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 { - CryptTest { - // Appendix B. - []byte { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c, }, - []byte { 0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d, 0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34, }, - []byte { 0x39, 0x25, 0x84, 0x1d, 0x02, 0xdc, 0x09, 0xfb, 0xdc, 0x11, 0x85, 0x97, 0x19, 0x6a, 0x0b, 0x32, }, - }, - CryptTest { - // Appendix C.1. AES-128 - []byte { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, }, - []byte { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, }, - []byte { 0x69, 0xc4, 0xe0, 0xd8, 0x6a, 0x7b, 0x04, 0x30, 0xd8, 0xcd, 0xb7, 0x80, 0x70, 0xb4, 0xc5, 0x5a, }, - }, - CryptTest { - // Appendix C.2. AES-192 - []byte { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, }, - []byte { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, }, - []byte { 0xdd, 0xa9, 0x7c, 0xa4, 0x86, 0x4c, 0xdf, 0xe0, 0x6e, 0xaf, 0x70, 0xa0, 0xec, 0x0d, 0x71, 0x91, }, - }, - CryptTest { - // Appendix C.3. AES-256 - []byte { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, }, - []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, tt.in, out); - 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, tt.out, plain); - 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(tt.in, out); - 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(tt.out, plain); - 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/lib/crypto/aes/block.go b/src/lib/crypto/aes/block.go deleted file mode 100644 index 3c67d1c3c..000000000 --- a/src/lib/crypto/aes/block.go +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright 2009 The Go 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 -// @author Antoon Bosselaers -// @author Paulo Barreto -// -// 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 - -import "crypto/aes" - -// Encrypt one block from src into dst, using the expanded key xk. -func encryptBlock(xk []uint32, src, dst []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, src, dst []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/lib/crypto/aes/cipher.go b/src/lib/crypto/aes/cipher.go deleted file mode 100644 index fd8e43e16..000000000 --- a/src/lib/crypto/aes/cipher.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package aes - -import ( - "crypto/aes"; - "os"; -) - -// 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; -} - -// 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) { - switch len(key) { - default: - return nil, os.ErrorString("crypto/aes: invalid key size"); - case 16, 24, 32: - break; - } - - n := len(key) + 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 Key interface in the -// package "crypto/modes". -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 AESCBC (see modes.go). -func (c *Cipher) Encrypt(src, dst []byte) { - encryptBlock(c.enc, src, dst); -} - -// Decrypt decrypts the 16-byte buffer src using the key k -// and stores the result in dst. -func (c *Cipher) Decrypt(src, dst []byte) { - decryptBlock(c.dec, src, dst); -} - -// 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/lib/crypto/aes/const.go b/src/lib/crypto/aes/const.go deleted file mode 100644 index 9167d602d..000000000 --- a/src/lib/crypto/aes/const.go +++ /dev/null @@ -1,363 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// AES constants - 8720 bytes of initialized data. - -// This package implements AES encryption (formerly Rijndael), -// as defined in U.S. Federal Information Processing Standards Publication 197. -package aes - -// http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf - -// AES is based on the mathematical behavior of binary polynomials -// (polynomials over GF(2)) modulo the irreducible polynomial x⁸ + x⁴ + x² + x + 1. -// Addition of these binary polynomials corresponds to binary xor. -// Reducing mod poly corresponds to binary xor with poly every -// time a 0x100 bit appears. -const poly = 1<<8 | 1<<4 | 1<<3 | 1<<1 | 1<<0; // x⁸ + x⁴ + x² + x + 1 - -// Powers of x mod poly in GF(2). -var powx = [16]byte{ - 0x01, - 0x02, - 0x04, - 0x08, - 0x10, - 0x20, - 0x40, - 0x80, - 0x1b, - 0x36, - 0x6c, - 0xd8, - 0xab, - 0x4d, - 0x9a, - 0x2f, -} - -// FIPS-197 Figure 7. S-box substitution values in hexadecimal format. -var sbox0 = [256]byte { - 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, - 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, - 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, - 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, - 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, - 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, - 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, - 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, - 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, - 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, - 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, - 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, - 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, - 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, - 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, - 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16, -} - -// FIPS-197 Figure 14. Inverse S-box substitution values in hexadecimal format. -var sbox1 = [256]byte { - 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, - 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, - 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, - 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, - 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, - 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, - 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, - 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, - 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, - 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, - 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, - 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, - 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, - 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, - 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, - 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d, -} - -// Lookup tables for encryption. -// These can be recomputed by adapting the tests in aes_test.go. - -var te = [4][256]uint32 { - [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, - }, - [256]uint32 { - 0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b, 0x0dfff2f2, 0xbdd66b6b, 0xb1de6f6f, 0x5491c5c5, - 0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b, 0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676, - 0x458fcaca, 0x9d1f8282, 0x4089c9c9, 0x87fa7d7d, 0x15effafa, 0xebb25959, 0xc98e4747, 0x0bfbf0f0, - 0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf, 0xbf239c9c, 0xf753a4a4, 0x96e47272, 0x5b9bc0c0, - 0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626, 0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc, - 0x5c683434, 0xf451a5a5, 0x34d1e5e5, 0x08f9f1f1, 0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515, - 0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3, 0x28301818, 0xa1379696, 0x0f0a0505, 0xb52f9a9a, - 0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2, 0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575, - 0x1b120909, 0x9e1d8383, 0x74582c2c, 0x2e341a1a, 0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0, - 0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3, 0x7b522929, 0x3edde3e3, 0x715e2f2f, 0x97138484, - 0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded, 0x60402020, 0x1fe3fcfc, 0xc879b1b1, 0xedb65b5b, - 0xbed46a6a, 0x468dcbcb, 0xd967bebe, 0x4b723939, 0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf, - 0x6bbbd0d0, 0x2ac5efef, 0xe54faaaa, 0x16edfbfb, 0xc5864343, 0xd79a4d4d, 0x55663333, 0x94118585, - 0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f, 0xf0a05050, 0x44783c3c, 0xba259f9f, 0xe34ba8a8, - 0xf3a25151, 0xfe5da3a3, 0xc0804040, 0x8a058f8f, 0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5, - 0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121, 0x30201010, 0x1ae5ffff, 0x0efdf3f3, 0x6dbfd2d2, - 0x4c81cdcd, 0x14180c0c, 0x35261313, 0x2fc3ecec, 0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717, - 0x5793c4c4, 0xf255a7a7, 0x82fc7e7e, 0x477a3d3d, 0xacc86464, 0xe7ba5d5d, 0x2b321919, 0x95e67373, - 0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc, 0x66442222, 0x7e542a2a, 0xab3b9090, 0x830b8888, - 0xca8c4646, 0x29c7eeee, 0xd36bb8b8, 0x3c281414, 0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb, - 0x3bdbe0e0, 0x56643232, 0x4e743a3a, 0x1e140a0a, 0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c, - 0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262, 0xa8399191, 0xa4319595, 0x37d3e4e4, 0x8bf27979, - 0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d, 0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9, - 0xb4d86c6c, 0xfaac5656, 0x07f3f4f4, 0x25cfeaea, 0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808, - 0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e, 0x24381c1c, 0xf157a6a6, 0xc773b4b4, 0x5197c6c6, - 0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f, 0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a, - 0x90e07070, 0x427c3e3e, 0xc471b5b5, 0xaacc6666, 0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e, - 0xa3c26161, 0x5f6a3535, 0xf9ae5757, 0xd069b9b9, 0x91178686, 0x5899c1c1, 0x273a1d1d, 0xb9279e9e, - 0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111, 0xbbd26969, 0x70a9d9d9, 0x89078e8e, 0xa7339494, - 0xb62d9b9b, 0x223c1e1e, 0x92158787, 0x20c9e9e9, 0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf, - 0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d, 0xda65bfbf, 0x31d7e6e6, 0xc6844242, 0xb8d06868, - 0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f, 0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616, - }, - [256]uint32 { - 0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b, 0xf20dfff2, 0x6bbdd66b, 0x6fb1de6f, 0xc55491c5, - 0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b, 0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76, - 0xca458fca, 0x829d1f82, 0xc94089c9, 0x7d87fa7d, 0xfa15effa, 0x59ebb259, 0x47c98e47, 0xf00bfbf0, - 0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af, 0x9cbf239c, 0xa4f753a4, 0x7296e472, 0xc05b9bc0, - 0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26, 0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc, - 0x345c6834, 0xa5f451a5, 0xe534d1e5, 0xf108f9f1, 0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15, - 0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3, 0x18283018, 0x96a13796, 0x050f0a05, 0x9ab52f9a, - 0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2, 0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75, - 0x091b1209, 0x839e1d83, 0x2c74582c, 0x1a2e341a, 0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0, - 0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3, 0x297b5229, 0xe33edde3, 0x2f715e2f, 0x84971384, - 0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed, 0x20604020, 0xfc1fe3fc, 0xb1c879b1, 0x5bedb65b, - 0x6abed46a, 0xcb468dcb, 0xbed967be, 0x394b7239, 0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf, - 0xd06bbbd0, 0xef2ac5ef, 0xaae54faa, 0xfb16edfb, 0x43c58643, 0x4dd79a4d, 0x33556633, 0x85941185, - 0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f, 0x50f0a050, 0x3c44783c, 0x9fba259f, 0xa8e34ba8, - 0x51f3a251, 0xa3fe5da3, 0x40c08040, 0x8f8a058f, 0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5, - 0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221, 0x10302010, 0xff1ae5ff, 0xf30efdf3, 0xd26dbfd2, - 0xcd4c81cd, 0x0c14180c, 0x13352613, 0xec2fc3ec, 0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17, - 0xc45793c4, 0xa7f255a7, 0x7e82fc7e, 0x3d477a3d, 0x64acc864, 0x5de7ba5d, 0x192b3219, 0x7395e673, - 0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc, 0x22664422, 0x2a7e542a, 0x90ab3b90, 0x88830b88, - 0x46ca8c46, 0xee29c7ee, 0xb8d36bb8, 0x143c2814, 0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb, - 0xe03bdbe0, 0x32566432, 0x3a4e743a, 0x0a1e140a, 0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c, - 0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462, 0x91a83991, 0x95a43195, 0xe437d3e4, 0x798bf279, - 0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d, 0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9, - 0x6cb4d86c, 0x56faac56, 0xf407f3f4, 0xea25cfea, 0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008, - 0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e, 0x1c24381c, 0xa6f157a6, 0xb4c773b4, 0xc65197c6, - 0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f, 0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a, - 0x7090e070, 0x3e427c3e, 0xb5c471b5, 0x66aacc66, 0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e, - 0x61a3c261, 0x355f6a35, 0x57f9ae57, 0xb9d069b9, 0x86911786, 0xc15899c1, 0x1d273a1d, 0x9eb9279e, - 0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211, 0x69bbd269, 0xd970a9d9, 0x8e89078e, 0x94a73394, - 0x9bb62d9b, 0x1e223c1e, 0x87921587, 0xe920c9e9, 0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df, - 0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d, 0xbfda65bf, 0xe631d7e6, 0x42c68442, 0x68b8d068, - 0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f, 0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16, - }, - [256]uint32 { - 0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6, 0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491, - 0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56, 0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec, - 0xcaca458f, 0x82829d1f, 0xc9c94089, 0x7d7d87fa, 0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb, - 0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45, 0x9c9cbf23, 0xa4a4f753, 0x727296e4, 0xc0c05b9b, - 0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c, 0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83, - 0x34345c68, 0xa5a5f451, 0xe5e534d1, 0xf1f108f9, 0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a, - 0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d, 0x18182830, 0x9696a137, 0x05050f0a, 0x9a9ab52f, - 0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf, 0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea, - 0x09091b12, 0x83839e1d, 0x2c2c7458, 0x1a1a2e34, 0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b, - 0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d, 0x29297b52, 0xe3e33edd, 0x2f2f715e, 0x84849713, - 0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1, 0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6, - 0x6a6abed4, 0xcbcb468d, 0xbebed967, 0x39394b72, 0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85, - 0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed, 0x4343c586, 0x4d4dd79a, 0x33335566, 0x85859411, - 0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe, 0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b, - 0x5151f3a2, 0xa3a3fe5d, 0x4040c080, 0x8f8f8a05, 0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1, - 0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342, 0x10103020, 0xffff1ae5, 0xf3f30efd, 0xd2d26dbf, - 0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3, 0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e, - 0xc4c45793, 0xa7a7f255, 0x7e7e82fc, 0x3d3d477a, 0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6, - 0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3, 0x22226644, 0x2a2a7e54, 0x9090ab3b, 0x8888830b, - 0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28, 0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad, - 0xe0e03bdb, 0x32325664, 0x3a3a4e74, 0x0a0a1e14, 0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8, - 0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4, 0x9191a839, 0x9595a431, 0xe4e437d3, 0x79798bf2, - 0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da, 0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049, - 0x6c6cb4d8, 0x5656faac, 0xf4f407f3, 0xeaea25cf, 0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810, - 0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c, 0x1c1c2438, 0xa6a6f157, 0xb4b4c773, 0xc6c65197, - 0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e, 0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f, - 0x707090e0, 0x3e3e427c, 0xb5b5c471, 0x6666aacc, 0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c, - 0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069, 0x86869117, 0xc1c15899, 0x1d1d273a, 0x9e9eb927, - 0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322, 0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733, - 0x9b9bb62d, 0x1e1e223c, 0x87879215, 0xe9e920c9, 0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5, - 0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a, 0xbfbfda65, 0xe6e631d7, 0x4242c684, 0x6868b8d0, - 0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e, 0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c, - }, -} - -// Lookup tables for decryption. -// These can be recomputed by adapting the tests in aes_test.go. - -var td = [4][256]uint32 { - [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, - }, - [256]uint32 { - 0x5051f4a7, 0x537e4165, 0xc31a17a4, 0x963a275e, 0xcb3bab6b, 0xf11f9d45, 0xabacfa58, 0x934be303, - 0x552030fa, 0xf6ad766d, 0x9188cc76, 0x25f5024c, 0xfc4fe5d7, 0xd7c52acb, 0x80263544, 0x8fb562a3, - 0x49deb15a, 0x6725ba1b, 0x9845ea0e, 0xe15dfec0, 0x02c32f75, 0x12814cf0, 0xa38d4697, 0xc66bd3f9, - 0xe7038f5f, 0x9515929c, 0xebbf6d7a, 0xda955259, 0x2dd4be83, 0xd3587421, 0x2949e069, 0x448ec9c8, - 0x6a75c289, 0x78f48e79, 0x6b99583e, 0xdd27b971, 0xb6bee14f, 0x17f088ad, 0x66c920ac, 0xb47dce3a, - 0x1863df4a, 0x82e51a31, 0x60975133, 0x4562537f, 0xe0b16477, 0x84bb6bae, 0x1cfe81a0, 0x94f9082b, - 0x58704868, 0x198f45fd, 0x8794de6c, 0xb7527bf8, 0x23ab73d3, 0xe2724b02, 0x57e31f8f, 0x2a6655ab, - 0x07b2eb28, 0x032fb5c2, 0x9a86c57b, 0xa5d33708, 0xf2302887, 0xb223bfa5, 0xba02036a, 0x5ced1682, - 0x2b8acf1c, 0x92a779b4, 0xf0f307f2, 0xa14e69e2, 0xcd65daf4, 0xd50605be, 0x1fd13462, 0x8ac4a6fe, - 0x9d342e53, 0xa0a2f355, 0x32058ae1, 0x75a4f6eb, 0x390b83ec, 0xaa4060ef, 0x065e719f, 0x51bd6e10, - 0xf93e218a, 0x3d96dd06, 0xaedd3e05, 0x464de6bd, 0xb591548d, 0x0571c45d, 0x6f0406d4, 0xff605015, - 0x241998fb, 0x97d6bde9, 0xcc894043, 0x7767d99e, 0xbdb0e842, 0x8807898b, 0x38e7195b, 0xdb79c8ee, - 0x47a17c0a, 0xe97c420f, 0xc9f8841e, 0x00000000, 0x83098086, 0x48322bed, 0xac1e1170, 0x4e6c5a72, - 0xfbfd0eff, 0x560f8538, 0x1e3daed5, 0x27362d39, 0x640a0fd9, 0x21685ca6, 0xd19b5b54, 0x3a24362e, - 0xb10c0a67, 0x0f9357e7, 0xd2b4ee96, 0x9e1b9b91, 0x4f80c0c5, 0xa261dc20, 0x695a774b, 0x161c121a, - 0x0ae293ba, 0xe5c0a02a, 0x433c22e0, 0x1d121b17, 0x0b0e090d, 0xadf28bc7, 0xb92db6a8, 0xc8141ea9, - 0x8557f119, 0x4caf7507, 0xbbee99dd, 0xfda37f60, 0x9ff70126, 0xbc5c72f5, 0xc544663b, 0x345bfb7e, - 0x768b4329, 0xdccb23c6, 0x68b6edfc, 0x63b8e4f1, 0xcad731dc, 0x10426385, 0x40139722, 0x2084c611, - 0x7d854a24, 0xf8d2bb3d, 0x11aef932, 0x6dc729a1, 0x4b1d9e2f, 0xf3dcb230, 0xec0d8652, 0xd077c1e3, - 0x6c2bb316, 0x99a970b9, 0xfa119448, 0x2247e964, 0xc4a8fc8c, 0x1aa0f03f, 0xd8567d2c, 0xef223390, - 0xc787494e, 0xc1d938d1, 0xfe8ccaa2, 0x3698d40b, 0xcfa6f581, 0x28a57ade, 0x26dab78e, 0xa43fadbf, - 0xe42c3a9d, 0x0d507892, 0x9b6a5fcc, 0x62547e46, 0xc2f68d13, 0xe890d8b8, 0x5e2e39f7, 0xf582c3af, - 0xbe9f5d80, 0x7c69d093, 0xa96fd52d, 0xb3cf2512, 0x3bc8ac99, 0xa710187d, 0x6ee89c63, 0x7bdb3bbb, - 0x09cd2678, 0xf46e5918, 0x01ec9ab7, 0xa8834f9a, 0x65e6956e, 0x7eaaffe6, 0x0821bccf, 0xe6ef15e8, - 0xd9bae79b, 0xce4a6f36, 0xd4ea9f09, 0xd629b07c, 0xaf31a4b2, 0x312a3f23, 0x30c6a594, 0xc035a266, - 0x37744ebc, 0xa6fc82ca, 0xb0e090d0, 0x1533a7d8, 0x4af10498, 0xf741ecda, 0x0e7fcd50, 0x2f1791f6, - 0x8d764dd6, 0x4d43efb0, 0x54ccaa4d, 0xdfe49604, 0xe39ed1b5, 0x1b4c6a88, 0xb8c12c1f, 0x7f466551, - 0x049d5eea, 0x5d018c35, 0x73fa8774, 0x2efb0b41, 0x5ab3671d, 0x5292dbd2, 0x33e91056, 0x136dd647, - 0x8c9ad761, 0x7a37a10c, 0x8e59f814, 0x89eb133c, 0xeecea927, 0x35b761c9, 0xede11ce5, 0x3c7a47b1, - 0x599cd2df, 0x3f55f273, 0x791814ce, 0xbf73c737, 0xea53f7cd, 0x5b5ffdaa, 0x14df3d6f, 0x867844db, - 0x81caaff3, 0x3eb968c4, 0x2c382434, 0x5fc2a340, 0x72161dc3, 0x0cbce225, 0x8b283c49, 0x41ff0d95, - 0x7139a801, 0xde080cb3, 0x9cd8b4e4, 0x906456c1, 0x617bcb84, 0x70d532b6, 0x74486c5c, 0x42d0b857, - }, - [256]uint32 { - 0xa75051f4, 0x65537e41, 0xa4c31a17, 0x5e963a27, 0x6bcb3bab, 0x45f11f9d, 0x58abacfa, 0x03934be3, - 0xfa552030, 0x6df6ad76, 0x769188cc, 0x4c25f502, 0xd7fc4fe5, 0xcbd7c52a, 0x44802635, 0xa38fb562, - 0x5a49deb1, 0x1b6725ba, 0x0e9845ea, 0xc0e15dfe, 0x7502c32f, 0xf012814c, 0x97a38d46, 0xf9c66bd3, - 0x5fe7038f, 0x9c951592, 0x7aebbf6d, 0x59da9552, 0x832dd4be, 0x21d35874, 0x692949e0, 0xc8448ec9, - 0x896a75c2, 0x7978f48e, 0x3e6b9958, 0x71dd27b9, 0x4fb6bee1, 0xad17f088, 0xac66c920, 0x3ab47dce, - 0x4a1863df, 0x3182e51a, 0x33609751, 0x7f456253, 0x77e0b164, 0xae84bb6b, 0xa01cfe81, 0x2b94f908, - 0x68587048, 0xfd198f45, 0x6c8794de, 0xf8b7527b, 0xd323ab73, 0x02e2724b, 0x8f57e31f, 0xab2a6655, - 0x2807b2eb, 0xc2032fb5, 0x7b9a86c5, 0x08a5d337, 0x87f23028, 0xa5b223bf, 0x6aba0203, 0x825ced16, - 0x1c2b8acf, 0xb492a779, 0xf2f0f307, 0xe2a14e69, 0xf4cd65da, 0xbed50605, 0x621fd134, 0xfe8ac4a6, - 0x539d342e, 0x55a0a2f3, 0xe132058a, 0xeb75a4f6, 0xec390b83, 0xefaa4060, 0x9f065e71, 0x1051bd6e, - 0x8af93e21, 0x063d96dd, 0x05aedd3e, 0xbd464de6, 0x8db59154, 0x5d0571c4, 0xd46f0406, 0x15ff6050, - 0xfb241998, 0xe997d6bd, 0x43cc8940, 0x9e7767d9, 0x42bdb0e8, 0x8b880789, 0x5b38e719, 0xeedb79c8, - 0x0a47a17c, 0x0fe97c42, 0x1ec9f884, 0x00000000, 0x86830980, 0xed48322b, 0x70ac1e11, 0x724e6c5a, - 0xfffbfd0e, 0x38560f85, 0xd51e3dae, 0x3927362d, 0xd9640a0f, 0xa621685c, 0x54d19b5b, 0x2e3a2436, - 0x67b10c0a, 0xe70f9357, 0x96d2b4ee, 0x919e1b9b, 0xc54f80c0, 0x20a261dc, 0x4b695a77, 0x1a161c12, - 0xba0ae293, 0x2ae5c0a0, 0xe0433c22, 0x171d121b, 0x0d0b0e09, 0xc7adf28b, 0xa8b92db6, 0xa9c8141e, - 0x198557f1, 0x074caf75, 0xddbbee99, 0x60fda37f, 0x269ff701, 0xf5bc5c72, 0x3bc54466, 0x7e345bfb, - 0x29768b43, 0xc6dccb23, 0xfc68b6ed, 0xf163b8e4, 0xdccad731, 0x85104263, 0x22401397, 0x112084c6, - 0x247d854a, 0x3df8d2bb, 0x3211aef9, 0xa16dc729, 0x2f4b1d9e, 0x30f3dcb2, 0x52ec0d86, 0xe3d077c1, - 0x166c2bb3, 0xb999a970, 0x48fa1194, 0x642247e9, 0x8cc4a8fc, 0x3f1aa0f0, 0x2cd8567d, 0x90ef2233, - 0x4ec78749, 0xd1c1d938, 0xa2fe8cca, 0x0b3698d4, 0x81cfa6f5, 0xde28a57a, 0x8e26dab7, 0xbfa43fad, - 0x9de42c3a, 0x920d5078, 0xcc9b6a5f, 0x4662547e, 0x13c2f68d, 0xb8e890d8, 0xf75e2e39, 0xaff582c3, - 0x80be9f5d, 0x937c69d0, 0x2da96fd5, 0x12b3cf25, 0x993bc8ac, 0x7da71018, 0x636ee89c, 0xbb7bdb3b, - 0x7809cd26, 0x18f46e59, 0xb701ec9a, 0x9aa8834f, 0x6e65e695, 0xe67eaaff, 0xcf0821bc, 0xe8e6ef15, - 0x9bd9bae7, 0x36ce4a6f, 0x09d4ea9f, 0x7cd629b0, 0xb2af31a4, 0x23312a3f, 0x9430c6a5, 0x66c035a2, - 0xbc37744e, 0xcaa6fc82, 0xd0b0e090, 0xd81533a7, 0x984af104, 0xdaf741ec, 0x500e7fcd, 0xf62f1791, - 0xd68d764d, 0xb04d43ef, 0x4d54ccaa, 0x04dfe496, 0xb5e39ed1, 0x881b4c6a, 0x1fb8c12c, 0x517f4665, - 0xea049d5e, 0x355d018c, 0x7473fa87, 0x412efb0b, 0x1d5ab367, 0xd25292db, 0x5633e910, 0x47136dd6, - 0x618c9ad7, 0x0c7a37a1, 0x148e59f8, 0x3c89eb13, 0x27eecea9, 0xc935b761, 0xe5ede11c, 0xb13c7a47, - 0xdf599cd2, 0x733f55f2, 0xce791814, 0x37bf73c7, 0xcdea53f7, 0xaa5b5ffd, 0x6f14df3d, 0xdb867844, - 0xf381caaf, 0xc43eb968, 0x342c3824, 0x405fc2a3, 0xc372161d, 0x250cbce2, 0x498b283c, 0x9541ff0d, - 0x017139a8, 0xb3de080c, 0xe49cd8b4, 0xc1906456, 0x84617bcb, 0xb670d532, 0x5c74486c, 0x5742d0b8, - }, - [256]uint32 { - 0xf4a75051, 0x4165537e, 0x17a4c31a, 0x275e963a, 0xab6bcb3b, 0x9d45f11f, 0xfa58abac, 0xe303934b, - 0x30fa5520, 0x766df6ad, 0xcc769188, 0x024c25f5, 0xe5d7fc4f, 0x2acbd7c5, 0x35448026, 0x62a38fb5, - 0xb15a49de, 0xba1b6725, 0xea0e9845, 0xfec0e15d, 0x2f7502c3, 0x4cf01281, 0x4697a38d, 0xd3f9c66b, - 0x8f5fe703, 0x929c9515, 0x6d7aebbf, 0x5259da95, 0xbe832dd4, 0x7421d358, 0xe0692949, 0xc9c8448e, - 0xc2896a75, 0x8e7978f4, 0x583e6b99, 0xb971dd27, 0xe14fb6be, 0x88ad17f0, 0x20ac66c9, 0xce3ab47d, - 0xdf4a1863, 0x1a3182e5, 0x51336097, 0x537f4562, 0x6477e0b1, 0x6bae84bb, 0x81a01cfe, 0x082b94f9, - 0x48685870, 0x45fd198f, 0xde6c8794, 0x7bf8b752, 0x73d323ab, 0x4b02e272, 0x1f8f57e3, 0x55ab2a66, - 0xeb2807b2, 0xb5c2032f, 0xc57b9a86, 0x3708a5d3, 0x2887f230, 0xbfa5b223, 0x036aba02, 0x16825ced, - 0xcf1c2b8a, 0x79b492a7, 0x07f2f0f3, 0x69e2a14e, 0xdaf4cd65, 0x05bed506, 0x34621fd1, 0xa6fe8ac4, - 0x2e539d34, 0xf355a0a2, 0x8ae13205, 0xf6eb75a4, 0x83ec390b, 0x60efaa40, 0x719f065e, 0x6e1051bd, - 0x218af93e, 0xdd063d96, 0x3e05aedd, 0xe6bd464d, 0x548db591, 0xc45d0571, 0x06d46f04, 0x5015ff60, - 0x98fb2419, 0xbde997d6, 0x4043cc89, 0xd99e7767, 0xe842bdb0, 0x898b8807, 0x195b38e7, 0xc8eedb79, - 0x7c0a47a1, 0x420fe97c, 0x841ec9f8, 0x00000000, 0x80868309, 0x2bed4832, 0x1170ac1e, 0x5a724e6c, - 0x0efffbfd, 0x8538560f, 0xaed51e3d, 0x2d392736, 0x0fd9640a, 0x5ca62168, 0x5b54d19b, 0x362e3a24, - 0x0a67b10c, 0x57e70f93, 0xee96d2b4, 0x9b919e1b, 0xc0c54f80, 0xdc20a261, 0x774b695a, 0x121a161c, - 0x93ba0ae2, 0xa02ae5c0, 0x22e0433c, 0x1b171d12, 0x090d0b0e, 0x8bc7adf2, 0xb6a8b92d, 0x1ea9c814, - 0xf1198557, 0x75074caf, 0x99ddbbee, 0x7f60fda3, 0x01269ff7, 0x72f5bc5c, 0x663bc544, 0xfb7e345b, - 0x4329768b, 0x23c6dccb, 0xedfc68b6, 0xe4f163b8, 0x31dccad7, 0x63851042, 0x97224013, 0xc6112084, - 0x4a247d85, 0xbb3df8d2, 0xf93211ae, 0x29a16dc7, 0x9e2f4b1d, 0xb230f3dc, 0x8652ec0d, 0xc1e3d077, - 0xb3166c2b, 0x70b999a9, 0x9448fa11, 0xe9642247, 0xfc8cc4a8, 0xf03f1aa0, 0x7d2cd856, 0x3390ef22, - 0x494ec787, 0x38d1c1d9, 0xcaa2fe8c, 0xd40b3698, 0xf581cfa6, 0x7ade28a5, 0xb78e26da, 0xadbfa43f, - 0x3a9de42c, 0x78920d50, 0x5fcc9b6a, 0x7e466254, 0x8d13c2f6, 0xd8b8e890, 0x39f75e2e, 0xc3aff582, - 0x5d80be9f, 0xd0937c69, 0xd52da96f, 0x2512b3cf, 0xac993bc8, 0x187da710, 0x9c636ee8, 0x3bbb7bdb, - 0x267809cd, 0x5918f46e, 0x9ab701ec, 0x4f9aa883, 0x956e65e6, 0xffe67eaa, 0xbccf0821, 0x15e8e6ef, - 0xe79bd9ba, 0x6f36ce4a, 0x9f09d4ea, 0xb07cd629, 0xa4b2af31, 0x3f23312a, 0xa59430c6, 0xa266c035, - 0x4ebc3774, 0x82caa6fc, 0x90d0b0e0, 0xa7d81533, 0x04984af1, 0xecdaf741, 0xcd500e7f, 0x91f62f17, - 0x4dd68d76, 0xefb04d43, 0xaa4d54cc, 0x9604dfe4, 0xd1b5e39e, 0x6a881b4c, 0x2c1fb8c1, 0x65517f46, - 0x5eea049d, 0x8c355d01, 0x877473fa, 0x0b412efb, 0x671d5ab3, 0xdbd25292, 0x105633e9, 0xd647136d, - 0xd7618c9a, 0xa10c7a37, 0xf8148e59, 0x133c89eb, 0xa927eece, 0x61c935b7, 0x1ce5ede1, 0x47b13c7a, - 0xd2df599c, 0xf2733f55, 0x14ce7918, 0xc737bf73, 0xf7cdea53, 0xfdaa5b5f, 0x3d6f14df, 0x44db8678, - 0xaff381ca, 0x68c43eb9, 0x24342c38, 0xa3405fc2, 0x1dc37216, 0xe2250cbc, 0x3c498b28, 0x0d9541ff, - 0xa8017139, 0x0cb3de08, 0xb4e49cd8, 0x56c19064, 0xcb84617b, 0x32b670d5, 0x6c5c7448, 0xb85742d0, - }, -} - diff --git a/src/lib/crypto/block/Makefile b/src/lib/crypto/block/Makefile deleted file mode 100644 index e8bc8e907..000000000 --- a/src/lib/crypto/block/Makefile +++ /dev/null @@ -1,82 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m >Makefile - -D=/crypto/ - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - cipher.$O\ - xor.$O\ - -O2=\ - cmac.$O\ - ctr.$O\ - ecb.$O\ - ofb.$O\ - -O3=\ - cbc.$O\ - cfb.$O\ - eax.$O\ - - -phases: a1 a2 a3 -_obj$D/block.a: phases - -a1: $(O1) - $(AR) grc _obj$D/block.a cipher.$O xor.$O - rm -f $(O1) - -a2: $(O2) - $(AR) grc _obj$D/block.a cmac.$O ctr.$O ecb.$O ofb.$O - rm -f $(O2) - -a3: $(O3) - $(AR) grc _obj$D/block.a cbc.$O cfb.$O eax.$O - rm -f $(O3) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/block.a - -$(O1): newpkg -$(O2): a1 -$(O3): a2 -$(O4): a3 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/block.a - -packages: _obj$D/block.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/block.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/block.a diff --git a/src/lib/crypto/block/cbc.go b/src/lib/crypto/block/cbc.go deleted file mode 100644 index 85a746b72..000000000 --- a/src/lib/crypto/block/cbc.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Cipher block chaining (CBC) mode. - -// CBC provides confidentiality by xoring (chaining) each plaintext block -// with the previous ciphertext block before applying the block cipher. - -// See NIST SP 800-38A, pp 10-11 - -package block - -import ( - "crypto/block"; - "io"; -) - -type cbcCipher struct { - c Cipher; - blockSize int; - iv []byte; - tmp []byte; -} - -func newCBC(c Cipher, iv []byte) *cbcCipher { - n := c.BlockSize(); - x := new(cbcCipher); - x.c = c; - x.blockSize = n; - x.iv = copy(iv); - x.tmp = make([]byte, n); - return x; -} - -func (x *cbcCipher) BlockSize() int { - return x.blockSize; -} - -func (x *cbcCipher) Encrypt(src, dst []byte) { - for i := 0; i < x.blockSize; i++ { - x.iv[i] ^= src[i]; - } - x.c.Encrypt(x.iv, x.iv); - for i := 0; i < x.blockSize; i++ { - dst[i] = x.iv[i]; - } -} - -func (x *cbcCipher) Decrypt(src, dst []byte) { - x.c.Decrypt(src, x.tmp); - for i := 0; i < x.blockSize; i++ { - x.tmp[i] ^= x.iv[i]; - x.iv[i] = src[i]; - dst[i] = x.tmp[i]; - } -} - -// NewCBCDecrypter returns a reader that reads data from r and decrypts it using c -// in cipher block chaining (CBC) mode with the initialization vector iv. -// The returned Reader does not buffer or read ahead except -// as required by the cipher's block size. -func NewCBCDecrypter(c Cipher, iv []byte, r io.Reader) io.Reader { - return NewECBDecrypter(newCBC(c, iv), r); -} - -// NewCBCEncrypter returns a writer that encrypts data using c -// in cipher block chaining (CBC) mode with the initialization vector iv -// and writes the encrypted data to w. -// The returned Writer does no buffering except as required -// by the cipher's block size, so there is no need for a Flush method. -func NewCBCEncrypter(c Cipher, iv []byte, w io.Writer) io.Writer { - return NewECBEncrypter(newCBC(c, iv), w); -} - diff --git a/src/lib/crypto/block/cbc_aes_test.go b/src/lib/crypto/block/cbc_aes_test.go deleted file mode 100644 index 4681c1c07..000000000 --- a/src/lib/crypto/block/cbc_aes_test.go +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 2009 The Go 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 block - -// gobuild: $GC ecb_aes_test.go - -import ( - "crypto/aes"; - "crypto/block"; - "io"; - "os"; - "testing"; - - "./ecb_aes_test"; -) - -type cbcTest struct { - name string; - key []byte; - iv []byte; - in []byte; - out []byte; -} - -var cbcAESTests = []cbcTest { - // NIST SP 800-38A pp 27-29 - cbcTest { - "CBC-AES128", - commonKey128, - commonIV, - 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, - }, - }, - cbcTest { - "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, - }, - }, - cbcTest { - "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 i, 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; - } - - var crypt io.ByteBuffer; - w := NewCBCEncrypter(c, tt.iv, &crypt); - var r io.Reader = io.NewByteReader(tt.in); - n, err := io.Copy(r, w); - if n != int64(len(tt.in)) || err != nil { - t.Errorf("%s: CBCEncrypter io.Copy = %d, %v want %d, nil", test, n, err, len(tt.in)); - } else if d := crypt.Data(); !same(tt.out, d) { - t.Errorf("%s: CBCEncrypter\nhave %x\nwant %x", test, d, tt.out); - } - - var plain io.ByteBuffer; - r = NewCBCDecrypter(c, tt.iv, io.NewByteReader(tt.out)); - w = &plain; - n, err = io.Copy(r, w); - if n != int64(len(tt.out)) || err != nil { - t.Errorf("%s: CBCDecrypter io.Copy = %d, %v want %d, nil", test, n, err, len(tt.out)); - } else if d := plain.Data(); !same(tt.in, d) { - t.Errorf("%s: CBCDecrypter\nhave %x\nwant %x", test, d, tt.in); - } - - if t.Failed() { - break; - } - } -} diff --git a/src/lib/crypto/block/cfb.go b/src/lib/crypto/block/cfb.go deleted file mode 100644 index 5c4c09a1b..000000000 --- a/src/lib/crypto/block/cfb.go +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Cipher feedback (CFB) mode. - -// CFB provides confidentiality by feeding a fraction of -// the previous ciphertext in as the plaintext for the next -// block operation. - -// See NIST SP 800-38A, pp 11-13 - -package block - -import ( - "crypto/block"; - "io"; -) - -type cfbCipher struct { - c Cipher; - blockSize int; // our block size (s/8) - cipherSize int; // underlying cipher block size - iv []byte; - tmp []byte; -} - -func newCFB(c Cipher, s int, iv []byte) *cfbCipher { - if s == 0 || s % 8 != 0 { - panicln("crypto/block: invalid CFB mode", s); - } - b := c.BlockSize(); - x := new(cfbCipher); - x.c = c; - x.blockSize = s/8; - x.cipherSize = b; - x.iv = copy(iv); - x.tmp = make([]byte, b); - return x; -} - -func (x *cfbCipher) BlockSize() int { - return x.blockSize; -} - -func (x *cfbCipher) Encrypt(src, dst []byte) { - // Encrypt old IV and xor prefix with src to make dst. - x.c.Encrypt(x.iv, x.tmp); - for i := 0; i < x.blockSize; i++ { - dst[i] = src[i] ^ x.tmp[i]; - } - - // Slide unused IV pieces down and insert dst at end. - for i := 0; i < x.cipherSize - x.blockSize; i++ { - x.iv[i] = x.iv[i + x.blockSize]; - } - off := x.cipherSize - x.blockSize; - for i := off; i < x.cipherSize; i++ { - x.iv[i] = dst[i - off]; - } -} - -func (x *cfbCipher) Decrypt(src, dst []byte) { - // Encrypt [sic] old IV and xor prefix with src to make dst. - x.c.Encrypt(x.iv, x.tmp); - for i := 0; i < x.blockSize; i++ { - dst[i] = src[i] ^ x.tmp[i]; - } - - // Slide unused IV pieces down and insert src at top. - for i := 0; i < x.cipherSize - x.blockSize; i++ { - x.iv[i] = x.iv[i + x.blockSize]; - } - off := x.cipherSize - x.blockSize; - for i := off; i < x.cipherSize; i++ { - // Reconstruct src = dst ^ x.tmp - // in case we overwrote src (src == dst). - x.iv[i] = dst[i - off] ^ x.tmp[i - off]; - } -} - -// NewCFBDecrypter returns a reader that reads data from r and decrypts it using c -// in s-bit cipher feedback (CFB) mode with the initialization vector iv. -// The returned Reader does not buffer or read ahead except -// as required by the cipher's block size. -// Modes for s not a multiple of 8 are unimplemented. -func NewCFBDecrypter(c Cipher, s int, iv []byte, r io.Reader) io.Reader { - return NewECBDecrypter(newCFB(c, s, iv), r); -} - -// NewCFBEncrypter returns a writer that encrypts data using c -// in s-bit cipher feedback (CFB) mode with the initialization vector iv -// and writes the encrypted data to w. -// The returned Writer does no buffering except as required -// by the cipher's block size, so there is no need for a Flush method. -// Modes for s not a multiple of 8 are unimplemented. -func NewCFBEncrypter(c Cipher, s int, iv []byte, w io.Writer) io.Writer { - return NewECBEncrypter(newCFB(c, s, iv), w); -} - diff --git a/src/lib/crypto/block/cfb_aes_test.go b/src/lib/crypto/block/cfb_aes_test.go deleted file mode 100644 index 6c793dba8..000000000 --- a/src/lib/crypto/block/cfb_aes_test.go +++ /dev/null @@ -1,316 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// CFB AES test vectors. - -// See U.S. National Institute of Standards and Technology (NIST) -// Special Publication 800-38A, ``Recommendation for Block Cipher -// Modes of Operation,'' 2001 Edition, pp. 29-52. - -package block - -// gobuild: $GC ecb_aes_test.go - -import ( - "crypto/aes"; - "crypto/block"; - "io"; - "os"; - "testing"; - - "./ecb_aes_test"; -) - -type cfbTest struct { - name string; - s int; - key []byte; - iv []byte; - in []byte; - out []byte; -} - -var cfbAESTests = []cfbTest { - cfbTest { - "CFB1-AES128", - 1, - commonKey128, - commonIV, - []byte{ - 0<<7 | 1<<6 | 1<<5 | 0<<4 | 1<<3 | 0<<2 | 1<<1, - 1<<7 | 1<<6 | 0<<5 | 0<<4 | 0<<3 | 0<<2 | 0<<1, - }, - []byte{ - 0<<7 | 1<<6 | 1<<5 | 0<<4 | 1<<3 | 0<<2 | 0<<1, - 1<<7 | 0<<6 | 1<<5 | 1<<4 | 0<<3 | 0<<2 | 1<<1, - }, - }, - cfbTest { - "CFB1-AES192", - 1, - commonKey192, - commonIV, - []byte{ - 0<<7 | 1<<6 | 1<<5 | 0<<4 | 1<<3 | 0<<2 | 1<<1, - 1<<7 | 1<<6 | 0<<5 | 0<<4 | 0<<3 | 0<<2 | 0<<1, - }, - []byte{ - 1<<7 | 0<<6 | 0<<5 | 1<<4 | 0<<3 | 0<<2 | 1<<1, - 0<<7 | 1<<6 | 0<<5 | 1<<4 | 1<<3 | 0<<2 | 0<<1, - }, - }, - cfbTest { - "CFB1-AES256", - 1, - commonKey256, - commonIV, - []byte{ - 0<<7 | 1<<6 | 1<<5 | 0<<4 | 1<<3 | 0<<2 | 1<<1, - 1<<7 | 1<<6 | 0<<5 | 0<<4 | 0<<3 | 0<<2 | 0<<1, - }, - []byte{ - 1<<7 | 0<<6 | 0<<5 | 1<<4 | 0<<3 | 0<<2 | 0<<1, - 0<<7 | 0<<6 | 1<<5 | 0<<4 | 1<<3 | 0<<2 | 0<<1, - }, - }, - - cfbTest { - "CFB8-AES128", - 8, - commonKey128, - commonIV, - []byte{ - 0x6b, - 0xc1, - 0xbe, - 0xe2, - 0x2e, - 0x40, - 0x9f, - 0x96, - 0xe9, - 0x3d, - 0x7e, - 0x11, - 0x73, - 0x93, - 0x17, - 0x2a, - 0xae, - 0x2d, - }, - []byte{ - 0x3b, - 0x79, - 0x42, - 0x4c, - 0x9c, - 0x0d, - 0xd4, - 0x36, - 0xba, - 0xce, - 0x9e, - 0x0e, - 0xd4, - 0x58, - 0x6a, - 0x4f, - 0x32, - 0xb9, - }, - }, - - cfbTest { - "CFB8-AES192", - 8, - commonKey192, - commonIV, - []byte{ - 0x6b, - 0xc1, - 0xbe, - 0xe2, - 0x2e, - 0x40, - 0x9f, - 0x96, - 0xe9, - 0x3d, - 0x7e, - 0x11, - 0x73, - 0x93, - 0x17, - 0x2a, - 0xae, - 0x2d, - }, - []byte{ - 0xcd, - 0xa2, - 0x52, - 0x1e, - 0xf0, - 0xa9, - 0x05, - 0xca, - 0x44, - 0xcd, - 0x05, - 0x7c, - 0xbf, - 0x0d, - 0x47, - 0xa0, - 0x67, - 0x8a, - }, - }, - - cfbTest { - "CFB8-AES256", - 8, - commonKey256, - commonIV, - []byte{ - 0x6b, - 0xc1, - 0xbe, - 0xe2, - 0x2e, - 0x40, - 0x9f, - 0x96, - 0xe9, - 0x3d, - 0x7e, - 0x11, - 0x73, - 0x93, - 0x17, - 0x2a, - 0xae, - 0x2d, - }, - []byte{ - 0xdc, - 0x1f, - 0x1a, - 0x85, - 0x20, - 0xa6, - 0x4d, - 0xb5, - 0x5f, - 0xcc, - 0x8a, - 0xc5, - 0x54, - 0x84, - 0x4e, - 0x88, - 0x97, - 0x00, - }, - }, - - cfbTest { - "CFB128-AES128", - 128, - commonKey128, - commonIV, - []byte{ - 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, - 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, - 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, - 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10, - }, - []byte{ - 0x3b, 0x3f, 0xd9, 0x2e, 0xb7, 0x2d, 0xad, 0x20, 0x33, 0x34, 0x49, 0xf8, 0xe8, 0x3c, 0xfb, 0x4a, - 0xc8, 0xa6, 0x45, 0x37, 0xa0, 0xb3, 0xa9, 0x3f, 0xcd, 0xe3, 0xcd, 0xad, 0x9f, 0x1c, 0xe5, 0x8b, - 0x26, 0x75, 0x1f, 0x67, 0xa3, 0xcb, 0xb1, 0x40, 0xb1, 0x80, 0x8c, 0xf1, 0x87, 0xa4, 0xf4, 0xdf, - 0xc0, 0x4b, 0x05, 0x35, 0x7c, 0x5d, 0x1c, 0x0e, 0xea, 0xc4, 0xc6, 0x6f, 0x9f, 0xf7, 0xf2, 0xe6, - }, - }, - - cfbTest { - "CFB128-AES192", - 128, - commonKey192, - commonIV, - []byte{ - 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, - 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, - 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, - 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10, - }, - []byte{ - 0xcd, 0xc8, 0x0d, 0x6f, 0xdd, 0xf1, 0x8c, 0xab, 0x34, 0xc2, 0x59, 0x09, 0xc9, 0x9a, 0x41, 0x74, - 0x67, 0xce, 0x7f, 0x7f, 0x81, 0x17, 0x36, 0x21, 0x96, 0x1a, 0x2b, 0x70, 0x17, 0x1d, 0x3d, 0x7a, - 0x2e, 0x1e, 0x8a, 0x1d, 0xd5, 0x9b, 0x88, 0xb1, 0xc8, 0xe6, 0x0f, 0xed, 0x1e, 0xfa, 0xc4, 0xc9, - 0xc0, 0x5f, 0x9f, 0x9c, 0xa9, 0x83, 0x4f, 0xa0, 0x42, 0xae, 0x8f, 0xba, 0x58, 0x4b, 0x09, 0xff, - }, - }, - - cfbTest { - "CFB128-AES256", - 128, - commonKey256, - commonIV, - []byte{ - 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, - 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, - 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, - 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10, - }, - []byte{ - 0xdc, 0x7e, 0x84, 0xbf, 0xda, 0x79, 0x16, 0x4b, 0x7e, 0xcd, 0x84, 0x86, 0x98, 0x5d, 0x38, 0x60, - 0x39, 0xff, 0xed, 0x14, 0x3b, 0x28, 0xb1, 0xc8, 0x32, 0x11, 0x3c, 0x63, 0x31, 0xe5, 0x40, 0x7b, - 0xdf, 0x10, 0x13, 0x24, 0x15, 0xe5, 0x4b, 0x92, 0xa1, 0x3e, 0xd0, 0xa8, 0x26, 0x7a, 0xe2, 0xf9, - 0x75, 0xa3, 0x85, 0x74, 0x1a, 0xb9, 0xce, 0xf8, 0x20, 0x31, 0x62, 0x3d, 0x55, 0xb1, 0xe4, 0x71, - }, - }, -} - -func TestCFB_AES(t *testing.T) { - for i, tt := range cfbAESTests { - test := tt.name; - - if tt.s == 1 { - // 1-bit CFB not implemented - continue; - } - - c, err := aes.NewCipher(tt.key); - if err != nil { - t.Errorf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err); - continue; - } - - var crypt io.ByteBuffer; - w := NewCFBEncrypter(c, tt.s, tt.iv, &crypt); - var r io.Reader = io.NewByteReader(tt.in); - n, err := io.Copy(r, w); - if n != int64(len(tt.in)) || err != nil { - t.Errorf("%s: CFBEncrypter io.Copy = %d, %v want %d, nil", test, n, err, len(tt.in)); - } else if d := crypt.Data(); !same(tt.out, d) { - t.Errorf("%s: CFBEncrypter\nhave %x\nwant %x", test, d, tt.out); - } - - var plain io.ByteBuffer; - r = NewCFBDecrypter(c, tt.s, tt.iv, io.NewByteReader(tt.out)); - w = &plain; - n, err = io.Copy(r, w); - if n != int64(len(tt.out)) || err != nil { - t.Errorf("%s: CFBDecrypter io.Copy = %d, %v want %d, nil", test, n, err, len(tt.out)); - } else if d := plain.Data(); !same(tt.in, d) { - t.Errorf("%s: CFBDecrypter\nhave %x\nwant %x", test, d, tt.in); - } - - if t.Failed() { - break; - } - } -} diff --git a/src/lib/crypto/block/cipher.go b/src/lib/crypto/block/cipher.go deleted file mode 100644 index 7ea035db9..000000000 --- a/src/lib/crypto/block/cipher.go +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// The block package implements standard block cipher modes -// that can be wrapped around low-level block cipher implementations. -// See http://csrc.nist.gov/groups/ST/toolkit/BCM/current_modes.html -// and NIST Special Publication 800-38A. -package block - -import "io"; - -// A Cipher represents an implementation of block cipher -// using a given key. It provides the capability to encrypt -// or decrypt individual blocks. The mode implementations -// extend that capability to streams of blocks. -type Cipher interface { - // BlockSize returns the cipher's block size. - BlockSize() int; - - // Encrypt encrypts the first block in src into dst. - // Src and dst may point at the same memory. - Encrypt(src, dst []byte); - - // Decrypt decrypts the first block in src into dst. - // Src and dst may point at the same memory. - Decrypt(src, dst []byte); -} - -// TODO(rsc): Digest belongs elsewhere. - -// A Digest is an implementation of a message digest algorithm. -// Write data to it and then call Sum to retreive the digest. -// Calling Reset resets the internal state, as though no data has -// been written. -type Digest interface { - io.Writer; - Sum() []byte; - Reset(); -} - - - -// Utility routines - -func shift1(src, dst []byte) byte { - var b byte; - for i := len(src)-1; i >= 0; i-- { - bb := src[i]>>7; - dst[i] = src[i]<<1 | b; - b = bb; - } - return b; -} - -func same(p, q []byte) bool { - if len(p) != len(q) { - return false; - } - for i := 0; i < len(p); i++ { - if p[i] != q[i] { - return false; - } - } - return true; -} - -func copy(p []byte) []byte { - q := make([]byte, len(p)); - for i, b := range p { - q[i] = b; - } - return q; -} diff --git a/src/lib/crypto/block/cmac.go b/src/lib/crypto/block/cmac.go deleted file mode 100644 index 40697cabd..000000000 --- a/src/lib/crypto/block/cmac.go +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// CMAC message authentication code, defined in -// NIST Special Publication SP 800-38B. - -package block - -import ( - "crypto/block"; - "io"; - "os"; -) - -const ( - // minimal irreducible polynomial of degree b - r64 = 0x1b; - r128 = 0x87; -) - -type cmac struct { - k1, k2, ci, digest []byte; - p int; // position in ci - c Cipher; -} - -// TODO(rsc): Should this return an error instead of panic? - -// NewCMAC returns a new instance of a CMAC message authentication code -// digest using the given Cipher. -func NewCMAC(c Cipher) Digest { - var r byte; - n := c.BlockSize(); - switch n { - case 64/8: - r = r64; - case 128/8: - r = r128; - default: - panic("crypto/block: NewCMAC: invalid cipher block size", n); - } - - d := new(cmac); - d.c = c; - d.k1 = make([]byte, n); - d.k2 = make([]byte, n); - d.ci = make([]byte, n); - d.digest = make([]byte, n); - - // Subkey generation, p. 7 - c.Encrypt(d.k1, d.k1); - if shift1(d.k1, d.k1) != 0 { - d.k1[n-1] ^= r; - } - if shift1(d.k1, d.k2) != 0 { - d.k2[n-1] ^= r; - } - - return d; -} - -// Reset clears the digest state, starting a new digest. -func (d *cmac) Reset() { - for i := range d.ci { - d.ci[i] = 0; - } - d.p = 0; -} - -// Write adds the given data to the digest state. -func (d *cmac) Write(p []byte) (n int, err os.Error) { - // Xor input into ci. - for i, c := range p { - // If ci is full, encrypt and start over. - if d.p >= len(d.ci) { - d.c.Encrypt(d.ci, d.ci); - d.p = 0; - } - d.ci[d.p] ^= c; - d.p++; - } - return len(p), nil; -} - -// Sum returns the CMAC digest, one cipher block in length, -// of the data written with Write. -func (d *cmac) Sum() []byte { - // Finish last block, mix in key, encrypt. - // Don't edit ci, in case caller wants - // to keep digesting after call to Sum. - k := d.k1; - if d.p < len(d.digest) { - k = d.k2; - } - for i := 0; i < len(d.ci); i++ { - d.digest[i] = d.ci[i] ^ k[i]; - } - if d.p < len(d.digest) { - d.digest[d.p] ^= 0x80; - } - d.c.Encrypt(d.digest, d.digest); - return d.digest; -} - diff --git a/src/lib/crypto/block/cmac_aes_test.go b/src/lib/crypto/block/cmac_aes_test.go deleted file mode 100644 index 9284ac40a..000000000 --- a/src/lib/crypto/block/cmac_aes_test.go +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// CMAC test vectors. See NIST SP 800-38B, Appendix D. - -package block - -// gobuild: $GC ecb_aes_test.go - -import ( - "crypto/aes"; - "crypto/block"; - "testing"; - - "./ecb_aes_test"; -) - -type cmacAESTest struct { - key []byte; - in []byte; - digest []byte; -} - -var cmacAESTests = []cmacAESTest { - cmacAESTest { - commonKey128, - nil, - []byte { - 0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28, 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46, - } - }, - cmacAESTest { - commonKey128, - []byte { - 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, - }, - []byte { - 0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44, 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c, - } - }, - cmacAESTest { - commonKey128, - []byte { - 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, - 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, - 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, - }, - []byte { - 0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30, 0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27, - } - }, - cmacAESTest { - commonKey128, - []byte { - 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, - 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, - 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, - 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10, - }, - []byte { - 0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92, 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe, - } - }, - cmacAESTest { - commonKey192, - nil, - []byte { - 0xd1, 0x7d, 0xdf, 0x46, 0xad, 0xaa, 0xcd, 0xe5, 0x31, 0xca, 0xc4, 0x83, 0xde, 0x7a, 0x93, 0x67, - } - }, - cmacAESTest { - commonKey192, - []byte { - 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, - }, - []byte { - 0x9e, 0x99, 0xa7, 0xbf, 0x31, 0xe7, 0x10, 0x90, 0x06, 0x62, 0xf6, 0x5e, 0x61, 0x7c, 0x51, 0x84, - } - }, - cmacAESTest { - commonKey192, - []byte { - 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, - 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, - 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, - }, - []byte { - 0x8a, 0x1d, 0xe5, 0xbe, 0x2e, 0xb3, 0x1a, 0xad, 0x08, 0x9a, 0x82, 0xe6, 0xee, 0x90, 0x8b, 0x0e, - } - }, - cmacAESTest { - commonKey192, - []byte { - 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, - 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, - 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, - 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10, - }, - []byte { - 0xa1, 0xd5, 0xdf, 0x0e, 0xed, 0x79, 0x0f, 0x79, 0x4d, 0x77, 0x58, 0x96, 0x59, 0xf3, 0x9a, 0x11, - } - }, - cmacAESTest { - commonKey256, - nil, - []byte { - 0x02, 0x89, 0x62, 0xf6, 0x1b, 0x7b, 0xf8, 0x9e, 0xfc, 0x6b, 0x55, 0x1f, 0x46, 0x67, 0xd9, 0x83, - } - }, - cmacAESTest { - commonKey256, - []byte { - 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, - }, - []byte { - 0x28, 0xa7, 0x02, 0x3f, 0x45, 0x2e, 0x8f, 0x82, 0xbd, 0x4b, 0xf2, 0x8d, 0x8c, 0x37, 0xc3, 0x5c, - } - }, - cmacAESTest { - commonKey256, - []byte { - 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, - 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, - 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, - }, - []byte { - 0xaa, 0xf3, 0xd8, 0xf1, 0xde, 0x56, 0x40, 0xc2, 0x32, 0xf5, 0xb1, 0x69, 0xb9, 0xc9, 0x11, 0xe6, - } - }, - cmacAESTest { - commonKey256, - []byte { - 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, - 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, - 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, - 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10, - }, - []byte { - 0xe1, 0x99, 0x21, 0x90, 0x54, 0x9f, 0x6e, 0xd5, 0x69, 0x6a, 0x2c, 0x05, 0x6c, 0x31, 0x54, 0x10, - } - } -} - -func TestCMAC_AES(t *testing.T) { - for i, tt := range cmacAESTests { - c, err := aes.NewCipher(tt.key); - if err != nil { - t.Errorf("test %d: NewCipher: %s", i, err); - continue; - } - d := NewCMAC(c); - n, err := d.Write(tt.in); - if err != nil || n != len(tt.in) { - t.Errorf("test %d: Write %d: %d, %s", i, len(tt.in), n, err); - continue; - } - sum := d.Sum(); - if !same(sum, tt.digest) { - x := d.(*cmac); - t.Errorf("test %d: digest mismatch\n\twant %x\n\thave %x\n\tk1 %x\n\tk2 %x", i, tt.digest, sum, x.k1, x.k2); - continue; - } - } -} diff --git a/src/lib/crypto/block/ctr.go b/src/lib/crypto/block/ctr.go deleted file mode 100644 index eecb615ad..000000000 --- a/src/lib/crypto/block/ctr.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Counter (CTR) mode. - -// CTR converts a block cipher into a stream cipher by -// repeatedly encrypting an incrementing counter and -// xoring the resulting stream of data with the input. - -// See NIST SP 800-38A, pp 13-15 - -package block - -import ( - "crypto/block"; - "io"; -) - -type ctrStream struct { - c Cipher; - ctr []byte; - out []byte; -} - -func newCTRStream(c Cipher, ctr []byte) *ctrStream { - x := new(ctrStream); - x.c = c; - x.ctr = copy(ctr); - x.out = make([]byte, len(ctr)); - return x; -} - -func (x *ctrStream) Next() []byte { - // Next block is encryption of counter. - x.c.Encrypt(x.ctr, x.out); - - // Increment counter - for i := len(x.ctr) - 1; i >= 0; i-- { - x.ctr[i]++; - if x.ctr[i] != 0 { - break; - } - } - - return x.out; -} - -// NewCTRReader returns a reader that reads data from r, decrypts (or encrypts) -// it using c in counter (CTR) mode with the initialization vector iv. -// The returned Reader does not buffer and has no block size. -// In CTR mode, encryption and decryption are the same operation: -// a CTR reader applied to an encrypted stream produces a decrypted -// stream and vice versa. -func NewCTRReader(c Cipher, iv []byte, r io.Reader) io.Reader { - return newXorReader(newCTRStream(c, iv), r); -} - -// NewCTRWriter returns a writer that encrypts (or decrypts) data using c -// in counter (CTR) mode with the initialization vector iv -// and writes the encrypted data to w. -// The returned Writer does not buffer and has no block size. -// In CTR mode, encryption and decryption are the same operation: -// a CTR writer applied to an decrypted stream produces an encrypted -// stream and vice versa. -func NewCTRWriter(c Cipher, iv []byte, w io.Writer) io.Writer { - return newXorWriter(newCTRStream(c, iv), w); -} - diff --git a/src/lib/crypto/block/ctr_aes_test.go b/src/lib/crypto/block/ctr_aes_test.go deleted file mode 100644 index a3da1b5bf..000000000 --- a/src/lib/crypto/block/ctr_aes_test.go +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright 2009 The Go 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 block - -import ( - "crypto/aes"; - "crypto/block"; - "io"; - "os"; - "testing"; - - "./ecb_aes_test"; -) - -type ctrTest struct { - name string; - key []byte; - iv []byte; - in []byte; - out []byte; -} - -var commonCounter = []byte { - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, -} - -var ctrAESTests = []ctrTest { - // NIST SP 800-38A pp 55-58 - ctrTest { - "CTR-AES128", - commonKey128, - commonCounter, - 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, - }, - }, - ctrTest { - "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, - }, - }, - ctrTest { - "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 i, 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 { - var crypt io.ByteBuffer; - in := tt.in[0:len(tt.in) - j]; - w := block.NewCTRWriter(c, tt.iv, &crypt); - var r io.Reader = io.NewByteReader(in); - n, err := io.Copy(r, w); - if n != int64(len(in)) || err != nil { - t.Errorf("%s/%d: CTRWriter io.Copy = %d, %v want %d, nil", test, len(in), n, err, len(in)); - } else if d, out := crypt.Data(), tt.out[0:len(in)]; !same(out, d) { - t.Errorf("%s/%d: CTRWriter\ninpt %x\nhave %x\nwant %x", test, len(in), in, d, out); - } - } - - for j := 0; j <= 7; j += 7 { - var plain io.ByteBuffer; - out := tt.out[0:len(tt.out) - j]; - r := block.NewCTRReader(c, tt.iv, io.NewByteReader(out)); - w := &plain; - n, err := io.Copy(r, w); - if n != int64(len(out)) || err != nil { - t.Errorf("%s/%d: CTRReader io.Copy = %d, %v want %d, nil", test, len(out), n, err, len(out)); - } else if d, in := plain.Data(), tt.in[0:len(out)]; !same(in, d) { - t.Errorf("%s/%d: CTRReader\nhave %x\nwant %x", test, len(out), d, in); - } - } - - if t.Failed() { - break; - } - } -} diff --git a/src/lib/crypto/block/eax.go b/src/lib/crypto/block/eax.go deleted file mode 100644 index 7e1d7475c..000000000 --- a/src/lib/crypto/block/eax.go +++ /dev/null @@ -1,254 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// EAX mode, not a NIST standard (yet). -// EAX provides encryption and authentication. -// EAX targets the same uses as NIST's CCM mode, -// but EAX adds the ability to run in streaming mode. - -// See -// http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/eax/eax-spec.pdf -// http://www.cs.ucdavis.edu/~rogaway/papers/eax.pdf -// What those papers call OMAC is now called CMAC. - -package block - -import ( - "crypto/block"; - "fmt"; - "io"; - "os"; -) - -// An EAXTagError is returned when the message has failed to authenticate, -// because the tag at the end of the message stream (Read) does not match -// the tag computed from the message itself (Computed). -type EAXTagError struct { - Read []byte; - Computed []byte; -} - -func (e *EAXTagError) String() string { - return fmt.Sprintf("crypto/block: EAX tag mismatch: read %x but computed %x", e.Read, e.Computed); -} - -func setupEAX(c Cipher, iv, hdr []byte, tagBytes int) (ctrIV, tag []byte, cmac Digest) { - n := len(iv); - if n != c.BlockSize() { - panicln("crypto/block: EAX: iv length", n, "!=", c.BlockSize()); - } - buf := make([]byte, n); // zeroed - - // tag = CMAC(0 + iv) ^ CMAC(1 + hdr) ^ CMAC(2 + data) - cmac = NewCMAC(c); - cmac.Write(buf); // 0 - cmac.Write(iv); - sum := cmac.Sum(); - ctrIV = copy(sum); - tag = copy(sum[0:tagBytes]); - - cmac.Reset(); - buf[n-1] = 1; - cmac.Write(buf); // 1 - cmac.Write(hdr); - sum = cmac.Sum(); - for i := 0; i < tagBytes; i++ { - tag[i] ^= sum[i]; - } - - cmac.Reset(); - buf[n-1] = 2; // 2 - cmac.Write(buf); - - return; -} - -func finishEAX(tag []byte, cmac Digest) { - // Finish CMAC #2 and xor into tag. - sum := cmac.Sum(); - for i := range tag { - tag[i] ^= sum[i]; - } -} - -// Writer adapter. Tees writes into both w and cmac. -// Knows that cmac never returns write errors. -type cmacWriter struct { - w io.Writer; - cmac Digest; -} - -func (cw *cmacWriter) Write(p []byte) (n int, err os.Error) { - n, err = cw.w.Write(p); - cw.cmac.Write(p[0:n]); - return; -} - -// An eaxEncrypter implements the EAX encryption mode. -type eaxEncrypter struct { - ctr io.Writer; // CTR encrypter - cw cmacWriter; // CTR's output stream - tag []byte; -} - -// NewEAXEncrypter creates and returns a new EAX encrypter -// using the given cipher c, initialization vector iv, associated data hdr, -// and tag length tagBytes. The encrypter's Write method encrypts -// the data it receives and writes that data to w. -// The encrypter's Close method writes a final authenticating tag to w. -func NewEAXEncrypter(c Cipher, iv []byte, hdr []byte, tagBytes int, w io.Writer) io.WriteCloser { - x := new(eaxEncrypter); - - // Create new CTR instance writing to both - // w for encrypted output and cmac for digesting. - x.cw.w = w; - var ctrIV []byte; - ctrIV, x.tag, x.cw.cmac = setupEAX(c, iv, hdr, tagBytes); - x.ctr = NewCTRWriter(c, ctrIV, &x.cw); - return x; -} - -func (x *eaxEncrypter) Write(p []byte) (n int, err os.Error) { - return x.ctr.Write(p); -} - -func (x *eaxEncrypter) Close() os.Error { - x.ctr = nil; // crash if Write is called again - - // Write tag. - finishEAX(x.tag, x.cw.cmac); - n, err := x.cw.w.Write(x.tag); - if n != len(x.tag) && err == nil { - err = io.ErrShortWrite; - } - - return err; -} - -// Reader adapter. Returns data read from r but hangs -// on to the last len(tag) bytes for itself (returns EOF len(tag) -// bytes early). Also tees all data returned from Read into -// the cmac digest. The "don't return the last t bytes" -// and the "tee into digest" functionality could be separated, -// but the latter half is trivial. -type cmacReader struct { - r io.Reader; - cmac Digest; - tag []byte; - tmp []byte; -} - -func (cr *cmacReader) Read(p []byte) (n int, err os.Error) { - // TODO(rsc): Maybe fall back to simpler code if - // we recognize the underlying r as a ByteBuffer - // or ByteReader. Then we can just take the last piece - // off at the start. - - // First, read a tag-sized chunk. - // It's probably not the tag (unless there's no data). - tag := cr.tag; - if len(tag) < cap(tag) { - nt := len(tag); - nn, err1 := io.FullRead(cr.r, tag[nt:cap(tag)]); - tag = tag[0:nt+nn]; - cr.tag = tag; - if err1 != nil { - return 0, err1; - } - } - - tagBytes := len(tag); - if len(p) > 4*tagBytes { - // If p is big, try to read directly into p to avoid a copy. - n, err = cr.r.Read(p[tagBytes:len(p)]); - if n == 0 { - goto out; - } - // copy old tag into p - for i := 0; i < tagBytes; i++ { - p[i] = tag[i]; - } - // copy new tag out of p - for i := 0; i < tagBytes; i++ { - tag[i] = p[n+i]; - } - goto out; - } - - // Otherwise, read into p and then slide data - n, err = cr.r.Read(p); - if n == 0 { - goto out; - } - - // copy tag+p into p+tmp and then swap tmp, tag - tmp := cr.tmp; - for i := n + tagBytes - 1; i >= 0; i-- { - var c byte; - if i < tagBytes { - c = tag[i]; - } else { - c = p[i - tagBytes]; - } - if i < n { - p[i] = c; - } else { - tmp[i] = c; - } - } - cr.tmp, cr.tag = tag, tmp; - -out: - cr.cmac.Write(p[0:n]); - return; -} - -type eaxDecrypter struct { - ctr io.Reader; - cr cmacReader; - tag []byte; -} - -// NewEAXDecrypter creates and returns a new EAX decrypter -// using the given cipher c, initialization vector iv, associated data hdr, -// and tag length tagBytes. The encrypter's Read method decrypts and -// returns data read from r. At r's EOF, the encrypter checks the final -// authenticating tag and returns an EAXTagError if the tag is invalid. -// In that case, the message should be discarded. -// Note that the data stream returned from Read cannot be -// assumed to be valid, authenticated data until Read returns -// 0, nil to signal the end of the data. -func NewEAXDecrypter(c Cipher, iv []byte, hdr []byte, tagBytes int, r io.Reader) io.Reader { - x := new(eaxDecrypter); - - x.cr.r = r; - x.cr.tag = make([]byte, 0, tagBytes); - x.cr.tmp = make([]byte, 0, tagBytes); - var ctrIV []byte; - ctrIV, x.tag, x.cr.cmac = setupEAX(c, iv, hdr, tagBytes); - x.ctr = NewCTRReader(c, ctrIV, &x.cr); - return x; -} - -func (x *eaxDecrypter) checkTag() os.Error { - x.ctr = nil; // crash if Read is called again - - finishEAX(x.tag, x.cr.cmac); - if !same(x.tag, x.cr.tag) { - e := new(EAXTagError); - e.Computed = copy(x.tag); - e.Read = copy(x.cr.tag); - return e; - } - return nil; -} - -func (x *eaxDecrypter) Read(p []byte) (n int, err os.Error) { - n, err = x.ctr.Read(p); - if n == 0 && err == nil { - err = x.checkTag(); - } - return n, err; -} - diff --git a/src/lib/crypto/block/eax_aes_test.go b/src/lib/crypto/block/eax_aes_test.go deleted file mode 100644 index f0453be80..000000000 --- a/src/lib/crypto/block/eax_aes_test.go +++ /dev/null @@ -1,239 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package block - -import ( - "crypto/aes"; - "crypto/block"; - "fmt"; - "io"; - "testing"; -) - -// Test vectors from http://www.cs.ucdavis.edu/~rogaway/papers/eax.pdf - -type eaxAESTest struct { - msg []byte; - key []byte; - nonce []byte; - header []byte; - cipher []byte; -} - -var eaxAESTests = []eaxAESTest { - eaxAESTest { - []byte { - }, - []byte { - 0x23, 0x39, 0x52, 0xDE, 0xE4, 0xD5, 0xED, 0x5F, 0x9B, 0x9C, 0x6D, 0x6F, 0xF8, 0x0F, 0xF4, 0x78, - }, - []byte { - 0x62, 0xEC, 0x67, 0xF9, 0xC3, 0xA4, 0xA4, 0x07, 0xFC, 0xB2, 0xA8, 0xC4, 0x90, 0x31, 0xA8, 0xB3, - }, - []byte { - 0x6B, 0xFB, 0x91, 0x4F, 0xD0, 0x7E, 0xAE, 0x6B, - }, - []byte { - 0xE0, 0x37, 0x83, 0x0E, 0x83, 0x89, 0xF2, 0x7B, 0x02, 0x5A, 0x2D, 0x65, 0x27, 0xE7, 0x9D, 0x01, - }, - }, - eaxAESTest { - []byte { - 0xF7, 0xFB, - }, - []byte { - 0x91, 0x94, 0x5D, 0x3F, 0x4D, 0xCB, 0xEE, 0x0B, 0xF4, 0x5E, 0xF5, 0x22, 0x55, 0xF0, 0x95, 0xA4, - }, - []byte { - 0xBE, 0xCA, 0xF0, 0x43, 0xB0, 0xA2, 0x3D, 0x84, 0x31, 0x94, 0xBA, 0x97, 0x2C, 0x66, 0xDE, 0xBD, - }, - []byte { - 0xFA, 0x3B, 0xFD, 0x48, 0x06, 0xEB, 0x53, 0xFA, - }, - []byte { - 0x19, 0xDD, 0x5C, 0x4C, 0x93, 0x31, 0x04, 0x9D, 0x0B, 0xDA, 0xB0, 0x27, 0x74, 0x08, 0xF6, 0x79, 0x67, 0xE5, - }, - }, - eaxAESTest { - []byte { - 0x1A, 0x47, 0xCB, 0x49, 0x33, - }, - []byte { - 0x01, 0xF7, 0x4A, 0xD6, 0x40, 0x77, 0xF2, 0xE7, 0x04, 0xC0, 0xF6, 0x0A, 0xDA, 0x3D, 0xD5, 0x23, - }, - []byte { - 0x70, 0xC3, 0xDB, 0x4F, 0x0D, 0x26, 0x36, 0x84, 0x00, 0xA1, 0x0E, 0xD0, 0x5D, 0x2B, 0xFF, 0x5E, - }, - []byte { - 0x23, 0x4A, 0x34, 0x63, 0xC1, 0x26, 0x4A, 0xC6, - }, - []byte { - 0xD8, 0x51, 0xD5, 0xBA, 0xE0, 0x3A, 0x59, 0xF2, 0x38, 0xA2, 0x3E, 0x39, 0x19, 0x9D, 0xC9, 0x26, 0x66, 0x26, 0xC4, 0x0F, 0x80, - }, - }, - eaxAESTest { - []byte { - 0x48, 0x1C, 0x9E, 0x39, 0xB1, - }, - []byte { - 0xD0, 0x7C, 0xF6, 0xCB, 0xB7, 0xF3, 0x13, 0xBD, 0xDE, 0x66, 0xB7, 0x27, 0xAF, 0xD3, 0xC5, 0xE8, - }, - []byte { - 0x84, 0x08, 0xDF, 0xFF, 0x3C, 0x1A, 0x2B, 0x12, 0x92, 0xDC, 0x19, 0x9E, 0x46, 0xB7, 0xD6, 0x17, - }, - []byte { - 0x33, 0xCC, 0xE2, 0xEA, 0xBF, 0xF5, 0xA7, 0x9D, - }, - []byte { - 0x63, 0x2A, 0x9D, 0x13, 0x1A, 0xD4, 0xC1, 0x68, 0xA4, 0x22, 0x5D, 0x8E, 0x1F, 0xF7, 0x55, 0x93, 0x99, 0x74, 0xA7, 0xBE, 0xDE, - }, - }, - eaxAESTest { - []byte { - 0x40, 0xD0, 0xC0, 0x7D, 0xA5, 0xE4, - }, - []byte { - 0x35, 0xB6, 0xD0, 0x58, 0x00, 0x05, 0xBB, 0xC1, 0x2B, 0x05, 0x87, 0x12, 0x45, 0x57, 0xD2, 0xC2, - }, - []byte { - 0xFD, 0xB6, 0xB0, 0x66, 0x76, 0xEE, 0xDC, 0x5C, 0x61, 0xD7, 0x42, 0x76, 0xE1, 0xF8, 0xE8, 0x16, - }, - []byte { - 0xAE, 0xB9, 0x6E, 0xAE, 0xBE, 0x29, 0x70, 0xE9, - }, - []byte { - 0x07, 0x1D, 0xFE, 0x16, 0xC6, 0x75, 0xCB, 0x06, 0x77, 0xE5, 0x36, 0xF7, 0x3A, 0xFE, 0x6A, 0x14, 0xB7, 0x4E, 0xE4, 0x98, 0x44, 0xDD, - }, - }, - eaxAESTest { - []byte { - 0x4D, 0xE3, 0xB3, 0x5C, 0x3F, 0xC0, 0x39, 0x24, 0x5B, 0xD1, 0xFB, 0x7D, - }, - []byte { - 0xBD, 0x8E, 0x6E, 0x11, 0x47, 0x5E, 0x60, 0xB2, 0x68, 0x78, 0x4C, 0x38, 0xC6, 0x2F, 0xEB, 0x22, - }, - []byte { - 0x6E, 0xAC, 0x5C, 0x93, 0x07, 0x2D, 0x8E, 0x85, 0x13, 0xF7, 0x50, 0x93, 0x5E, 0x46, 0xDA, 0x1B, - }, - []byte { - 0xD4, 0x48, 0x2D, 0x1C, 0xA7, 0x8D, 0xCE, 0x0F, - }, - []byte { - 0x83, 0x5B, 0xB4, 0xF1, 0x5D, 0x74, 0x3E, 0x35, 0x0E, 0x72, 0x84, 0x14, 0xAB, 0xB8, 0x64, 0x4F, 0xD6, 0xCC, 0xB8, 0x69, 0x47, 0xC5, 0xE1, 0x05, 0x90, 0x21, 0x0A, 0x4F, - }, - }, - eaxAESTest { - []byte { - 0x8B, 0x0A, 0x79, 0x30, 0x6C, 0x9C, 0xE7, 0xED, 0x99, 0xDA, 0xE4, 0xF8, 0x7F, 0x8D, 0xD6, 0x16, 0x36, - }, - []byte { - 0x7C, 0x77, 0xD6, 0xE8, 0x13, 0xBE, 0xD5, 0xAC, 0x98, 0xBA, 0xA4, 0x17, 0x47, 0x7A, 0x2E, 0x7D, - }, - []byte { - 0x1A, 0x8C, 0x98, 0xDC, 0xD7, 0x3D, 0x38, 0x39, 0x3B, 0x2B, 0xF1, 0x56, 0x9D, 0xEE, 0xFC, 0x19, - }, - []byte { - 0x65, 0xD2, 0x01, 0x79, 0x90, 0xD6, 0x25, 0x28, - }, - []byte { - 0x02, 0x08, 0x3E, 0x39, 0x79, 0xDA, 0x01, 0x48, 0x12, 0xF5, 0x9F, 0x11, 0xD5, 0x26, 0x30, 0xDA, 0x30, 0x13, 0x73, 0x27, 0xD1, 0x06, 0x49, 0xB0, 0xAA, 0x6E, 0x1C, 0x18, 0x1D, 0xB6, 0x17, 0xD7, 0xF2, - }, - }, - eaxAESTest { - []byte { - 0x1B, 0xDA, 0x12, 0x2B, 0xCE, 0x8A, 0x8D, 0xBA, 0xF1, 0x87, 0x7D, 0x96, 0x2B, 0x85, 0x92, 0xDD, 0x2D, 0x56, - }, - []byte { - 0x5F, 0xFF, 0x20, 0xCA, 0xFA, 0xB1, 0x19, 0xCA, 0x2F, 0xC7, 0x35, 0x49, 0xE2, 0x0F, 0x5B, 0x0D, - }, - []byte { - 0xDD, 0xE5, 0x9B, 0x97, 0xD7, 0x22, 0x15, 0x6D, 0x4D, 0x9A, 0xFF, 0x2B, 0xC7, 0x55, 0x98, 0x26, - }, - []byte { - 0x54, 0xB9, 0xF0, 0x4E, 0x6A, 0x09, 0x18, 0x9A, - }, - []byte { - 0x2E, 0xC4, 0x7B, 0x2C, 0x49, 0x54, 0xA4, 0x89, 0xAF, 0xC7, 0xBA, 0x48, 0x97, 0xED, 0xCD, 0xAE, 0x8C, 0xC3, 0x3B, 0x60, 0x45, 0x05, 0x99, 0xBD, 0x02, 0xC9, 0x63, 0x82, 0x90, 0x2A, 0xEF, 0x7F, 0x83, 0x2A, - }, - }, - eaxAESTest { - []byte { - 0x6C, 0xF3, 0x67, 0x20, 0x87, 0x2B, 0x85, 0x13, 0xF6, 0xEA, 0xB1, 0xA8, 0xA4, 0x44, 0x38, 0xD5, 0xEF, 0x11, - }, - []byte { - 0xA4, 0xA4, 0x78, 0x2B, 0xCF, 0xFD, 0x3E, 0xC5, 0xE7, 0xEF, 0x6D, 0x8C, 0x34, 0xA5, 0x61, 0x23, - }, - []byte { - 0xB7, 0x81, 0xFC, 0xF2, 0xF7, 0x5F, 0xA5, 0xA8, 0xDE, 0x97, 0xA9, 0xCA, 0x48, 0xE5, 0x22, 0xEC, - }, - []byte { - 0x89, 0x9A, 0x17, 0x58, 0x97, 0x56, 0x1D, 0x7E, - }, - []byte { - 0x0D, 0xE1, 0x8F, 0xD0, 0xFD, 0xD9, 0x1E, 0x7A, 0xF1, 0x9F, 0x1D, 0x8E, 0xE8, 0x73, 0x39, 0x38, 0xB1, 0xE8, 0xE7, 0xF6, 0xD2, 0x23, 0x16, 0x18, 0x10, 0x2F, 0xDB, 0x7F, 0xE5, 0x5F, 0xF1, 0x99, 0x17, 0x00, - }, - }, - eaxAESTest { - []byte { - 0xCA, 0x40, 0xD7, 0x44, 0x6E, 0x54, 0x5F, 0xFA, 0xED, 0x3B, 0xD1, 0x2A, 0x74, 0x0A, 0x65, 0x9F, 0xFB, 0xBB, 0x3C, 0xEA, 0xB7, - }, - []byte { - 0x83, 0x95, 0xFC, 0xF1, 0xE9, 0x5B, 0xEB, 0xD6, 0x97, 0xBD, 0x01, 0x0B, 0xC7, 0x66, 0xAA, 0xC3, - }, - []byte { - 0x22, 0xE7, 0xAD, 0xD9, 0x3C, 0xFC, 0x63, 0x93, 0xC5, 0x7E, 0xC0, 0xB3, 0xC1, 0x7D, 0x6B, 0x44, - }, - []byte { - 0x12, 0x67, 0x35, 0xFC, 0xC3, 0x20, 0xD2, 0x5A, - }, - []byte { - 0xCB, 0x89, 0x20, 0xF8, 0x7A, 0x6C, 0x75, 0xCF, 0xF3, 0x96, 0x27, 0xB5, 0x6E, 0x3E, 0xD1, 0x97, 0xC5, 0x52, 0xD2, 0x95, 0xA7, 0xCF, 0xC4, 0x6A, 0xFC, 0x25, 0x3B, 0x46, 0x52, 0xB1, 0xAF, 0x37, 0x95, 0xB1, 0x24, 0xAB, 0x6E, - }, - }, -} - -func TestEAXEncrypt_AES(t *testing.T) { - b := new(io.ByteBuffer); - for i, tt := range eaxAESTests { - test := fmt.Sprintf("test %d", i); - c, err := aes.NewCipher(tt.key); - if err != nil { - t.Fatalf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err); - } - b.Reset(); - enc := NewEAXEncrypter(c, tt.nonce, tt.header, 16, b); - n, err := io.Copy(io.NewByteReader(tt.msg), enc); - if n != int64(len(tt.msg)) || err != nil { - t.Fatalf("%s: io.Copy into encrypter: %d, %s", test, n, err); - } - err = enc.Close(); - if err != nil { - t.Fatalf("%s: enc.Close: %s", test, err); - } - if d := b.Data(); !same(d, tt.cipher) { - t.Fatalf("%s: got %x want %x", test, d, tt.cipher); - } - } -} - -func TestEAXDecrypt_AES(t *testing.T) { - b := new(io.ByteBuffer); - for i, tt := range eaxAESTests { - test := fmt.Sprintf("test %d", i); - c, err := aes.NewCipher(tt.key); - if err != nil { - t.Fatalf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err); - } - b.Reset(); - dec := NewEAXDecrypter(c, tt.nonce, tt.header, 16, io.NewByteReader(tt.cipher)); - n, err := io.Copy(dec, b); - if n != int64(len(tt.msg)) || err != nil { - t.Fatalf("%s: io.Copy into decrypter: %d, %s", test, n, err); - } - if d := b.Data(); !same(d, tt.msg) { - t.Fatalf("%s: got %x want %x", test, d, tt.msg); - } - } -} diff --git a/src/lib/crypto/block/ecb.go b/src/lib/crypto/block/ecb.go deleted file mode 100644 index 141d38cc8..000000000 --- a/src/lib/crypto/block/ecb.go +++ /dev/null @@ -1,271 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Electronic codebook (ECB) mode. -// ECB is a fancy name for ``encrypt and decrypt each block separately.'' -// It's a pretty bad thing to do for any large amount of data (more than one block), -// because the individual blocks can still be identified, duplicated, and reordered. -// The ECB implementation exists mainly to provide buffering for -// the other modes, which wrap it by providing modified Ciphers. - -// See NIST SP 800-38A, pp 9-10 - -package block - -import ( - "crypto/block"; - "io"; - "os"; -) - -type ecbDecrypter struct { - c Cipher; - r io.Reader; - blockSize int; // block size - - // Buffered data. - // The buffer buf is used as storage for both - // plain or crypt; at least one of those is nil at any given time. - buf []byte; - plain []byte; // plain text waiting to be read - crypt []byte; // ciphertext waiting to be decrypted -} - -// Read into x.crypt until it has a full block or EOF or an error happens. -func (x *ecbDecrypter) fillCrypt() os.Error { - var err os.Error; - for len(x.crypt) < x.blockSize { - off := len(x.crypt); - var m int; - m, err = x.r.Read(x.crypt[off:x.blockSize]); - x.crypt = x.crypt[0:off+m]; - if m == 0 { - break; - } - - // If an error happened but we got enough - // data to do some decryption, we can decrypt - // first and report the error (with some data) later. - // But if we don't have enough to decrypt, - // have to stop now. - if err != nil && len(x.crypt) < x.blockSize { - break; - } - } - return err; -} - -// Read from plain text buffer into p. -func (x *ecbDecrypter) readPlain(p []byte) int { - n := len(x.plain); - if n > len(p) { - n = len(p); - } - for i := 0; i < n; i++ { - p[i] = x.plain[i]; - } - if n < len(x.plain) { - x.plain = x.plain[n:len(x.plain)]; - } else { - x.plain = nil; - } - return n; -} - -func (x *ecbDecrypter) Read(p []byte) (n int, err os.Error) { - if len(p) == 0 { - return; - } - - // If there's no plaintext waiting and p is not big enough - // to hold a whole cipher block, we'll have to work in the - // cipher text buffer. Set it to non-nil so that the - // code below will fill it. - if x.plain == nil && len(p) < x.blockSize && x.crypt == nil { - x.crypt = x.buf[0:0]; - } - - // If there is a leftover cipher text buffer, - // try to accumulate a full block. - if x.crypt != nil { - err = x.fillCrypt(); - if err != nil || len(x.crypt) == 0 { - return; - } - x.c.Decrypt(x.crypt, x.crypt); - x.plain = x.crypt; - x.crypt = nil; - } - - // If there is a leftover plain text buffer, read from it. - if x.plain != nil { - n = x.readPlain(p); - return; - } - - // Read and decrypt directly in caller's buffer. - n, err = io.ReadAtLeast(x.r, p, x.blockSize); - if err == io.ErrEOF && n == 0 { - // EOF is okay on block boundary - err = nil; - return; - } - var i int; - for i = 0; i+x.blockSize <= n; i += x.blockSize { - a := p[i:i+x.blockSize]; - x.c.Decrypt(a, a); - } - - // There might be an encrypted fringe remaining. - // Save it for next time. - if i < n { - p = p[i:n]; - for j, v := range p { - x.buf[j] = p[j]; - } - x.crypt = x.buf[0:len(p)]; - n = i; - } - - return; -} - -// NewECBDecrypter returns a reader that reads data from r and decrypts it using c. -// It decrypts by calling c.Decrypt on each block in sequence; -// this mode is known as electronic codebook mode, or ECB. -// The returned Reader does not buffer or read ahead except -// as required by the cipher's block size. -func NewECBDecrypter(c Cipher, r io.Reader) io.Reader { - x := new(ecbDecrypter); - x.c = c; - x.r = r; - x.blockSize = c.BlockSize(); - x.buf = make([]byte, x.blockSize); - return x; -} - -type ecbEncrypter struct { - c Cipher; - w io.Writer; - blockSize int; - - // Buffered data. - // The buffer buf is used as storage for both - // plain or crypt. If both are non-nil, plain - // follows crypt in buf. - buf []byte; - plain []byte; // plain text waiting to be encrypted - crypt []byte; // encrypted text waiting to be written -} - -// Flush the x.crypt buffer to x.w. -func (x *ecbEncrypter) flushCrypt() os.Error { - if len(x.crypt) == 0 { - return nil; - } - n, err := x.w.Write(x.crypt); - if n < len(x.crypt) { - x.crypt = x.crypt[n:len(x.crypt)]; - if err == nil { - err = io.ErrShortWrite; - } - } - if err != nil { - return err; - } - x.crypt = nil; - return nil; -} - -// Slide x.plain down to the beginning of x.buf. -// Plain is known to have less than one block of data, -// so this is cheap enough. -func (x *ecbEncrypter) slidePlain() { - if len(x.plain) == 0 { - x.plain = x.buf[0:0]; - } else if cap(x.plain) < cap(x.buf) { - // plain and buf share same data, - // but buf is before plain, so forward loop is correct - for i := 0; i < len(x.plain); i++ { - x.buf[i] = x.plain[i]; - } - x.plain = x.buf[0:len(x.plain)]; - } -} - -// Fill x.plain from the data in p. -// Return the number of bytes copied. -func (x *ecbEncrypter) fillPlain(p []byte) int { - off := len(x.plain); - n := len(p); - if max := cap(x.plain) - off; n > max { - n = max; - } - x.plain = x.plain[0:off+n]; - for i := 0; i < n; i++ { - x.plain[off + i] = p[i]; - } - return n; -} - -// Encrypt x.plain; record encrypted range as x.crypt. -func (x *ecbEncrypter) encrypt() { - var i int; - n := len(x.plain); - for i = 0; i+x.blockSize <= n; i += x.blockSize { - a := x.plain[i:i+x.blockSize]; - x.c.Encrypt(a, a); - } - x.crypt = x.plain[0:i]; - x.plain = x.plain[i:n]; -} - -func (x *ecbEncrypter) Write(p []byte) (n int, err os.Error) { - for { - // If there is data waiting to be written, write it. - // This can happen on the first iteration - // if a write failed in an earlier call. - if err = x.flushCrypt(); err != nil { - return; - } - - // Now that encrypted data is gone (flush ran), - // perhaps we need to slide the plaintext down. - x.slidePlain(); - - // Fill plaintext buffer from p. - m := x.fillPlain(p); - if m == 0 { - break; - } - n += m; - p = p[m:len(p)]; - - // Encrypt, adjusting crypt and plain. - x.encrypt(); - - // Write x.crypt. - if err = x.flushCrypt(); err != nil { - break; - } - } - return; -} - -// NewECBEncrypter returns a writer that encrypts data using c and writes it to w. -// It encrypts by calling c.Encrypt on each block in sequence; -// this mode is known as electronic codebook mode, or ECB. -// The returned Writer does no buffering except as required -// by the cipher's block size, so there is no need for a Flush method. -func NewECBEncrypter(c Cipher, w io.Writer) io.Writer { - x := new(ecbEncrypter); - x.c = c; - x.w = w; - x.blockSize = c.BlockSize(); - - // Create a buffer that is an integral number of blocks. - x.buf = make([]byte, 8192/x.blockSize * x.blockSize); - return x; -} - diff --git a/src/lib/crypto/block/ecb_aes_test.go b/src/lib/crypto/block/ecb_aes_test.go deleted file mode 100644 index de8a624b9..000000000 --- a/src/lib/crypto/block/ecb_aes_test.go +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// ECB AES test vectors. - -// See U.S. National Institute of Standards and Technology (NIST) -// Special Publication 800-38A, ``Recommendation for Block Cipher -// Modes of Operation,'' 2001 Edition, pp. 24-27. - -package block - -import ( - "crypto/aes"; - "crypto/block"; - "io"; - "os"; - "testing"; -) - -type ecbTest struct { - name string; - key []byte; - in []byte; - out []byte; -} - -var commonInput = []byte { - 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, - 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, - 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, - 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10, -} - -var commonKey128 = []byte { - 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c, -} - -var commonKey192 = []byte { - 0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5, - 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b, -} - -var commonKey256 = []byte { - 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, - 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4, -} - -var commonIV = []byte { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, -} - -var ecbAESTests = []ecbTest { - // FIPS 197, Appendix B, C - ecbTest { - "FIPS-197 Appendix B", - commonKey128, - []byte { - 0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d, 0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34, - }, - []byte { - 0x39, 0x25, 0x84, 0x1d, 0x02, 0xdc, 0x09, 0xfb, 0xdc, 0x11, 0x85, 0x97, 0x19, 0x6a, 0x0b, 0x32, - } - }, - - // NIST SP 800-38A pp 24-27 - ecbTest { - "ECB-AES128", - commonKey128, - commonInput, - []byte { - 0x3a, 0xd7, 0x7b, 0xb4, 0x0d, 0x7a, 0x36, 0x60, 0xa8, 0x9e, 0xca, 0xf3, 0x24, 0x66, 0xef, 0x97, - 0xf5, 0xd3, 0xd5, 0x85, 0x03, 0xb9, 0x69, 0x9d, 0xe7, 0x85, 0x89, 0x5a, 0x96, 0xfd, 0xba, 0xaf, - 0x43, 0xb1, 0xcd, 0x7f, 0x59, 0x8e, 0xce, 0x23, 0x88, 0x1b, 0x00, 0xe3, 0xed, 0x03, 0x06, 0x88, - 0x7b, 0x0c, 0x78, 0x5e, 0x27, 0xe8, 0xad, 0x3f, 0x82, 0x23, 0x20, 0x71, 0x04, 0x72, 0x5d, 0xd4, - } - }, - ecbTest { - "ECB-AES192", - commonKey192, - commonInput, - []byte { - 0xbd, 0x33, 0x4f, 0x1d, 0x6e, 0x45, 0xf2, 0x5f, 0xf7, 0x12, 0xa2, 0x14, 0x57, 0x1f, 0xa5, 0xcc, - 0x97, 0x41, 0x04, 0x84, 0x6d, 0x0a, 0xd3, 0xad, 0x77, 0x34, 0xec, 0xb3, 0xec, 0xee, 0x4e, 0xef, - 0xef, 0x7a, 0xfd, 0x22, 0x70, 0xe2, 0xe6, 0x0a, 0xdc, 0xe0, 0xba, 0x2f, 0xac, 0xe6, 0x44, 0x4e, - 0x9a, 0x4b, 0x41, 0xba, 0x73, 0x8d, 0x6c, 0x72, 0xfb, 0x16, 0x69, 0x16, 0x03, 0xc1, 0x8e, 0x0e, - } - }, - ecbTest { - "ECB-AES256", - commonKey256, - commonInput, - []byte { - 0xf3, 0xee, 0xd1, 0xbd, 0xb5, 0xd2, 0xa0, 0x3c, 0x06, 0x4b, 0x5a, 0x7e, 0x3d, 0xb1, 0x81, 0xf8, - 0x59, 0x1c, 0xcb, 0x10, 0xd4, 0x10, 0xed, 0x26, 0xdc, 0x5b, 0xa7, 0x4a, 0x31, 0x36, 0x28, 0x70, - 0xb6, 0xed, 0x21, 0xb9, 0x9c, 0xa6, 0xf4, 0xf9, 0xf1, 0x53, 0xe7, 0xb1, 0xbe, 0xaf, 0xed, 0x1d, - 0x23, 0x30, 0x4b, 0x7a, 0x39, 0xf9, 0xf3, 0xff, 0x06, 0x7d, 0x8d, 0x8f, 0x9e, 0x24, 0xec, 0xc7, - } - } -} - -func TestECB_AES(t *testing.T) { - for i, tt := range ecbAESTests { - test := tt.name; - - c, err := aes.NewCipher(tt.key); - if err != nil { - t.Errorf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err); - continue; - } - - var crypt io.ByteBuffer; - w := NewECBEncrypter(c, &crypt); - var r io.Reader = io.NewByteReader(tt.in); - n, err := io.Copy(r, w); - if n != int64(len(tt.in)) || err != nil { - t.Errorf("%s: ECBReader io.Copy = %d, %v want %d, nil", test, n, err, len(tt.in)); - } else if d := crypt.Data(); !same(tt.out, d) { - t.Errorf("%s: ECBReader\nhave %x\nwant %x", test, d, tt.out); - } - - var plain io.ByteBuffer; - r = NewECBDecrypter(c, io.NewByteReader(tt.out)); - w = &plain; - n, err = io.Copy(r, w); - if n != int64(len(tt.out)) || err != nil { - t.Errorf("%s: ECBWriter io.Copy = %d, %v want %d, nil", test, n, err, len(tt.out)); - } else if d := plain.Data(); !same(tt.in, d) { - t.Errorf("%s: ECBWriter\nhave %x\nwant %x", test, d, tt.in); - } - - if t.Failed() { - break; - } - } -} diff --git a/src/lib/crypto/block/ecb_test.go b/src/lib/crypto/block/ecb_test.go deleted file mode 100644 index 968893a9b..000000000 --- a/src/lib/crypto/block/ecb_test.go +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package block - -import ( - "crypto/block"; - "fmt"; - "io"; - "testing"; - "testing/iotest"; -) - -// Simple Cipher for testing: adds an incrementing amount -// to each byte in each -type IncCipher struct { - blockSize int; - delta byte; - encrypting bool; -} - -func (c *IncCipher) BlockSize() int { - return c.blockSize; -} - -func (c *IncCipher) Encrypt(src, dst []byte) { - if !c.encrypting { - panicln("encrypt: not encrypting"); - } - if len(src) != c.blockSize || len(dst) != c.blockSize { - panicln("encrypt: wrong block size", c.blockSize, len(src), len(dst)); - } - c.delta++; - for i, b := range src { - dst[i] = b + c.delta; - } -} - -func (c *IncCipher) Decrypt(src, dst []byte) { - if c.encrypting { - panicln("decrypt: not decrypting"); - } - if len(src) != c.blockSize || len(dst) != c.blockSize { - panicln("decrypt: wrong block size", c.blockSize, len(src), len(dst)); - } - c.delta--; - for i, b := range src { - dst[i] = b + c.delta; - } -} - -func TestECBEncrypter(t *testing.T) { - var plain, crypt [256]byte; - for i := 0; i < len(plain); i++ { - plain[i] = byte(i); - } - b := new(io.ByteBuffer); - for block := 1; block <= 64; block *= 2 { - // compute encrypted version - delta := byte(0); - for i := 0; i < len(crypt); i++ { - if i % block == 0 { - delta++; - } - crypt[i] = plain[i] + delta; - } - - for frag := 0; frag < 2; frag++ { - c := &IncCipher{block, 0, true}; - b.Reset(); - r := io.NewByteReader(&plain); - w := NewECBEncrypter(c, b); - - // copy plain into w in increasingly large chunks: 1, 1, 2, 4, 8, ... - // if frag != 0, move the 1 to the end to cause fragmentation. - if frag == 0 { - nn, err := io.Copyn(r, w, 1); - if err != nil { - t.Errorf("block=%d frag=0: first Copyn: %s", block, err); - continue; - } - } - for n := 1; n <= len(plain)/2; n *= 2 { - nn, err := io.Copyn(r, w, int64(n)); - if err != nil { - t.Errorf("block=%d frag=%d: Copyn %d: %s", block, frag, n, err); - } - } - if frag != 0 { - nn, err := io.Copyn(r, w, 1); - if err != nil { - t.Errorf("block=%d frag=1: last Copyn: %s", block, err); - continue; - } - } - - // check output - data := b.Data(); - if len(data) != len(crypt) { - t.Errorf("block=%d frag=%d: want %d bytes, got %d", block, frag, len(crypt), len(data)); - continue; - } - - if string(data) != string(&crypt) { - t.Errorf("block=%d frag=%d: want %x got %x", block, frag, data, crypt); - } - } - } -} - -func testECBDecrypter(t *testing.T, maxio int) { - var readers = []func(io.Reader) io.Reader { - func (r io.Reader) io.Reader { return r }, - iotest.OneByteReader, - iotest.HalfReader, - }; - var plain, crypt [256]byte; - for i := 0; i < len(plain); i++ { - plain[i] = byte(255 - i); - } - b := new(io.ByteBuffer); - for block := 1; block <= 64 && block <= maxio; block *= 2 { - // compute encrypted version - delta := byte(0); - for i := 0; i < len(crypt); i++ { - if i % block == 0 { - delta++; - } - crypt[i] = plain[i] + delta; - } - - for mode := 0; mode < len(readers); mode++ { - for frag := 0; frag < 2; frag++ { - test := fmt.Sprintf("block=%d mode=%d frag=%d maxio=%d", block, mode, frag, maxio); - c := &IncCipher{block, 0, false}; - b.Reset(); - r := NewECBDecrypter(c, readers[mode](io.NewByteReader(crypt[0:maxio]))); - - // read from crypt in increasingly large chunks: 1, 1, 2, 4, 8, ... - // if frag == 1, move the 1 to the end to cause fragmentation. - if frag == 0 { - nn, err := io.Copyn(r, b, 1); - if err != nil { - t.Errorf("%s: first Copyn: %s", test, err); - continue; - } - } - for n := 1; n <= maxio/2; n *= 2 { - nn, err := io.Copyn(r, b, int64(n)); - if err != nil { - t.Errorf("%s: Copyn %d: %s", test, n, err); - } - } - if frag != 0 { - nn, err := io.Copyn(r, b, 1); - if err != nil { - t.Errorf("%s: last Copyn: %s", test, err); - continue; - } - } - - // check output - data := b.Data(); - if len(data) != maxio { - t.Errorf("%s: want %d bytes, got %d", test, maxio, len(data)); - continue; - } - - if string(data) != string(plain[0:maxio]) { - t.Errorf("%s: input=%x want %x got %x", test, crypt[0:maxio], plain[0:maxio], data); - } - } - } - } -} - -func TestECBDecrypter(t *testing.T) { - // Do shorter I/O sizes first; they're easier to debug. - for n := 1; n <= 256 && !t.Failed(); n *= 2 { - testECBDecrypter(t, n); - } -} diff --git a/src/lib/crypto/block/ofb.go b/src/lib/crypto/block/ofb.go deleted file mode 100644 index 084274a08..000000000 --- a/src/lib/crypto/block/ofb.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Output feedback (OFB) mode. - -// OFB converts a block cipher into a stream cipher by -// repeatedly encrypting an initialization vector and -// xoring the resulting stream of data with the input. - -// See NIST SP 800-38A, pp 13-15 - -package block - -import ( - "crypto/block"; - "io"; -) - -type ofbStream struct { - c Cipher; - iv []byte; -} - -func newOFBStream(c Cipher, iv []byte) *ofbStream { - x := new(ofbStream); - x.c = c; - n := len(iv); - if n != c.BlockSize() { - panicln("crypto/block: newOFBStream: invalid iv size", n, "!=", c.BlockSize()); - } - x.iv = copy(iv); - return x; -} - -func (x *ofbStream) Next() []byte { - x.c.Encrypt(x.iv, x.iv); - return x.iv; -} - -// NewOFBReader returns a reader that reads data from r, decrypts (or encrypts) -// it using c in output feedback (OFB) mode with the initialization vector iv. -// The returned Reader does not buffer and has no block size. -// In OFB mode, encryption and decryption are the same operation: -// an OFB reader applied to an encrypted stream produces a decrypted -// stream and vice versa. -func NewOFBReader(c Cipher, iv []byte, r io.Reader) io.Reader { - return newXorReader(newOFBStream(c, iv), r); -} - -// NewOFBWriter returns a writer that encrypts (or decrypts) data using c -// in cipher feedback (OFB) mode with the initialization vector iv -// and writes the encrypted data to w. -// The returned Writer does not buffer and has no block size. -// In OFB mode, encryption and decryption are the same operation: -// an OFB writer applied to an decrypted stream produces an encrypted -// stream and vice versa. -func NewOFBWriter(c Cipher, iv []byte, w io.Writer) io.Writer { - return newXorWriter(newOFBStream(c, iv), w); -} - diff --git a/src/lib/crypto/block/ofb_aes_test.go b/src/lib/crypto/block/ofb_aes_test.go deleted file mode 100644 index 3f5f9f482..000000000 --- a/src/lib/crypto/block/ofb_aes_test.go +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// OFB AES test vectors. - -// See U.S. National Institute of Standards and Technology (NIST) -// Special Publication 800-38A, ``Recommendation for Block Cipher -// Modes of Operation,'' 2001 Edition, pp. 52-55. - -package block - -// gotest: $GC ecb_aes_test.go - -import ( - "crypto/aes"; - "crypto/block"; - "io"; - "os"; - "testing"; - - "./ecb_aes_test"; -) - -type ofbTest struct { - name string; - key []byte; - iv []byte; - in []byte; - out []byte; -} - -var ofbAESTests = []ofbTest { - // NIST SP 800-38A pp 52-55 - ofbTest { - "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, - }, - }, - ofbTest { - "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, - }, - }, - ofbTest { - "OFB-AES256", - commonKey256, - commonIV, - commonInput, - []byte { - 0xdc, 0x7e, 0x84, 0xbf, 0xda, 0x79, 0x16, 0x4b, 0x7e, 0xcd, 0x84, 0x86, 0x98, 0x5d, 0x38, 0x60, - 0x4f, 0xeb, 0xdc, 0x67, 0x40, 0xd2, 0x0b, 0x3a, 0xc8, 0x8f, 0x6a, 0xd8, 0x2a, 0x4f, 0xb0, 0x8d, - 0x71, 0xab, 0x47, 0xa0, 0x86, 0xe8, 0x6e, 0xed, 0xf3, 0x9d, 0x1c, 0x5b, 0xba, 0x97, 0xc4, 0x08, - 0x01, 0x26, 0x14, 0x1d, 0x67, 0xf3, 0x7b, 0xe8, 0x53, 0x8f, 0x5a, 0x8b, 0xe7, 0x40, 0xe4, 0x84, - } - }, -} - -func TestOFB_AES(t *testing.T) { - for i, tt := range ofbAESTests { - test := tt.name; - - c, err := aes.NewCipher(tt.key); - if err != nil { - t.Errorf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err); - continue; - } - - for j := 0; j <= 5; j += 5 { - var crypt io.ByteBuffer; - in := tt.in[0:len(tt.in) - j]; - w := NewOFBWriter(c, tt.iv, &crypt); - var r io.Reader = io.NewByteReader(in); - n, err := io.Copy(r, w); - if n != int64(len(in)) || err != nil { - t.Errorf("%s/%d: OFBWriter io.Copy = %d, %v want %d, nil", test, len(in), n, err, len(in)); - } else if d, out := crypt.Data(), tt.out[0:len(in)]; !same(out, d) { - t.Errorf("%s/%d: OFBWriter\ninpt %x\nhave %x\nwant %x", test, len(in), in, d, out); - } - } - - for j := 0; j <= 7; j += 7 { - var plain io.ByteBuffer; - out := tt.out[0:len(tt.out) - j]; - r := NewOFBReader(c, tt.iv, io.NewByteReader(out)); - w := &plain; - n, err := io.Copy(r, w); - if n != int64(len(out)) || err != nil { - t.Errorf("%s/%d: OFBReader io.Copy = %d, %v want %d, nil", test, len(out), n, err, len(out)); - } else if d, in := plain.Data(), tt.in[0:len(out)]; !same(in, d) { - t.Errorf("%s/%d: OFBReader\nhave %x\nwant %x", test, len(out), d, in); - } - } - - if t.Failed() { - break; - } - } -} diff --git a/src/lib/crypto/block/xor.go b/src/lib/crypto/block/xor.go deleted file mode 100644 index 63229dbb4..000000000 --- a/src/lib/crypto/block/xor.go +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Encrypt/decrypt data by xor with a pseudo-random data stream. - -package block - -import ( - "crypto/block"; - "io"; - "os"; -) - -// A dataStream is an interface to an unending stream of data, -// used by XorReader and XorWriter to model a pseudo-random generator. -// Calls to Next() return sequential blocks of data from the stream. -// Each call must return at least one byte: there is no EOF. -type dataStream interface { - Next() []byte -} - -type xorReader struct { - r io.Reader; - rand dataStream; // pseudo-random - buf []byte; // data available from last call to rand -} - -func newXorReader(rand dataStream, r io.Reader) io.Reader { - x := new(xorReader); - x.r = r; - x.rand = rand; - return x; -} - -func (x *xorReader) Read(p []byte) (n int, err os.Error) { - n, err = x.r.Read(p); - - // xor input with stream. - bp := 0; - buf := x.buf; - for i := 0; i < n; i++ { - if bp >= len(buf) { - buf = x.rand.Next(); - bp = 0; - } - p[i] ^= buf[bp]; - bp++; - } - x.buf = buf[bp:len(buf)]; - return n, err; -} - -type xorWriter struct { - w io.Writer; - rand dataStream; // pseudo-random - buf []byte; // last buffer returned by rand - extra []byte; // extra random data (use before buf) - work []byte; // work space -} - -func newXorWriter(rand dataStream, w io.Writer) io.Writer { - x := new(xorWriter); - x.w = w; - x.rand = rand; - x.work = make([]byte, 4096); - return x; -} - -func (x *xorWriter) Write(p []byte) (n int, err os.Error) { - for len(p) > 0 { - // Determine next chunk of random data - // and xor with p into x.work. - var chunk []byte; - m := len(p); - if nn := len(x.extra); nn > 0 { - // extra points into work, so edit directly - if m > nn { - m = nn; - } - for i := 0; i < m; i++ { - x.extra[i] ^= p[i]; - } - chunk = x.extra[0:m]; - } else { - // xor p ^ buf into work, refreshing buf as needed - if nn := len(x.work); m > nn { - m = nn; - } - bp := 0; - buf := x.buf; - for i := 0; i < m; i++ { - if bp >= len(buf) { - buf = x.rand.Next(); - bp = 0; - } - x.work[i] = buf[bp] ^ p[i]; - bp++; - } - x.buf = buf[bp:len(buf)]; - chunk = x.work[0:m]; - } - - // Write chunk. - var nn int; - nn, err = x.w.Write(chunk); - if nn != len(chunk) && err == nil { - err = io.ErrShortWrite; - } - if nn < len(chunk) { - // Reconstruct the random bits from the unwritten - // data and save them for next time. - for i := nn; i < m; i++ { - chunk[i] ^= p[i]; - } - x.extra = chunk[nn:len(chunk)]; - } - n += nn; - if err != nil { - return; - } - p = p[m:len(p)]; - } - return; -} - diff --git a/src/lib/crypto/block/xor_test.go b/src/lib/crypto/block/xor_test.go deleted file mode 100644 index 6e6d1a3ce..000000000 --- a/src/lib/crypto/block/xor_test.go +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package block - -import ( - "crypto/block"; - "fmt"; - "io"; - "testing"; - "testing/iotest"; -) - -// Simple "pseudo-random" stream for testing. -type incStream struct { - buf []byte; - n byte; -} - -func newIncStream(blockSize int) *incStream { - x := new(incStream); - x.buf = make([]byte, blockSize); - return x; -} - -func (x *incStream) Next() []byte { - x.n++; - for i := range x.buf { - x.buf[i] = x.n; - x.n++; - } - return x.buf; -} - -func testXorWriter(t *testing.T, maxio int) { - var plain, crypt [256]byte; - for i := 0; i < len(plain); i++ { - plain[i] = byte(i); - } - b := new(io.ByteBuffer); - for block := 1; block <= 64 && block <= maxio; block *= 2 { - // compute encrypted version - n := byte(0); - for i := 0; i < len(crypt); i++ { - if i % block == 0 { - n++; - } - crypt[i] = plain[i] ^ n; - n++; - } - - for frag := 0; frag < 2; frag++ { - test := fmt.Sprintf("block=%d frag=%d maxio=%d", block, frag, maxio); - b.Reset(); - r := io.NewByteReader(&plain); - s := newIncStream(block); - w := newXorWriter(s, b); - - // copy plain into w in increasingly large chunks: 1, 1, 2, 4, 8, ... - // if frag != 0, move the 1 to the end to cause fragmentation. - if frag == 0 { - nn, err := io.Copyn(r, w, 1); - if err != nil { - t.Errorf("%s: first Copyn: %s", test, err); - continue; - } - } - for n := 1; n <= len(plain)/2; n *= 2 { - nn, err := io.Copyn(r, w, int64(n)); - if err != nil { - t.Errorf("%s: Copyn %d: %s", test, n, err); - } - } - - // check output - crypt := crypt[0:len(crypt) - frag]; - data := b.Data(); - if len(data) != len(crypt) { - t.Errorf("%s: want %d bytes, got %d", test, len(crypt), len(data)); - continue; - } - - if string(data) != string(crypt) { - t.Errorf("%s: want %x got %x", test, data, crypt); - } - } - } -} - - -func TestXorWriter(t *testing.T) { - // Do shorter I/O sizes first; they're easier to debug. - for n := 1; n <= 256 && !t.Failed(); n *= 2 { - testXorWriter(t, n); - } -} - -func testXorReader(t *testing.T, maxio int) { - var readers = []func(io.Reader) io.Reader { - func (r io.Reader) io.Reader { return r }, - iotest.OneByteReader, - iotest.HalfReader, - }; - var plain, crypt [256]byte; - for i := 0; i < len(plain); i++ { - plain[i] = byte(255 - i); - } - b := new(io.ByteBuffer); - for block := 1; block <= 64 && block <= maxio; block *= 2 { - // compute encrypted version - n := byte(0); - for i := 0; i < len(crypt); i++ { - if i % block == 0 { - n++; - } - crypt[i] = plain[i] ^ n; - n++; - } - - for mode := 0; mode < len(readers); mode++ { - for frag := 0; frag < 2; frag++ { - test := fmt.Sprintf("block=%d mode=%d frag=%d maxio=%d", block, mode, frag, maxio); - s := newIncStream(block); - b.Reset(); - r := newXorReader(s, readers[mode](io.NewByteReader(crypt[0:maxio]))); - - // read from crypt in increasingly large chunks: 1, 1, 2, 4, 8, ... - // if frag == 1, move the 1 to the end to cause fragmentation. - if frag == 0 { - nn, err := io.Copyn(r, b, 1); - if err != nil { - t.Errorf("%s: first Copyn: %s", test, err); - continue; - } - } - for n := 1; n <= maxio/2; n *= 2 { - nn, err := io.Copyn(r, b, int64(n)); - if err != nil { - t.Errorf("%s: Copyn %d: %s", test, n, err); - } - } - - // check output - data := b.Data(); - crypt := crypt[0:maxio - frag]; - plain := plain[0:maxio - frag]; - if len(data) != len(plain) { - t.Errorf("%s: want %d bytes, got %d", test, len(plain), len(data)); - continue; - } - - if string(data) != string(plain) { - t.Errorf("%s: input=%x want %x got %x", test, crypt, plain, data); - } - } - } - } -} - -func TestXorReader(t *testing.T) { - // Do shorter I/O sizes first; they're easier to debug. - for n := 1; n <= 256 && !t.Failed(); n *= 2 { - testXorReader(t, n); - } -} - -// TODO(rsc): Test handling of writes after write errors. - diff --git a/src/lib/crypto/hmac/Makefile b/src/lib/crypto/hmac/Makefile deleted file mode 100644 index 1da3f58dd..000000000 --- a/src/lib/crypto/hmac/Makefile +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m >Makefile - -D=/crypto/ - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - hmac.$O\ - - -phases: a1 -_obj$D/hmac.a: phases - -a1: $(O1) - $(AR) grc _obj$D/hmac.a hmac.$O - rm -f $(O1) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/hmac.a - -$(O1): newpkg -$(O2): a1 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/hmac.a - -packages: _obj$D/hmac.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/hmac.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/hmac.a diff --git a/src/lib/crypto/hmac/hmac.go b/src/lib/crypto/hmac/hmac.go deleted file mode 100644 index a3f47ccc9..000000000 --- a/src/lib/crypto/hmac/hmac.go +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// The hmac package implements the Keyed-Hash Message Authentication Code (HMAC) -// as defined in U.S. Federal Information Processing Standards Publication 198. -// An HMAC is a cryptographic hash that uses a key to sign a message. -// The receiver verifies the hash by recomputing it using the same key. -package hmac - -import ( - "crypto/md5"; - "crypto/sha1"; - "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 []byte; - tmp []byte; - 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 { - h.tmpPad(0x5c); - sum := h.inner.Sum(); - for i, b := range sum { - h.tmp[padSize + i] = b; - } - h.inner.Reset(); - h.inner.Write(h.tmp); - return h.inner.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 and key. -func New(h hash.Hash, key []byte) hash.Hash { - if len(key) > padSize { - // If key is too big, hash it. - h.Write(key); - key = h.Sum(); - } - hm := new(hmac); - hm.inner = h; - hm.size = h.Size(); - hm.key = make([]byte, len(key)); - for i, k := range key { - hm.key[i] = k; - } - hm.tmp = make([]byte, padSize + hm.size); - 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); -} diff --git a/src/lib/crypto/hmac/hmac_test.go b/src/lib/crypto/hmac/hmac_test.go deleted file mode 100644 index 01e532d9f..000000000 --- a/src/lib/crypto/hmac/hmac_test.go +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package hmac - -// TODO(rsc): better test - -import ( - "hash"; - "crypto/hmac"; - "io"; - "fmt"; - "testing"; -) - -type hmacTest struct { - hash func([]byte) hash.Hash; - key []byte; - in []byte; - out string; -} - -// Tests from US FIPS 198 -// http://csrc.nist.gov/publications/fips/fips198/fips-198a.pdf -var hmacTests = []hmacTest { - hmacTest { - 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, - }, - io.StringBytes("Sample #1"), - "4f4ca3d5d68ba7cc0a1208c9c61e9c5da0403c0a", - }, - hmacTest { - NewSHA1, - []byte { - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, - 0x40, 0x41, 0x42, 0x43, - }, - io.StringBytes("Sample #2"), - "0922d3405faa3d194f82a45830737d5cc6c75d24", - }, - hmacTest { - 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, - }, - io.StringBytes("Sample #3"), - "bcf41eab8bb2d802f3d05caf7cb092ecf8d1a3aa", - }, - - // Test from Plan 9. - hmacTest { - NewMD5, - io.StringBytes("Jefe"), - io.StringBytes("what do ya want for nothing?"), - "750c783e6ab0b503eaa86e310a5db738", - } -} - -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; - } - sum := fmt.Sprintf("%x", h.Sum()); - if sum != tt.out { - t.Errorf("test %d.%d: have %s want %s\n", i, j, sum, tt.out); - } - - // Second iteration: make sure reset works. - h.Reset(); - } - } -} diff --git a/src/lib/crypto/md5/Makefile b/src/lib/crypto/md5/Makefile deleted file mode 100644 index b6c88d45a..000000000 --- a/src/lib/crypto/md5/Makefile +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m >Makefile - -D=/crypto/ - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - md5.$O\ - -O2=\ - md5block.$O\ - - -phases: a1 a2 -_obj$D/md5.a: phases - -a1: $(O1) - $(AR) grc _obj$D/md5.a md5.$O - rm -f $(O1) - -a2: $(O2) - $(AR) grc _obj$D/md5.a md5block.$O - rm -f $(O2) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/md5.a - -$(O1): newpkg -$(O2): a1 -$(O3): a2 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/md5.a - -packages: _obj$D/md5.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/md5.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/md5.a diff --git a/src/lib/crypto/md5/md5.go b/src/lib/crypto/md5/md5.go deleted file mode 100644 index cbc007f01..000000000 --- a/src/lib/crypto/md5/md5.go +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// This package implements the MD5 hash algorithm as defined in RFC 1321. -package md5 - -import ( - "hash"; - "os"; -) - -// The size of an MD5 checksum in bytes. -const Size = 16; - -const ( - _Chunk = 64; - - _Init0 = 0x67452301; - _Init1 = 0xEFCDAB89; - _Init2 = 0x98BADCFE; - _Init3 = 0x10325476; -) - -// digest represents the partial evaluation of a checksum. -type digest struct { - s [4]uint32; - x [_Chunk]byte; - nx int; - len uint64; -} - -func (d *digest) Reset() { - d.s[0] = _Init0; - d.s[1] = _Init1; - d.s[2] = _Init2; - d.s[3] = _Init3; - d.nx = 0; - d.len = 0; -} - -// New returns a Hash computing the SHA1 checksum. -func New() hash.Hash { - d := new(digest); - d.Reset(); - return d; -} - -func (d *digest) Size() int { - return Size; -} - -func _Block(dig *digest, p []byte) int - -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); - d.nx = 0; - } - p = p[n:len(p)]; - } - n := _Block(d, p); - p = p[n:len(p)]; - if len(p) > 0 { - for i := 0; i < len(p); i++ { - d.x[i] = p[i]; - } - d.nx = len(p); - } - return; -} - -func (d *digest) Sum() []byte { - // 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 { - panicln("oops"); - } - - p := make([]byte, 16); - j := 0; - for i := 0; i < 4; i++ { - s := d.s[i]; - p[j] = byte(s); j++; - p[j] = byte(s>>8); j++; - p[j] = byte(s>>16); j++; - p[j] = byte(s>>24); j++; - } - return p; -} - diff --git a/src/lib/crypto/md5/md5_test.go b/src/lib/crypto/md5/md5_test.go deleted file mode 100644 index f610f1143..000000000 --- a/src/lib/crypto/md5/md5_test.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2009 The Go Authors. 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"; - "crypto/md5"; - "io"; - "testing"; -) - -type md5Test struct { - out string; - in string; -} - -var golden = []md5Test { - md5Test{ "d41d8cd98f00b204e9800998ecf8427e", "" }, - md5Test{ "0cc175b9c0f1b6a831c399e269772661", "a" }, - md5Test{ "187ef4436122d1cc2f40dc2b92f0eba0", "ab" }, - md5Test{ "900150983cd24fb0d6963f7d28e17f72", "abc" }, - md5Test{ "e2fc714c4727ee9395f324cd2e7f331f", "abcd" }, - md5Test{ "ab56b4d92b40713acc5af89985d4b786", "abcde" }, - md5Test{ "e80b5017098950fc58aad83c8c14978e", "abcdef" }, - md5Test{ "7ac66c0f148de9519b8bd264312c4d64", "abcdefg" }, - md5Test{ "e8dc4081b13434b45189a720b77b6818", "abcdefgh" }, - md5Test{ "8aa99b1f439ff71293e95357bac6fd94", "abcdefghi" }, - md5Test{ "a925576942e94b2ef57a066101b48876", "abcdefghij" }, - md5Test{ "d747fc1719c7eacb84058196cfe56d57", "Discard medicine more than two years old." }, - md5Test{ "bff2dcb37ef3a44ba43ab144768ca837", "He who has a shady past knows that nice guys finish last." }, - md5Test{ "0441015ecb54a7342d017ed1bcfdbea5", "I wouldn't marry him with a ten foot pole." }, - md5Test{ "9e3cac8e9e9757a60c3ea391130d3689", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave" }, - md5Test{ "a0f04459b031f916a59a35cc482dc039", "The days of the digital watch are numbered. -Tom Stoppard" }, - md5Test{ "e7a48e0fe884faf31475d2a04b1362cc", "Nepal premier won't resign." }, - md5Test{ "637d2fe925c07c113800509964fb0e06", "For every action there is an equal and opposite government program." }, - md5Test{ "834a8d18d5c6562119cf4c7f5086cb71", "His money is twice tainted: 'taint yours and 'taint mine." }, - md5Test{ "de3a4d2fd6c73ec2db2abad23b444281", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977" }, - md5Test{ "acf203f997e2cf74ea3aff86985aefaf", "It's a tiny change to the code and not completely disgusting. - Bob Manchek" }, - md5Test{ "e1c1384cb4d2221dfdd7c795a4222c9a", "size: a.out: bad magic" }, - md5Test{ "c90f3ddecc54f34228c063d7525bf644", "The major problem is with sendmail. -Mark Horton" }, - md5Test{ "cdf7ab6c1fd49bd9933c43f3ea5af185", "Give me a rock, paper and scissors and I will move the world. CCFestoon" }, - md5Test{ "83bc85234942fc883c063cbd7f0ad5d0", "If the enemy is within range, then so are you." }, - md5Test{ "277cbe255686b48dd7e8f389394d9299", "It's well we cannot hear the screams/That we create in others' dreams." }, - md5Test{ "fd3fb0a7ffb8af16603f3d3af98f8e1f", "You remind me of a TV show, but that's all right: I watch it anyway." }, - md5Test{ "469b13a78ebf297ecda64d4723655154", "C is as portable as Stonehedge!!" }, - md5Test{ "63eb3a2f466410104731c4b037600110", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley" }, - md5Test{ "72c2ed7592debca1c90fc0100f931a2f", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule" }, - md5Test{ "132f7619d33b523b1d9e5bd8e0928355", "How can you write a big system without C++? -Paul Glick" }, -} - -func TestGolden(t *testing.T) { - for i := 0; i < len(golden); i++ { - g := golden[i]; - c := New(); - for j := 0; j < 2; j++ { - io.WriteString(c, g.in); - s := fmt.Sprintf("%x", c.Sum()); - if s != g.out { - t.Errorf("md5[%d](%s) = %s want %s", j, g.in, s, g.out); - t.FailNow(); - } - c.Reset(); - } - } -} - diff --git a/src/lib/crypto/md5/md5block.go b/src/lib/crypto/md5/md5block.go deleted file mode 100644 index 2776c8795..000000000 --- a/src/lib/crypto/md5/md5block.go +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright 2009 The Go 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 - -import "crypto/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; - - for i := 0; i < 16; i++ { - j := i*4; - X[i] = uint32(p[j]) | uint32(p[j+1])<<8 | uint32(p[j+2])<<16 | uint32(p[j+3])<<24; - } - - // 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). - - // Round 1. - for i := 0; i < 16; i++ { - x := i; - t := i; - s := shift1[i%4]; - f := ((c ^ d) & b) ^ d; - a += f + X[x] + table[t]; - a = a<>(32-s); - a += b; - a, b, c, d = d, a, b, c; - } - - // Round 2. - for i := 0; i < 16; i++ { - 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<>(32-s); - a += b; - a, b, c, d = d, a, b, c; - } - - // Round 3. - for i := 0; i < 16; i++ { - x := (5+3*i)%16; - t := 32+i; - s := shift3[i%4]; - h := b ^ c ^ d; - a += h + X[x] + table[t]; - a = a<>(32-s); - a += b; - a, b, c, d = d, a, b, c; - } - - // Round 4. - for i := 0; i < 16; i++ { - x := (7*i)%16; - s := shift4[i%4]; - t := 48+i; - ii := c ^ (b | ^d); - a += ii + X[x] + table[t]; - a = a<>(32-s); - a += b; - a, b, c, d = d, a, b, c; - } - - a += aa; - b += bb; - c += cc; - d += dd; - - p = p[_Chunk:len(p)]; - n += _Chunk; - } - - dig.s[0] = a; - dig.s[1] = b; - dig.s[2] = c; - dig.s[3] = d; - return n; -} diff --git a/src/lib/crypto/sha1/Makefile b/src/lib/crypto/sha1/Makefile deleted file mode 100644 index 03ffe4fd7..000000000 --- a/src/lib/crypto/sha1/Makefile +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m >Makefile - -D=/crypto/ - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - sha1.$O\ - -O2=\ - sha1block.$O\ - - -phases: a1 a2 -_obj$D/sha1.a: phases - -a1: $(O1) - $(AR) grc _obj$D/sha1.a sha1.$O - rm -f $(O1) - -a2: $(O2) - $(AR) grc _obj$D/sha1.a sha1block.$O - rm -f $(O2) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/sha1.a - -$(O1): newpkg -$(O2): a1 -$(O3): a2 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/sha1.a - -packages: _obj$D/sha1.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/sha1.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/sha1.a diff --git a/src/lib/crypto/sha1/sha1.go b/src/lib/crypto/sha1/sha1.go deleted file mode 100644 index a4cccd7a3..000000000 --- a/src/lib/crypto/sha1/sha1.go +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// This package implements the SHA1 hash algorithm as defined in RFC 3174. -package sha1 - -import ( - "hash"; - "os"; -) - -// The size of a SHA1 checksum in bytes. -const Size = 20; - -const ( - _Chunk = 64; - - _Init0 = 0x67452301; - _Init1 = 0xEFCDAB89; - _Init2 = 0x98BADCFE; - _Init3 = 0x10325476; - _Init4 = 0xC3D2E1F0; -) - -// digest represents the partial evaluation of a checksum. -type digest struct { - h [5]uint32; - x [_Chunk]byte; - nx int; - len uint64; -} - -func (d *digest) Reset() { - d.h[0] = _Init0; - d.h[1] = _Init1; - d.h[2] = _Init2; - d.h[3] = _Init3; - d.h[4] = _Init4; - d.nx = 0; - d.len = 0; -} - -// New returns a Hash computing the SHA1 checksum. -func New() hash.Hash { - d := new(digest); - d.Reset(); - return d; -} - -func (d *digest) Size() int { - return Size; -} - -func _Block(dig *digest, p []byte) int - -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); - d.nx = 0; - } - p = p[n:len(p)]; - } - n := _Block(d, p); - p = p[n:len(p)]; - if len(p) > 0 { - for i := 0; i < len(p); i++ { - d.x[i] = p[i]; - } - d.nx = len(p); - } - return; -} - -func (d *digest) Sum() []byte { - // 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 { - panicln("oops"); - } - - p := make([]byte, 20); - j := 0; - for i := 0; i < 5; i++ { - s := d.h[i]; - p[j] = byte(s>>24); j++; - p[j] = byte(s>>16); j++; - p[j] = byte(s>>8); j++; - p[j] = byte(s); j++; - } - return p; -} - diff --git a/src/lib/crypto/sha1/sha1_test.go b/src/lib/crypto/sha1/sha1_test.go deleted file mode 100644 index 381cc76ee..000000000 --- a/src/lib/crypto/sha1/sha1_test.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// SHA1 hash algorithm. See RFC 3174. - -package sha1 - -import ( - "fmt"; - "crypto/sha1"; - "io"; - "testing"; -) - -type sha1Test struct { - out string; - in string; -} - -var golden = []sha1Test { - sha1Test{ "da39a3ee5e6b4b0d3255bfef95601890afd80709", "" }, - sha1Test{ "86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", "a" }, - sha1Test{ "da23614e02469a0d7c7bd1bdab5c9c474b1904dc", "ab" }, - sha1Test{ "a9993e364706816aba3e25717850c26c9cd0d89d", "abc" }, - sha1Test{ "81fe8bfe87576c3ecb22426f8e57847382917acf", "abcd" }, - sha1Test{ "03de6c570bfe24bfc328ccd7ca46b76eadaf4334", "abcde" }, - sha1Test{ "1f8ac10f23c5b5bc1167bda84b833e5c057a77d2", "abcdef" }, - sha1Test{ "2fb5e13419fc89246865e7a324f476ec624e8740", "abcdefg" }, - sha1Test{ "425af12a0743502b322e93a015bcf868e324d56a", "abcdefgh" }, - sha1Test{ "c63b19f1e4c8b5f76b25c49b8b87f57d8e4872a1", "abcdefghi" }, - sha1Test{ "d68c19a0a345b7eab78d5e11e991c026ec60db63", "abcdefghij" }, - sha1Test{ "ebf81ddcbe5bf13aaabdc4d65354fdf2044f38a7", "Discard medicine more than two years old." }, - sha1Test{ "e5dea09392dd886ca63531aaa00571dc07554bb6", "He who has a shady past knows that nice guys finish last." }, - sha1Test{ "45988f7234467b94e3e9494434c96ee3609d8f8f", "I wouldn't marry him with a ten foot pole." }, - sha1Test{ "55dee037eb7460d5a692d1ce11330b260e40c988", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave" }, - sha1Test{ "b7bc5fb91080c7de6b582ea281f8a396d7c0aee8", "The days of the digital watch are numbered. -Tom Stoppard" }, - sha1Test{ "c3aed9358f7c77f523afe86135f06b95b3999797", "Nepal premier won't resign." }, - sha1Test{ "6e29d302bf6e3a5e4305ff318d983197d6906bb9", "For every action there is an equal and opposite government program." }, - sha1Test{ "597f6a540010f94c15d71806a99a2c8710e747bd", "His money is twice tainted: 'taint yours and 'taint mine." }, - sha1Test{ "6859733b2590a8a091cecf50086febc5ceef1e80", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977" }, - sha1Test{ "514b2630ec089b8aee18795fc0cf1f4860cdacad", "It's a tiny change to the code and not completely disgusting. - Bob Manchek" }, - sha1Test{ "c5ca0d4a7b6676fc7aa72caa41cc3d5df567ed69", "size: a.out: bad magic" }, - sha1Test{ "74c51fa9a04eadc8c1bbeaa7fc442f834b90a00a", "The major problem is with sendmail. -Mark Horton" }, - sha1Test{ "0b4c4ce5f52c3ad2821852a8dc00217fa18b8b66", "Give me a rock, paper and scissors and I will move the world. CCFestoon" }, - sha1Test{ "3ae7937dd790315beb0f48330e8642237c61550a", "If the enemy is within range, then so are you." }, - sha1Test{ "410a2b296df92b9a47412b13281df8f830a9f44b", "It's well we cannot hear the screams/That we create in others' dreams." }, - sha1Test{ "841e7c85ca1adcddbdd0187f1289acb5c642f7f5", "You remind me of a TV show, but that's all right: I watch it anyway." }, - sha1Test{ "163173b825d03b952601376b25212df66763e1db", "C is as portable as Stonehedge!!" }, - sha1Test{ "32b0377f2687eb88e22106f133c586ab314d5279", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley" }, - sha1Test{ "0885aaf99b569542fd165fa44e322718f4a984e0", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule" }, - sha1Test{ "6627d6904d71420b0bf3886ab629623538689f45", "How can you write a big system without C++? -Paul Glick" }, -} - -func TestGolden(t *testing.T) { - for i := 0; i < len(golden); i++ { - g := golden[i]; - c := New(); - for j := 0; j < 2; j++ { - io.WriteString(c, g.in); - s := fmt.Sprintf("%x", c.Sum()); - if s != g.out { - t.Errorf("sha1[%d](%s) = %s want %s", j, g.in, s, g.out); - t.FailNow(); - } - c.Reset(); - } - } -} - diff --git a/src/lib/crypto/sha1/sha1block.go b/src/lib/crypto/sha1/sha1block.go deleted file mode 100644 index 01ddd9506..000000000 --- a/src/lib/crypto/sha1/sha1block.go +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2009 The Go 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 - -import "crypto/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:len(p)]; - 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/lib/datafmt/Makefile b/src/lib/datafmt/Makefile deleted file mode 100644 index 1546faf7e..000000000 --- a/src/lib/datafmt/Makefile +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m >Makefile - -D= - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - datafmt.$O\ - -O2=\ - parser.$O\ - - -phases: a1 a2 -_obj$D/datafmt.a: phases - -a1: $(O1) - $(AR) grc _obj$D/datafmt.a datafmt.$O - rm -f $(O1) - -a2: $(O2) - $(AR) grc _obj$D/datafmt.a parser.$O - rm -f $(O2) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/datafmt.a - -$(O1): newpkg -$(O2): a1 -$(O3): a2 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/datafmt.a - -packages: _obj$D/datafmt.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/datafmt.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/datafmt.a diff --git a/src/lib/datafmt/datafmt.go b/src/lib/datafmt/datafmt.go deleted file mode 100644 index 0aedbbbb0..000000000 --- a/src/lib/datafmt/datafmt.go +++ /dev/null @@ -1,789 +0,0 @@ -// Copyright 2009 The Go 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 ( - "container/vector"; - "fmt"; - "go/token"; - "io"; - "os"; - "reflect"; - "runtime"; - "strconv"; - "strings"; -) - - -// ---------------------------------------------------------------------------- -// Format representation - -type State struct - -// 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 io.ByteBuffer; // current indentation - output io.ByteBuffer; // 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.Data()); - n += n1 + n2; - i0 = i + 1; - s.linePos.Offset = s.output.Len(); - s.linePos.Line++; - } - } - n3, _ := s.output.Write(data[i0 : len(data)]); - 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(); -} - - -// getField searches in val, which must be a struct, for a field -// with the given name. It returns the value and the embedded depth -// where it was found. -// -func getField(val reflect.Value, fieldname string) (reflect.Value, int) { - // do we have a struct in the first place? - if val.Kind() != reflect.StructKind { - return nil, 0; - } - - sval, styp := val.(reflect.StructValue), val.Type().(reflect.StructType); - - // look for field at the top level - for i := 0; i < styp.Len(); i++ { - name, typ, tag, offset := styp.Field(i); - if name == fieldname || name == "" && strings.HasSuffix(typ.Name(), "." + fieldname) /* anonymous field */ { - return sval.Field(i), 0; - } - } - - // look for field in anonymous fields - var field reflect.Value; - level := 1000; // infinity (no struct has that many levels) - for i := 0; i < styp.Len(); i++ { - name, typ, tag, offset := styp.Field(i); - if name == "" { - f, l := getField(sval.Field(i), fieldname); - // keep the most shallow field - if f != nil { - switch { - case l < level: - field, level = f, l; - case l == level: - // more than one field at the same level, - // possibly an error unless there is a more - // shallow field found later - field = nil; - } - } - } - } - - return field, level + 1; -} - - -// 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. -// -var defaultNames = map[int]string { - reflect.ArrayKind: "array", - reflect.BoolKind: "bool", - reflect.ChanKind: "chan", - reflect.DotDotDotKind: "ellipsis", - reflect.FloatKind: "float", - reflect.Float32Kind: "float32", - reflect.Float64Kind: "float64", - reflect.FuncKind: "func", - reflect.IntKind: "int", - reflect.Int16Kind: "int16", - reflect.Int32Kind: "int32", - reflect.Int64Kind: "int64", - reflect.Int8Kind: "int8", - reflect.InterfaceKind: "interface", - reflect.MapKind: "map", - reflect.PtrKind: "ptr", - reflect.StringKind: "string", - reflect.StructKind: "struct", - reflect.UintKind: "uint", - reflect.Uint16Kind: "uint16", - reflect.Uint32Kind: "uint32", - reflect.Uint64Kind: "uint64", - reflect.Uint8Kind: "uint8", - reflect.UintptrKind: "uintptr", -} - - -func typename(value reflect.Value) string { - name := value.Type().Name(); - if name == "" { - if defaultName, found := defaultNames[value.Kind()]; found { - name = defaultName; - } - } - return name; -} - - -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 : len(lit)]); - } 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.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.Sub(); - - case reflect.InterfaceValue: - if v.IsNil() { - return false; - } - value = v.Value(); - - 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().Name())); - } - - default: - // value is value of named field - field, _ := getField(value, 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().Name())); - } - value = field; - } - - // determine rule - ruleName := t.ruleName; - if ruleName == "" { - // no alternate rule name, value type determines rule - ruleName = typename(value) - } - 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.Data()[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 occured, 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 ...) ([]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() { - value := reflect.NewValue(args).(reflect.StructValue); - for i := 0; i < value.Len(); i++ { - fld := value.Field(i); - mark := s.save(); - if !s.eval(s.getFormat(typename(fld)), fld, 0) { // TODO is 0 index correct? - s.restore(mark); - } - } - errors <- nil; // no errors - }(); - - return s.output.Data(), <- errors; -} - - -// ---------------------------------------------------------------------------- -// 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 ...) (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 ...) (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 ...) string { - var buf io.ByteBuffer; - n, err := f.Fprint(&buf, nil, args); - if err != nil { - fmt.Fprintf(&buf, "--- Sprint(%s) failed: %v", fmt.Sprint(args), err); - } - return string(buf.Data()); -} diff --git a/src/lib/datafmt/datafmt_test.go b/src/lib/datafmt/datafmt_test.go deleted file mode 100644 index 788c013c6..000000000 --- a/src/lib/datafmt/datafmt_test.go +++ /dev/null @@ -1,375 +0,0 @@ -// Copyright 2009 The Go Authors. 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"; - "datafmt"; - "io"; - "os"; - "testing"; -) - - -func parse(t *testing.T, form string, fmap FormatterMap) Format { - f, err := Parse(io.StringBytes(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 ...) { - 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(io.StringBytes("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; float="#"`, fmap1); - verify(t, f, `# # #`, 0.0, 1.0, 2.0); - - f = parse(t, `float=@: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 ...) { - 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, `float ="%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 TestInterfaceTypes(t *testing.T) { - var i0 interface{}; - check(t, `interface="interface"`, `interface`, i0); - - i0 = "foo"; - check(t, `interface="interface"`, `interface`, i0); - check(t, `interface=*; string="%s"`, `foo`, i0); -} - - -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/lib/datafmt/parser.go b/src/lib/datafmt/parser.go deleted file mode 100644 index 0d597dcb5..000000000 --- a/src/lib/datafmt/parser.go +++ /dev/null @@ -1,447 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package datafmt - -import ( - "container/vector"; - "datafmt"; - "fmt"; - "go/scanner"; - "go/token"; - "io"; - "os"; - "strconv"; - "strings"; -) - -// ---------------------------------------------------------------------------- -// Error handling - -// Error describes an individual error. The position Pos, if valid, -// indicates the format source position the error relates to. The -// error is specified with the Msg string. -// -type Error struct { - Pos token.Position; - Msg string; -} - - -func (e *Error) String() string { - pos := ""; - if e.Pos.IsValid() { - pos = fmt.Sprintf("%d:%d: ", e.Pos.Line, e.Pos.Column); - } - return pos + e.Msg; -} - - -// An ErrorList is a list of errors encountered during parsing. -type ErrorList []*Error - - -// ErrorList implements SortInterface and the os.Error 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 { return p[i].Pos.Offset < p[j].Pos.Offset; } - - -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); -} - - -// ---------------------------------------------------------------------------- -// Parsing - -type parser struct { - errors vector.Vector; - scanner scanner.Scanner; - pos token.Position; // token position - tok token.Token; // one token look-ahead - lit []byte; // token literal - - packs map [string] string; // PackageName -> ImportPath - rules map [string] expr; // RuleName -> Expression -} - - -func (p *parser) next() { - p.pos, p.tok, p.lit = p.scanner.Scan(); - switch p.tok { - case token.CHAN, token.FUNC, token.INTERFACE, token.MAP, token.STRUCT: - // Go keywords for composite types are type names - // returned by reflect. Accept them as identifiers. - p.tok = token.IDENT; // p.lit is already set correctly - } -} - - -func (p *parser) init(src []byte) { - p.errors.Init(0); - p.scanner.Init(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); -} - - -// The parser implements scanner.Error. -func (p *parser) Error(pos token.Position, msg string) { - // Don't collect errors that are on the same line as the previous error - // in the hope to reduce the number of spurious errors due to incorrect - // parser synchronization. - if p.errors.Len() == 0 || p.errors.Last().(*Error).Pos.Line != pos.Line { - p.errors.Push(&Error{pos, msg}); - } -} - - -func (p *parser) errorExpected(pos token.Position, msg string) { - msg = "expected " + msg; - if pos.Offset == p.pos.Offset { - // the error happened at the current position; - // make the error message more specific - msg += ", found '" + p.tok.String() + "'"; - if p.tok.IsLiteral() { - msg += " " + string(p.lit); - } - } - p.Error(pos, msg); -} - - -func (p *parser) expect(tok token.Token) token.Position { - pos := p.pos; - if p.tok != tok { - p.errorExpected(pos, "'" + tok.String() + "'"); - } - p.next(); // make progress in any case - return pos; -} - - -func (p *parser) parseIdentifier() string { - name := string(p.lit); - p.expect(token.IDENT); - return name; -} - - -func (p *parser) parseTypeName() (string, bool) { - pos := p.pos; - name, isIdent := p.parseIdentifier(), true; - if p.tok == token.PERIOD { - // got a package name, lookup package - if importPath, found := p.packs[name]; found { - name = importPath; - } else { - p.Error(pos, "package not declared: " + name); - } - p.next(); - name, isIdent = name + "." + p.parseIdentifier(), false; - } - return name, isIdent; -} - - -// Parses a rule name and returns it. If the rule name is -// a package-qualified type name, the package name is resolved. -// The 2nd result value is true iff the rule name consists of a -// single identifier only (and thus could be a package name). -// -func (p *parser) parseRuleName() (string, bool) { - name, isIdent := "", false; - switch p.tok { - case token.IDENT: - name, isIdent = p.parseTypeName(); - case token.DEFAULT: - name = "default"; - p.next(); - case token.QUO: - name = "/"; - p.next(); - default: - p.errorExpected(p.pos, "rule name"); - p.next(); // make progress in any case - } - return name, isIdent; -} - - -func (p *parser) parseString() string { - s := ""; - if p.tok == token.STRING { - var err os.Error; - s, err = strconv.Unquote(string(p.lit)); - // Unquote may fail with an error, but only if the scanner found - // an illegal string in the first place. In this case the error - // has already been reported. - p.next(); - return s; - } else { - p.expect(token.STRING); - } - return s; -} - - -func (p *parser) parseLiteral() literal { - s := io.StringBytes(p.parseString()); - - // A string literal may contain %-format specifiers. To simplify - // and speed up printing of the literal, split it into segments - // that start with "%" possibly followed by a last segment that - // starts with some other character. - var list vector.Vector; - list.Init(0); - i0 := 0; - for i := 0; i < len(s); i++ { - if s[i] == '%' && i+1 < len(s) { - // the next segment starts with a % format - if i0 < i { - // the current segment is not empty, split it off - list.Push(s[i0 : i]); - i0 = i; - } - i++; // skip %; let loop skip over char after % - } - } - // the final segment may start with any character - // (it is empty iff the string is empty) - list.Push(s[i0 : len(s)]); - - // convert list into a literal - lit := make(literal, list.Len()); - for i := 0; i < list.Len(); i++ { - lit[i] = list.At(i).([]byte); - } - - return lit; -} - - -func (p *parser) parseField() expr { - var fname string; - switch p.tok { - case token.ILLEGAL: - if string(p.lit) != "@" { - return nil; - } - fname = "@"; - p.next(); - case token.MUL: - fname = "*"; - p.next(); - case token.IDENT: - fname = p.parseIdentifier(); - default: - return nil; - } - - var ruleName string; - if p.tok == token.COLON { - p.next(); - var _ bool; - ruleName, _ = p.parseRuleName(); - } - - return &field{fname, ruleName}; -} - - -func (p *parser) parseExpression() expr - -func (p *parser) parseOperand() (x expr) { - switch p.tok { - case token.STRING: - x = p.parseLiteral(); - - case token.LPAREN: - p.next(); - x = p.parseExpression(); - if p.tok == token.SHR { - p.next(); - x = &group{x, p.parseExpression()}; - } - p.expect(token.RPAREN); - - case token.LBRACK: - p.next(); - x = &option{p.parseExpression()}; - p.expect(token.RBRACK); - - case token.LBRACE: - p.next(); - x = p.parseExpression(); - var div expr; - if p.tok == token.QUO { - p.next(); - div = p.parseExpression(); - } - x = &repetition{x, div}; - p.expect(token.RBRACE); - - default: - x = p.parseField(); // may be nil - } - - return x; -} - - -func (p *parser) parseSequence() expr { - var list vector.Vector; - list.Init(0); - - for x := p.parseOperand(); x != nil; x = p.parseOperand() { - list.Push(x); - } - - // no need for a sequence if list.Len() < 2 - switch list.Len() { - case 0: return nil; - case 1: return list.At(0).(expr); - } - - // convert list into a sequence - seq := make(sequence, list.Len()); - for i := 0; i < list.Len(); i++ { - seq[i] = list.At(i).(expr); - } - return seq; -} - - -func (p *parser) parseExpression() expr { - var list vector.Vector; - list.Init(0); - - for { - x := p.parseSequence(); - if x != nil { - list.Push(x); - } - if p.tok != token.OR { - break; - } - p.next(); - } - - // no need for an alternatives if list.Len() < 2 - switch list.Len() { - case 0: return nil; - case 1: return list.At(0).(expr); - } - - // convert list into a alternatives - alt := make(alternatives, list.Len()); - for i := 0; i < list.Len(); i++ { - alt[i] = list.At(i).(expr); - } - return alt; -} - - -func (p *parser) parseFormat() { - for p.tok != token.EOF { - pos := p.pos; - - name, isIdent := p.parseRuleName(); - switch p.tok { - case token.STRING: - // package declaration - importPath := p.parseString(); - - // add package declaration - if !isIdent { - p.Error(pos, "illegal package name: " + name); - } else if _, found := p.packs[name]; !found { - p.packs[name] = importPath; - } else { - p.Error(pos, "package already declared: " + name); - } - - case token.ASSIGN: - // format rule - p.next(); - x := p.parseExpression(); - - // add rule - if _, found := p.rules[name]; !found { - p.rules[name] = x; - } else { - p.Error(pos, "format rule already declared: " + name); - } - - default: - p.errorExpected(p.pos, "package declaration or format rule"); - p.next(); // make progress in any case - } - - if p.tok == token.SEMICOLON { - p.next(); - } else { - break; - } - } - p.expect(token.EOF); -} - - -func remap(p *parser, name string) string { - i := strings.Index(name, "."); - if i >= 0 { - packageName, suffix := name[0 : i], name[i : len(name)]; - // 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(src []byte, fmap FormatterMap) (Format, os.Error) { - // parse source - var p parser; - p.init(src); - p.parseFormat(); - - // add custom formatters, if any - for name, form := range fmap { - name = remap(&p, name); - if t, found := p.rules[name]; !found { - p.rules[name] = &custom{name, form}; - } else { - var invalidPos token.Position; - p.Error(invalidPos, "formatter already declared: " + name); - } - } - - // convert errors list, if any - if p.errors.Len() > 0 { - errors := make(ErrorList, p.errors.Len()); - for i := 0; i < p.errors.Len(); i++ { - errors[i] = p.errors.At(i).(*Error); - } - return nil, errors; - } - - return p.rules, nil; -} diff --git a/src/lib/exec/Makefile b/src/lib/exec/Makefile deleted file mode 100644 index 679cc39c0..000000000 --- a/src/lib/exec/Makefile +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m >Makefile - -D= - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - exec.$O\ - - -phases: a1 -_obj$D/exec.a: phases - -a1: $(O1) - $(AR) grc _obj$D/exec.a exec.$O - rm -f $(O1) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/exec.a - -$(O1): newpkg -$(O2): a1 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/exec.a - -packages: _obj$D/exec.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/exec.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/exec.a diff --git a/src/lib/exec/exec.go b/src/lib/exec/exec.go deleted file mode 100644 index c2b7bdd59..000000000 --- a/src/lib/exec/exec.go +++ /dev/null @@ -1,228 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// The exec package runs external commands. -package exec - -import ( - "os"; - "strings"; -) - -// Arguments to Run. -const ( - DevNull = iota; - PassThrough; - Pipe; - MergeWithStdout; -) - -// A Cmd represents a running command. -// Stdin, Stdout, and Stderr are Files representing pipes -// connected to the running command's standard input, output, and error, -// or else nil, depending on the arguments to Run. -// Pid is the running command's operating system process ID. -type Cmd struct { - Stdin *os.File; - Stdout *os.File; - Stderr *os.File; - Pid int; -} - -// Given mode (DevNull, etc), return file for child -// and file to record in Cmd structure. -func modeToFiles(mode, fd int) (*os.File, *os.File, os.Error) { - switch mode { - case DevNull: - rw := os.O_WRONLY; - if fd == 0 { - rw = os.O_RDONLY; - } - f, err := os.Open("/dev/null", rw, 0); - return f, nil, err; - case PassThrough: - switch fd { - case 0: - return os.Stdin, nil, nil; - case 1: - return os.Stdout, nil, nil; - case 2: - return os.Stderr, nil, nil; - } - case Pipe: - r, w, err := os.Pipe(); - if err != nil { - return nil, nil, err; - } - if fd == 0 { - return r, w, nil; - } - return w, r, nil; - } - return nil, nil, os.EINVAL; -} - -// Run starts the binary prog running with -// arguments argv and environment envv. -// It returns a pointer to a new Cmd representing -// the command or an error. -// -// The parameters stdin, stdout, and stderr -// specify how to handle standard input, output, and error. -// The choices are DevNull (connect to /dev/null), -// PassThrough (connect to the current process's standard stream), -// Pipe (connect to an operating system pipe), and -// MergeWithStdout (only for standard error; use the same -// file descriptor as was used for standard output). -// If a parameter is Pipe, then the corresponding field (Stdin, Stdout, Stderr) -// of the returned Cmd is the other end of the pipe. -// Otherwise the field in Cmd is nil. -func Run(argv0 string, argv, envv []string, stdin, stdout, stderr int) (p *Cmd, err os.Error) -{ - p = new(Cmd); - var fd [3]*os.File; - - if fd[0], p.Stdin, err = modeToFiles(stdin, 0); err != nil { - goto Error; - } - if fd[1], p.Stdout, err = modeToFiles(stdout, 1); err != nil { - goto Error; - } - if stderr == MergeWithStdout { - p.Stderr = p.Stdout; - } else if fd[2], p.Stderr, err = modeToFiles(stderr, 2); err != nil { - goto Error; - } - - // Run command. - p.Pid, err = os.ForkExec(argv0, argv, envv, "", &fd); - if err != nil { - goto Error; - } - if fd[0] != os.Stdin { - fd[0].Close(); - } - if fd[1] != os.Stdout { - fd[1].Close(); - } - if fd[2] != os.Stderr && fd[2] != fd[1] { - fd[2].Close(); - } - return p, nil; - -Error: - if fd[0] != os.Stdin && fd[0] != nil { - fd[0].Close(); - } - if fd[1] != os.Stdout && fd[1] != nil { - fd[1].Close(); - } - if fd[2] != os.Stderr && fd[2] != nil && fd[2] != fd[1] { - fd[2].Close(); - } - if p.Stdin != nil { - p.Stdin.Close(); - } - if p.Stdout != nil { - p.Stdout.Close(); - } - if p.Stderr != nil { - p.Stderr.Close(); - } - return nil, err; -} - -// Wait waits for the running command p, -// returning the Waitmsg returned by os.Wait and an error. -// The options are passed through to os.Wait. -// Setting options to 0 waits for p to exit; -// other options cause Wait to return for other -// process events; see package os for details. -func (p *Cmd) Wait(options int) (*os.Waitmsg, os.Error) { - if p.Pid < 0 { - return nil, os.EINVAL; - } - w, err := os.Wait(p.Pid, options); - if w != nil && (w.Exited() || w.Signaled()) { - p.Pid = -1; - } - return w, err; -} - -// Close waits for the running command p to exit, -// if it hasn't already, and then closes the non-nil file descriptors -// p.Stdin, p.Stdout, and p.Stderr. -func (p *Cmd) Close() os.Error { - if p.Pid >= 0 { - // Loop on interrupt, but - // ignore other errors -- maybe - // caller has already waited for pid. - w, err := p.Wait(0); - for err == os.EINTR { - w, err = p.Wait(0); - } - } - - // Close the FDs that are still open. - var err os.Error; - if p.Stdin != nil && p.Stdin.Fd() >= 0 { - if err1 := p.Stdin.Close(); err1 != nil { - err = err1; - } - } - if p.Stdout != nil && p.Stdout.Fd() >= 0 { - if err1 := p.Stdout.Close(); err1 != nil && err != nil { - err = err1; - } - } - if p.Stderr != nil && p.Stderr != p.Stdout && p.Stderr.Fd() >= 0 { - if err1 := p.Stderr.Close(); err1 != nil && err != nil { - err = err1; - } - } - return err; -} - -func canExec(file string) bool{ - d, err := os.Stat(file); - if err != nil { - return false; - } - return d.IsRegular() && d.Permission() & 0111 != 0; -} - -// LookPath searches for an executable binary named file -// in the directories named by the PATH environment variable. -// If file contains a slash, it is tried directly and the PATH is not consulted. -// -// TODO(rsc): Does LookPath belong in os instead? -func LookPath(file string) (string, os.Error) { - // NOTE(rsc): I wish we could use the Plan 9 behavior here - // (only bypass the path if file begins with / or ./ or ../) - // but that would not match all the Unix shells. - - if strings.Index(file, "/") >= 0 { - if canExec(file) { - return file, nil; - } - return "", os.ENOENT; - } - pathenv, err := os.Getenv("PATH"); - if err != nil { - // Unix shell semantics: no $PATH means assume PATH="" - // (equivalent to PATH="."). - pathenv = ""; - } - for i, dir := range strings.Split(pathenv, ":") { - if dir == "" { - // Unix shell semantics: path element "" means "." - dir = "."; - } - if canExec(dir+"/"+file) { - return dir+"/"+file, nil; - } - } - return "", os.ENOENT; -} - diff --git a/src/lib/exec/exec_test.go b/src/lib/exec/exec_test.go deleted file mode 100644 index a1bb1f50e..000000000 --- a/src/lib/exec/exec_test.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package exec - -import ( - "exec"; - "io"; - "testing"; -) - -func TestRunCat(t *testing.T) { - cmd, err := exec.Run("/bin/cat", []string{"cat"}, nil, - exec.Pipe, exec.Pipe, exec.DevNull); - if err != nil { - t.Fatalf("opencmd /bin/cat: %v", err); - } - io.WriteString(cmd.Stdin, "hello, world\n"); - cmd.Stdin.Close(); - var buf [64]byte; - n, err1 := io.FullRead(cmd.Stdout, &buf); - if err1 != nil && err1 != io.ErrEOF { - t.Fatalf("reading from /bin/cat: %v", err1); - } - if string(buf[0:n]) != "hello, world\n" { - t.Fatalf("reading from /bin/cat: got %q", buf[0:n]); - } - if err1 = cmd.Close(); err1 != nil { - t.Fatalf("closing /bin/cat: %v", err1); - } -} - -func TestRunEcho(t *testing.T) { - cmd, err := Run("/bin/echo", []string{"echo", "hello", "world"}, nil, - exec.DevNull, exec.Pipe, exec.DevNull); - if err != nil { - t.Fatalf("opencmd /bin/echo: %v", err); - } - var buf [64]byte; - n, err1 := io.FullRead(cmd.Stdout, &buf); - if err1 != nil && err1 != io.ErrEOF { - t.Fatalf("reading from /bin/echo: %v", err1); - } - if string(buf[0:n]) != "hello world\n" { - t.Fatalf("reading from /bin/echo: got %q", buf[0:n]); - } - if err1 = cmd.Close(); err1 != nil { - t.Fatalf("closing /bin/echo: %v", err1); - } -} diff --git a/src/lib/exvar/Makefile b/src/lib/exvar/Makefile deleted file mode 100644 index a65a1ee6b..000000000 --- a/src/lib/exvar/Makefile +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m >Makefile - -D= - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - exvar.$O\ - - -phases: a1 -_obj$D/exvar.a: phases - -a1: $(O1) - $(AR) grc _obj$D/exvar.a exvar.$O - rm -f $(O1) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/exvar.a - -$(O1): newpkg -$(O2): a1 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/exvar.a - -packages: _obj$D/exvar.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/exvar.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/exvar.a diff --git a/src/lib/exvar/exvar.go b/src/lib/exvar/exvar.go deleted file mode 100644 index 6473f7af6..000000000 --- a/src/lib/exvar/exvar.go +++ /dev/null @@ -1,214 +0,0 @@ -// Copyright 2009 The Go 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 exvar package provides a standardized interface to public variables, -// such as operation counters in servers. It exposes these variables via -// HTTP at /debug/vars in JSON format. -package exvar - -import ( - "fmt"; - "http"; - "io"; - "log"; - "strconv"; - "sync"; -) - -// Var is an abstract type for all exported variables. -type Var interface { - String() string; -} - -// Int is a 64-bit integer variable, and 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; -} - -// Map is a string-to-Var map variable, and 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(io.ByteBuffer); - 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 string(b.Data()) -} - -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(); - if av, ok := v.m[key]; ok { - return av - } - return nil -} - -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); - } -} - -// TODO(rsc): Make sure map access in separate thread is safe. -func (v *Map) iterate(c chan<- KeyValue) { - for k, v := range v.m { - c <- KeyValue{ k, v }; - } - close(c); -} - -func (v *Map) Iter() <-chan KeyValue { - c := make(chan KeyValue); - go v.iterate(c); - return c -} - -// String is a string variable, and satisfies the Var interface. -type String struct { - s string; -} - -func (v *String) String() string { - return strconv.Quote(v.s) -} - -func (v *String) Set(value string) { - v.s = value; -} - -// IntFunc wraps a func() int64 to create a value that satisfies the Var interface. -// The function will be called each time the Var is evaluated. -type IntFunc func() int64; - -func (v IntFunc) String() string { - return strconv.Itoa64(v()) -} - - -// 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.Crash. -func Publish(name string, v Var) { - mutex.Lock(); - defer mutex.Unlock(); - if _, existing := vars[name]; existing { - log.Crash("Reuse of exported var name:", name); - } - vars[name] = v; -} - -// Get retrieves a named exported variable. -func Get(name string) Var { - if v, ok := vars[name]; ok { - return v - } - return nil -} - -// Convenience functions for creating new exported variables. - -func NewInt(name string) *Int { - v := new(Int); - 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 exvarHandler(c *http.Conn, req *http.Request) { - c.SetHeader("content-type", "application/json; charset=utf-8"); - fmt.Fprintf(c, "{\n"); - first := true; - for name, value := range vars { - if !first { - fmt.Fprintf(c, ",\n"); - } - first = false; - fmt.Fprintf(c, " %q: %s", name, value); - } - fmt.Fprintf(c, "\n}\n"); -} - -func init() { - http.Handle("/debug/vars", http.HandlerFunc(exvarHandler)); -} diff --git a/src/lib/exvar/exvar_test.go b/src/lib/exvar/exvar_test.go deleted file mode 100644 index 8b028bccb..000000000 --- a/src/lib/exvar/exvar_test.go +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package exvar - -import ( - "exvar"; - "fmt"; - "json"; - "testing"; -) - -func TestInt(t *testing.T) { - reqs := NewInt("requests"); - if reqs.i != 0 { - t.Errorf("reqs.i = %v, want 4", 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); - } -} - -func TestString(t *testing.T) { - name := NewString("my-name"); - if name.s != "" { - t.Errorf("name.s = %q, want \"\"", name.s) - } - - name.Set("Mike"); - if name.s != "Mike" { - t.Errorf("name.s = %q, want \"Mike\"", name.s) - } - - if s := name.String(); s != "\"Mike\"" { - t.Errorf("reqs.String() = %q, want \"\"Mike\"\"", s); - } -} - -func TestMapCounter(t *testing.T) { - colours := NewMap("bike-shed-colours"); - - colours.Add("red", 1); - colours.Add("red", 2); - colours.Add("blue", 4); - if x := colours.m["red"].(*Int).i; x != 3 { - t.Errorf("colours.m[\"red\"] = %v, want 3", x) - } - if x := colours.m["blue"].(*Int).i; x != 4 { - t.Errorf("colours.m[\"blue\"] = %v, want 4", x) - } - - // colours.String() should be '{"red":3, "blue":4}', - // though the order of red and blue could vary. - s := colours.String(); - j, ok, errtok := json.StringToJson(s); - if !ok { - t.Errorf("colours.String() isn't valid JSON: %v", errtok) - } - if j.Kind() != json.MapKind { - t.Error("colours.String() didn't produce a map.") - } - red := j.Get("red"); - if red.Kind() != json.NumberKind { - t.Error("red.Kind() is not a NumberKind.") - } - if x := red.Number(); x != 3 { - t.Error("red = %v, want 3", x) - } -} - -func TestIntFunc(t *testing.T) { - x := int(4); - ix := IntFunc(func() int64 { return int64(x) }); - if s := ix.String(); s != "4" { - t.Errorf("ix.String() = %v, want 4", s); - } - - x++; - if s := ix.String(); s != "5" { - t.Errorf("ix.String() = %v, want 5", s); - } -} diff --git a/src/lib/flag/Makefile b/src/lib/flag/Makefile deleted file mode 100644 index 466e19564..000000000 --- a/src/lib/flag/Makefile +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m >Makefile - -D= - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - flag.$O\ - - -phases: a1 -_obj$D/flag.a: phases - -a1: $(O1) - $(AR) grc _obj$D/flag.a flag.$O - rm -f $(O1) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/flag.a - -$(O1): newpkg -$(O2): a1 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/flag.a - -packages: _obj$D/flag.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/flag.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/flag.a diff --git a/src/lib/flag/flag.go b/src/lib/flag/flag.go deleted file mode 100644 index 63d649a9b..000000000 --- a/src/lib/flag/flag.go +++ /dev/null @@ -1,486 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* - The flag package implements command-line flag parsing. - - Usage: - - 1) Define flags using flag.String(), Bool(), Int(), etc. Example: - import flag "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") - } - - 2) After all flags are defined, call - flag.Parse() - to parse the command line into the defined flags. - - 3) Flags may then be used directly. If you're using the flags themselves, - they are all pointers; if you bind to variables, they're values. - print("ip has value ", *ip, "\n"); - print("flagvar has value ", flagvar, "\n"); - - 4) After parsing, flag.Arg(i) is the i'th argument after the flags. - Args are indexed from 0 up to flag.NArg(). - - Command line flag syntax: - -flag - -flag=x - -flag x - One or two minus signs may be used; they are equivalent. - - 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. - */ -package flag - -import ( - "fmt"; - "os"; - "strconv" -) - -// BUG: atob belongs elsewhere -func atob(str string) (value bool, ok bool) { - switch str { - case "1", "t", "T", "true", "TRUE", "True": - return true, true; - case "0", "f", "F", "false", "FALSE", "False": - return false, true - } - return false, false -} - -type ( - boolValue struct; - intValue struct; - int64Value struct; - uintValue struct; - uint64Value struct; - stringValue struct; -) - -// -- Bool Value -type boolValue struct { - p *bool; -} - -func newBoolValue(val bool, p *bool) *boolValue { - *p = val; - return &boolValue{p} -} - -func (b *boolValue) set(s string) bool { - v, ok := atob(s); - *b.p = v; - return ok -} - -func (b *boolValue) String() string { - return fmt.Sprintf("%v", *b.p) -} - -// -- Int Value -type intValue struct { - p *int; -} - -func newIntValue(val int, p *int) *intValue { - *p = val; - return &intValue{p} -} - -func (i *intValue) set(s string) bool { - v, err := strconv.Atoi(s); - *i.p = int(v); - return err == nil -} - -func (i *intValue) String() string { - return fmt.Sprintf("%v", *i.p) -} - -// -- Int64 Value -type int64Value struct { - p *int64; -} - -func newInt64Value(val int64, p *int64) *int64Value { - *p = val; - return &int64Value{p} -} - -func (i *int64Value) set(s string) bool { - v, err := strconv.Atoi64(s); - *i.p = v; - return err == nil; -} - -func (i *int64Value) String() string { - return fmt.Sprintf("%v", *i.p) -} - -// -- Uint Value -type uintValue struct { - p *uint; -} - -func newUintValue(val uint, p *uint) *uintValue { - *p = val; - return &uintValue{p} -} - -func (i *uintValue) set(s string) bool { - v, err := strconv.Atoui(s); - *i.p = uint(v); - return err == nil; -} - -func (i *uintValue) String() string { - return fmt.Sprintf("%v", *i.p) -} - -// -- uint64 Value -type uint64Value struct { - p *uint64; -} - -func newUint64Value(val uint64, p *uint64) *uint64Value { - *p = val; - return &uint64Value{p} -} - -func (i *uint64Value) set(s string) bool { - v, err := strconv.Atoui64(s); - *i.p = uint64(v); - return err == nil; -} - -func (i *uint64Value) String() string { - return fmt.Sprintf("%v", *i.p) -} - -// -- string Value -type stringValue struct { - p *string; -} - -func newStringValue(val string, p *string) *stringValue { - *p = val; - return &stringValue{p} -} - -func (s *stringValue) set(val string) bool { - *s.p = val; - return true; -} - -func (s *stringValue) String() string { - return fmt.Sprintf("%s", *s.p) -} - -// FlagValue is the interface to the dynamic value stored in a flag. -// (The default value is represented as a string.) -type FlagValue interface { - String() string; - set(string) bool; -} - -// A Flag represents the state of a flag. -type Flag struct { - Name string; // name as it appears on command line - Usage string; // help message - Value FlagValue; // value as set - DefValue string; // default value (as text); for usage message -} - -type allFlags struct { - actual map[string] *Flag; - formal map[string] *Flag; - first_arg int; // 0 is the program name, 1 is first arg -} - -var flags *allFlags = &allFlags{make(map[string] *Flag), make(map[string] *Flag), 1} - -// VisitAll visits the flags, calling fn for each. It visits all flags, even those not set. -func VisitAll(fn func(*Flag)) { - for k, f := range flags.formal { - fn(f) - } -} - -// Visit visits the flags, calling fn for each. It visits only those flags that have been set. -func Visit(fn func(*Flag)) { - for k, f := range flags.actual { - fn(f) - } -} - -// Lookup returns the Flag structure of the named flag, returning nil if none exists. -func Lookup(name string) *Flag { - f, ok := flags.formal[name]; - if !ok { - return nil - } - return f -} - -// Set sets the value of tne named flag. It returns true if the set succeeded; false if -// there is no such flag defined. -func Set(name, value string) bool { - f, ok := flags.formal[name]; - if !ok { - return false - } - ok = f.Value.set(value); - if !ok { - return false - } - flags.actual[name] = f; - return true; -} - -// PrintDefaults prints to standard error the default values of all defined flags. -func PrintDefaults() { - VisitAll(func(f *Flag) { - format := " -%s=%s: %s\n"; - if s, ok := f.Value.(*stringValue); ok { - // put quotes on the value - format = " -%s=%q: %s\n"; - } - fmt.Fprintf(os.Stderr, format, f.Name, f.DefValue, f.Usage); - }) -} - -// Usage prints to standard error a default usage message documenting all defined flags and -// then calls os.Exit(1). -func Usage() { - if len(os.Args) > 0 { - fmt.Fprintln(os.Stderr, "Usage of", os.Args[0] + ":"); - } else { - fmt.Fprintln(os.Stderr, "Usage:"); - } - PrintDefaults(); - os.Exit(1); -} - -func NFlag() int { - return len(flags.actual) -} - -// Arg returns the i'th command-line argument. Arg(0) is the first remaining argument -// after flags have been processed. -func Arg(i int) string { - i += flags.first_arg; - if i < 0 || i >= len(os.Args) { - return ""; - } - return os.Args[i] -} - -// NArg is the number of arguments remaining after flags have been processed. -func NArg() int { - return len(os.Args) - flags.first_arg -} - -// Args returns the non-flag command-line arguments. -func Args() []string { - return os.Args[flags.first_arg:len(os.Args)]; -} - -func add(name string, value FlagValue, usage string) { - // Remember the default value as a string; it won't change. - f := &Flag{name, usage, value, value.String()}; - dummy, alreadythere := flags.formal[name]; - if alreadythere { - print("flag redefined: ", name, "\n"); - panic("flag redefinition"); // Happens only if flags are declared with identical names - } - flags.formal[name] = f; -} - -// 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) { - add(name, newBoolValue(value, p), usage); -} - -// Bool defines a bool flag with specified name, default value, and usage string. -// The return value is the address of a bool variable that stores the value of the flag. -func Bool(name string, value bool, usage string) *bool { - p := new(bool); - BoolVar(p, name, value, usage); - return p; -} - -// IntVar defines an int flag with specified name, default value, and usage string. -// The argument p points to an int variable in which to store the value of the flag. -func IntVar(p *int, name string, value int, usage string) { - add(name, newIntValue(value, p), usage); -} - -// Int defines an int flag with specified name, default value, and usage string. -// The return value is the address of an int variable that stores the value of the flag. -func Int(name string, value int, usage string) *int { - p := new(int); - IntVar(p, name, value, usage); - return p; -} - -// Int64Var defines an int64 flag with specified name, default value, and usage string. -// The argument p points to an int64 variable in which to store the value of the flag. -func Int64Var(p *int64, name string, value int64, usage string) { - add(name, newInt64Value(value, p), usage); -} - -// Int64 defines an int64 flag with specified name, default value, and usage string. -// The return value is the address of an int64 variable that stores the value of the flag. -func Int64(name string, value int64, usage string) *int64 { - p := new(int64); - Int64Var(p, name, value, usage); - return p; -} - -// UintVar defines a uint flag with specified name, default value, and usage string. -// The argument p points to a uint variable in which to store the value of the flag. -func UintVar(p *uint, name string, value uint, usage string) { - add(name, newUintValue(value, p), usage); -} - -// Uint defines a uint flag with specified name, default value, and usage string. -// The return value is the address of a uint variable that stores the value of the flag. -func Uint(name string, value uint, usage string) *uint { - p := new(uint); - UintVar(p, name, value, usage); - return p; -} - -// Uint64Var defines a uint64 flag with specified name, default value, and usage string. -// The argument p points to a uint64 variable in which to store the value of the flag. -func Uint64Var(p *uint64, name string, value uint64, usage string) { - add(name, newUint64Value(value, p), usage); -} - -// Uint64 defines a uint64 flag with specified name, default value, and usage string. -// The return value is the address of a uint64 variable that stores the value of the flag. -func Uint64(name string, value uint64, usage string) *uint64 { - p := new(uint64); - Uint64Var(p, name, value, usage); - return p; -} - -// StringVar defines a string flag with specified name, default value, and usage string. -// The argument p points to a string variable in which to store the value of the flag. -func StringVar(p *string, name, value string, usage string) { - add(name, newStringValue(value, p), usage); -} - -// String defines a string flag with specified name, default value, and usage string. -// The return value is the address of a string variable that stores the value of the flag. -func String(name, value string, usage string) *string { - p := new(string); - StringVar(p, name, value, usage); - return p; -} - -func (f *allFlags) parseOne(index int) (ok bool, next int) -{ - s := os.Args[index]; - f.first_arg = index; // until proven otherwise - if len(s) == 0 { - return false, -1 - } - if s[0] != '-' { - return false, -1 - } - num_minuses := 1; - if len(s) == 1 { - return false, index - } - if s[1] == '-' { - num_minuses++; - if len(s) == 2 { // "--" terminates the flags - return false, index + 1 - } - } - name := s[num_minuses : len(s)]; - if len(name) == 0 || name[0] == '-' || name[0] == '=' { - print("bad flag syntax: ", s, "\n"); - Usage(); - } - - // it's a flag. does it have an argument? - has_value := false; - value := ""; - for i := 1; i < len(name); i++ { // equals cannot be first - if name[i] == '=' { - value = name[i+1 : len(name)]; - has_value = true; - name = name[0 : i]; - break; - } - } - flag, alreadythere := flags.actual[name]; - if alreadythere { - print("flag specified twice: -", name, "\n"); - Usage(); - } - m := flags.formal; - flag, alreadythere = m[name]; // BUG - if !alreadythere { - print("flag provided but not defined: -", name, "\n"); - Usage(); - } - if f, ok := flag.Value.(*boolValue); ok { // special case: doesn't need an arg - if has_value { - if !f.set(value) { - print("invalid boolean value ", value, " for flag: -", name, "\n"); - Usage(); - } - } else { - f.set("true") - } - } else { - // It must have a value, which might be the next argument. - if !has_value && index < len(os.Args)-1 { - // value is the next arg - has_value = true; - index++; - value = os.Args[index]; - } - if !has_value { - print("flag needs an argument: -", name, "\n"); - Usage(); - } - ok = flag.Value.set(value); - if !ok { - print("invalid value ", value, " for flag: -", name, "\n"); - Usage(); - } - } - flags.actual[name] = flag; - return true, index + 1 -} - -// Parse parses the command-line flags. Must be called after all flags are defined -// and before any are accessed by the program. -func Parse() { - for i := 1; i < len(os.Args); { - ok, next := flags.parseOne(i); - if next > 0 { - flags.first_arg = next; - i = next; - } - if !ok { - break - } - } -} diff --git a/src/lib/flag/flag_test.go b/src/lib/flag/flag_test.go deleted file mode 100644 index 0d83fcf81..000000000 --- a/src/lib/flag/flag_test.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package flag - -import ( - "flag"; - "fmt"; - "testing"; -) - -var ( - test_bool = flag.Bool("test_bool", false, "bool value"); - test_int = flag.Int("test_int", 0, "int value"); - test_int64 = flag.Int64("test_int64", 0, "int64 value"); - test_uint = flag.Uint("test_uint", 0, "uint value"); - test_uint64 = flag.Uint64("test_uint64", 0, "uint64 value"); - test_string = flag.String("test_string", "0", "string value"); -) - -func boolString(s string) string { - if s == "0" { - return "false" - } - return "true" -} - -func TestEverything(t *testing.T) { - m := make(map[string] *flag.Flag); - desired := "0"; - visitor := func(f *flag.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("flag.Visit: bad value", f.Value.String(), "for", f.Name); - } - } - }; - flag.VisitAll(visitor); - if len(m) != 6 { - t.Error("flag.VisitAll misses some flags"); - for k, v := range m { - t.Log(k, *v) - } - } - m = make(map[string] *flag.Flag); - flag.Visit(visitor); - if len(m) != 0 { - t.Errorf("flag.Visit sees unset flags"); - for k, v := range m { - t.Log(k, *v) - } - } - // Now set all flags - flag.Set("test_bool", "true"); - flag.Set("test_int", "1"); - flag.Set("test_int64", "1"); - flag.Set("test_uint", "1"); - flag.Set("test_uint64", "1"); - flag.Set("test_string", "1"); - desired = "1"; - flag.Visit(visitor); - if len(m) != 6 { - t.Error("flag.Visit fails after set"); - for k, v := range m { - t.Log(k, *v) - } - } -} diff --git a/src/lib/fmt/Makefile b/src/lib/fmt/Makefile deleted file mode 100644 index 5d0281a0c..000000000 --- a/src/lib/fmt/Makefile +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m >Makefile - -D= - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - format.$O\ - -O2=\ - print.$O\ - - -phases: a1 a2 -_obj$D/fmt.a: phases - -a1: $(O1) - $(AR) grc _obj$D/fmt.a format.$O - rm -f $(O1) - -a2: $(O2) - $(AR) grc _obj$D/fmt.a print.$O - rm -f $(O2) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/fmt.a - -$(O1): newpkg -$(O2): a1 -$(O3): a2 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/fmt.a - -packages: _obj$D/fmt.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/fmt.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/fmt.a diff --git a/src/lib/fmt/fmt_test.go b/src/lib/fmt/fmt_test.go deleted file mode 100644 index e8abc2f0d..000000000 --- a/src/lib/fmt/fmt_test.go +++ /dev/null @@ -1,247 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package fmt - -import ( - "fmt"; - "io"; - "math"; - "testing"; -) - -func TestFmtInterface(t *testing.T) { - var i1 interface{}; - i1 = "abc"; - s := fmt.Sprintf("%s", i1); - if s != "abc" { - t.Errorf(`fmt.Sprintf("%%s", empty("abc")) = %q want %q`, s, "abc"); - } -} - -type fmtTest struct { - fmt string; - val interface { }; - out string; -} - -const b32 uint32 = 1<<32 - 1 -const b64 uint64 = 1<<64 - 1 -var array = []int{1, 2, 3, 4, 5} -var iarray = []interface{}{1, "hello", 2.5, nil} - -var fmttests = []fmtTest{ - // basic string - fmtTest{ "%s", "abc", "abc" }, - fmtTest{ "%x", "abc", "616263" }, - fmtTest{ "%x", "xyz", "78797a" }, - fmtTest{ "%X", "xyz", "78797A" }, - fmtTest{ "%q", "abc", `"abc"` }, - - // basic bytes - fmtTest{ "%s", io.StringBytes("abc"), "abc" }, - fmtTest{ "%x", io.StringBytes("abc"), "616263" }, - fmtTest{ "% x", io.StringBytes("abc"), "61 62 63" }, - fmtTest{ "%x", io.StringBytes("xyz"), "78797a" }, - fmtTest{ "%X", io.StringBytes("xyz"), "78797A" }, - fmtTest{ "%q", io.StringBytes("abc"), `"abc"` }, - - // escaped strings - fmtTest{ "%#q", `abc`, "`abc`" }, - fmtTest{ "%#q", `"`, "`\"`" }, - fmtTest{ "1 %#q", `\n`, "1 `\\n`" }, - fmtTest{ "2 %#q", "\n", `2 "\n"` }, - fmtTest{ "%q", `"`, `"\""` }, - fmtTest{ "%q", "\a\b\f\r\n\t\v", `"\a\b\f\r\n\t\v"` }, - fmtTest{ "%q", "abc\xffdef", `"abc\xffdef"` }, - fmtTest{ "%q", "\u263a", `"\u263a"` }, - fmtTest{ "%q", "\U0010ffff", `"\U0010ffff"` }, - - // width - fmtTest{ "%5s", "abc", " abc" }, - fmtTest{ "%-5s", "abc", "abc " }, - fmtTest{ "%05s", "abc", "00abc" }, - - // integers - fmtTest{ "%d", 12345, "12345" }, - fmtTest{ "%d", -12345, "-12345" }, - fmtTest{ "%10d", 12345, " 12345" }, - fmtTest{ "%10d", -12345, " -12345" }, - fmtTest{ "%+10d", 12345, " +12345" }, - fmtTest{ "%010d", 12345, "0000012345" }, - fmtTest{ "%010d", -12345, "-000012345" }, - fmtTest{ "%-10d", 12345, "12345 " }, - fmtTest{ "%010.3d", 1, " 001" }, - fmtTest{ "%010.3d", -1, " -001" }, - fmtTest{ "%+d", 12345, "+12345" }, - fmtTest{ "%+d", -12345, "-12345" }, - fmtTest{ "% d", 12345, " 12345" }, - - // arrays - fmtTest{ "%v", array, "[1 2 3 4 5]" }, - fmtTest{ "%v", iarray, "[1 hello 2.5 ]" }, - fmtTest{ "%v", &array, "&[1 2 3 4 5]" }, - fmtTest{ "%v", &iarray, "&[1 hello 2.5 ]" }, - - // old test/fmt_test.go - fmtTest{ "%d", 1234, "1234" }, - fmtTest{ "%d", -1234, "-1234" }, - fmtTest{ "%d", uint(1234), "1234" }, - fmtTest{ "%d", uint32(b32), "4294967295" }, - fmtTest{ "%d", uint64(b64), "18446744073709551615" }, - fmtTest{ "%o", 01234, "1234" }, - fmtTest{ "%#o", 01234, "01234" }, - fmtTest{ "%o", uint32(b32), "37777777777" }, - fmtTest{ "%o", uint64(b64), "1777777777777777777777" }, - fmtTest{ "%x", 0x1234abcd, "1234abcd" }, - fmtTest{ "%#x", 0x1234abcd, "0x1234abcd" }, - fmtTest{ "%x", b32-0x1234567, "fedcba98" }, - fmtTest{ "%X", 0x1234abcd, "1234ABCD" }, - fmtTest{ "%X", b32-0x1234567, "FEDCBA98" }, - fmtTest{ "%#X", 0, "0X0" }, - fmtTest{ "%x", b64, "ffffffffffffffff" }, - fmtTest{ "%b", 7, "111" }, - fmtTest{ "%b", b64, "1111111111111111111111111111111111111111111111111111111111111111" }, - fmtTest{ "%e", float64(1), "1.000000e+00" }, - fmtTest{ "%e", float64(1234.5678e3), "1.234568e+06" }, - fmtTest{ "%e", float64(1234.5678e-8), "1.234568e-05" }, - fmtTest{ "%e", float64(-7), "-7.000000e+00" }, - fmtTest{ "%e", float64(-1e-9), "-1.000000e-09" }, - fmtTest{ "%f", float64(1234.5678e3), "1234567.800000" }, - fmtTest{ "%f", float64(1234.5678e-8), "0.000012" }, - fmtTest{ "%f", float64(-7), "-7.000000" }, - fmtTest{ "%f", float64(-1e-9), "-0.000000" }, - fmtTest{ "%g", float64(1234.5678e3), "1.2345678e+06" }, - fmtTest{ "%g", float32(1234.5678e3), "1.2345678e+06" }, - fmtTest{ "%g", float64(1234.5678e-8), "1.2345678e-05" }, - fmtTest{ "%g", float64(-7), "-7" }, - fmtTest{ "%g", float64(-1e-9), "-1e-09", }, - fmtTest{ "%g", float32(-1e-9), "-1e-09" }, - fmtTest{ "%c", 'x', "x" }, - fmtTest{ "%c", 0xe4, "ä" }, - fmtTest{ "%c", 0x672c, "本" }, - fmtTest{ "%c", '日', "日" }, - fmtTest{ "%20.8d", 1234, " 00001234" }, - fmtTest{ "%20.8d", -1234, " -00001234" }, - fmtTest{ "%20d", 1234, " 1234" }, - fmtTest{ "%-20.8d", 1234, "00001234 " }, - fmtTest{ "%-20.8d", -1234, "-00001234 " }, - fmtTest{ "%-#20.8x", 0x1234abc, "0x01234abc " }, - fmtTest{ "%-#20.8X", 0x1234abc, "0X01234ABC " }, - fmtTest{ "%-#20.8o", 01234, "00001234 " }, - fmtTest{ "%.20b", 7, "00000000000000000111" }, - fmtTest{ "%20.5s", "qwertyuiop", " qwert" }, - fmtTest{ "%.5s", "qwertyuiop", "qwert" }, - fmtTest{ "%-20.5s", "qwertyuiop", "qwert " }, - fmtTest{ "%20c", 'x', " x" }, - fmtTest{ "%-20c", 'x', "x " }, - fmtTest{ "%20.6e", 1.2345e3, " 1.234500e+03" }, - fmtTest{ "%20.6e", 1.2345e-3, " 1.234500e-03" }, - fmtTest{ "%20e", 1.2345e3, " 1.234500e+03" }, - fmtTest{ "%20e", 1.2345e-3, " 1.234500e-03" }, - fmtTest{ "%20.8e", 1.2345e3, " 1.23450000e+03" }, - fmtTest{ "%20f", float64(1.23456789e3), " 1234.567890" }, - fmtTest{ "%20f", float64(1.23456789e-3), " 0.001235" }, - fmtTest{ "%20f", float64(12345678901.23456789), " 12345678901.234568" }, - fmtTest{ "%-20f", float64(1.23456789e3), "1234.567890 " }, - fmtTest{ "%20.8f", float64(1.23456789e3), " 1234.56789000" }, - fmtTest{ "%20.8f", float64(1.23456789e-3), " 0.00123457" }, - fmtTest{ "%g", float64(1.23456789e3), "1234.56789" }, - fmtTest{ "%g", float64(1.23456789e-3), "0.00123456789" }, - fmtTest{ "%g", float64(1.23456789e20), "1.23456789e+20" }, - fmtTest{ "%20e", math.Inf(1), " +Inf" }, - fmtTest{ "%-20f", math.Inf(-1), "-Inf " }, - fmtTest{ "%20g", math.NaN(), " NaN" }, -} - -func TestSprintf(t *testing.T) { - for i := 0; i < len(fmttests); i++ { - tt := fmttests[i]; - s := fmt.Sprintf(tt.fmt, tt.val); - if s != tt.out { - if ss, ok := tt.val.(string); ok { - // Don't requote the already-quoted strings. - // It's too confusing to read the errors. - t.Errorf("fmt.Sprintf(%q, %q) = %s want %s", tt.fmt, tt.val, s, tt.out); - } else { - t.Errorf("fmt.Sprintf(%q, %v) = %q want %q", tt.fmt, tt.val, s, tt.out); - } - } - } -} - -type flagPrinter struct { } -func (*flagPrinter) Format(f fmt.Formatter, c int) { - s := "%"; - for i := 0; i < 128; i++ { - if f.Flag(i) { - s += string(i); - } - } - if w, ok := f.Width(); ok { - s += fmt.Sprintf("%d", w); - } - if p, ok := f.Precision(); ok { - s += fmt.Sprintf(".%d", p); - } - s += string(c); - io.WriteString(f, "["+s+"]"); -} - -type flagTest struct { - in string; - out string; -} - -var flagtests = []flagTest { - flagTest{ "%a", "[%a]" }, - flagTest{ "%-a", "[%-a]" }, - flagTest{ "%+a", "[%+a]" }, - flagTest{ "%#a", "[%#a]" }, - flagTest{ "% a", "[% a]" }, - flagTest{ "%0a", "[%0a]" }, - flagTest{ "%1.2a", "[%1.2a]" }, - flagTest{ "%-1.2a", "[%-1.2a]" }, - flagTest{ "%+1.2a", "[%+1.2a]" }, - flagTest{ "%-+1.2a", "[%+-1.2a]" }, - flagTest{ "%-+1.2abc", "[%+-1.2a]bc" }, - flagTest{ "%-1.2abc", "[%-1.2a]bc" }, -} - -func TestFlagParser(t *testing.T) { - var flagprinter flagPrinter; - for i := 0; i < len(flagtests); i++ { - tt := flagtests[i]; - s := fmt.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; - type Test struct { - fmt string; - out string; - } - var tests = []Test { - Test{ "%v", "{abc def 123}" }, - Test{ "%+v", "{a=abc b=def c=123}" }, - }; - for i := 0; i < len(tests); i++ { - tt := tests[i]; - out := fmt.Sprintf(tt.fmt, s); - if out != tt.out { - t.Errorf("Sprintf(%q, &s) = %q, want %q", tt.fmt, out, tt.out); - } - } -} diff --git a/src/lib/fmt/format.go b/src/lib/fmt/format.go deleted file mode 100644 index 3cd492980..000000000 --- a/src/lib/fmt/format.go +++ /dev/null @@ -1,533 +0,0 @@ -// Copyright 2009 The Go Authors. 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 ( - "strconv"; -) - - -const nByte = 64; -const nPows10 = 160; - -var ldigits string = "0123456789abcdef" // var not const because we take its address -var udigits string = "0123456789ABCDEF" - -/* - Fmt is the raw formatter used by Printf etc. Not meant for normal use. - See print.go for a more palatable interface. - - The model is to accumulate operands into an internal buffer and then - retrieve the buffer in one hit using Str(), Putnl(), etc. The formatting - methods return ``self'' so the operations can be chained. - - f := fmt.New(); - print(f.Fmt_d(1234).Fmt_s("\n").Str()); // create string, print it - f.Fmt_d(-1234).Fmt_s("\n").Put(); // print string - f.Fmt_ud(1<<63).Putnl(); // print string with automatic newline -*/ -type Fmt struct { - buf string; - wid int; - wid_present bool; - prec int; - prec_present bool; - // flags - minus bool; - plus bool; - sharp bool; - space bool; - zero bool; -} - -func (f *Fmt) clearflags() { - f.wid = 0; - f.wid_present = false; - f.prec = 0; - f.prec_present = false; - f.minus = false; - f.plus = false; - f.sharp = false; - f.space = false; - f.zero = false; -} - -func (f *Fmt) clearbuf() { - f.buf = ""; -} - -func (f *Fmt) init() { - f.clearbuf(); - f.clearflags(); -} - -// New returns a new initialized Fmt -func New() *Fmt { - f := new(Fmt); - f.init(); - return f; -} - -// Str returns the buffered contents as a string and resets the Fmt. -func (f *Fmt) Str() string { - s := f.buf; - f.clearbuf(); - f.clearflags(); - f.buf = ""; - return s; -} - -// Put writes the buffered contents to stdout and resets the Fmt. -func (f *Fmt) Put() { - print(f.buf); - f.clearbuf(); - f.clearflags(); -} - -// Putnl writes the buffered contents to stdout, followed by a newline, and resets the Fmt. -func (f *Fmt) Putnl() { - print(f.buf, "\n"); - f.clearbuf(); - f.clearflags(); -} - -// Wp sets the width and precision for formatting the next item. -func (f *Fmt) Wp(w, p int) *Fmt { - f.wid_present = true; - f.wid = w; - f.prec_present = true; - f.prec = p; - return f; -} - -// P sets the precision for formatting the next item. -func (f *Fmt) P(p int) *Fmt { - f.prec_present = true; - f.prec = p; - return f; -} - -// W sets the width for formatting the next item. -func (f *Fmt) W(x int) *Fmt { - f.wid_present = true; - f.wid = x; - return f; -} - -// append s to buf, padded on left (w > 0) or right (w < 0 or f.minus) -// padding is in bytes, not characters (agrees with ANSIC C, not Plan 9 C) -func (f *Fmt) pad(s string) { - if f.wid_present && f.wid != 0 { - left := !f.minus; - w := f.wid; - if w < 0 { - left = false; - w = -w; - } - w -= len(s); - padchar := byte(' '); - if left && f.zero { - padchar = '0'; - } - if w > 0 { - if w > nByte { - w = nByte; - } - buf := make([]byte, w); - for i := 0; i < w; i++ { - buf[i] = padchar; - } - if left { - s = string(buf) + s; - } else { - s = s + string(buf); - } - } - } - f.buf += s; -} - -// format val into buf, ending at buf[i]. (printing is easier right-to-left; -// that's why the bidi languages are right-to-left except for numbers. wait, -// never mind.) val is known to be unsigned. we could make things maybe -// marginally faster by splitting the 32-bit case out into a separate function -// but it's not worth the duplication, so val has 64 bits. -func putint(buf *[nByte]byte, i int, base, val uint64, digits *string) int { - 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) *Fmt { - if v { - f.pad("true"); - } else { - f.pad("false"); - } - f.clearflags(); - return f; -} - -// integer; interprets prec but not wid. -func (f *Fmt) integer(a int64, base uint, is_signed bool, digits *string) string { - var buf [nByte]byte; - negative := is_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.prec_present { - prec = f.prec; - f.zero = false; - } else if f.zero && f.wid_present && !f.minus && f.wid > 0{ - prec = f.wid; - if negative || f.plus || f.space { - prec--; // leave room for sign - } - } - - i := putint(&buf, nByte-1, uint64(base), uint64(a), digits); - for i > 0 && prec > (nByte-1-i) { - buf[i] = '0'; - i--; - } - - if f.sharp { - switch base { - case 8: - if buf[i+1] != '0' { - buf[i] = '0'; - i--; - } - case 16: - buf[i] = 'x' + digits[10]-'a'; - i--; - buf[i] = '0'; - i--; - } - } - - if negative { - buf[i] = '-'; - i--; - } else if f.plus { - buf[i] = '+'; - i--; - } else if f.space { - buf[i] = ' '; - i--; - } - return string(buf[i+1:nByte]); -} - -// Fmt_d64 formats an int64 in decimal. -func (f *Fmt) Fmt_d64(v int64) *Fmt { - f.pad(f.integer(v, 10, true, &ldigits)); - f.clearflags(); - return f; -} - -// Fmt_d32 formats an int32 in decimal. -func (f *Fmt) Fmt_d32(v int32) *Fmt { - return f.Fmt_d64(int64(v)); -} - -// Fmt_d formats an int in decimal. -func (f *Fmt) Fmt_d(v int) *Fmt { - return f.Fmt_d64(int64(v)); -} - -// Fmt_ud64 formats a uint64 in decimal. -func (f *Fmt) Fmt_ud64(v uint64) *Fmt { - f.pad(f.integer(int64(v), 10, false, &ldigits)); - f.clearflags(); - return f; -} - -// Fmt_ud32 formats a uint32 in decimal. -func (f *Fmt) Fmt_ud32(v uint32) *Fmt { - return f.Fmt_ud64(uint64(v)); -} - -// Fmt_ud formats a uint in decimal. -func (f *Fmt) Fmt_ud(v uint) *Fmt { - return f.Fmt_ud64(uint64(v)); -} - -// Fmt_x64 formats an int64 in hexadecimal. -func (f *Fmt) Fmt_x64(v int64) *Fmt { - f.pad(f.integer(v, 16, true, &ldigits)); - f.clearflags(); - return f; -} - -// Fmt_x32 formats an int32 in hexadecimal. -func (f *Fmt) Fmt_x32(v int32) *Fmt { - return f.Fmt_x64(int64(v)); -} - -// Fmt_x formats an int in hexadecimal. -func (f *Fmt) Fmt_x(v int) *Fmt { - return f.Fmt_x64(int64(v)); -} - -// Fmt_ux64 formats a uint64 in hexadecimal. -func (f *Fmt) Fmt_ux64(v uint64) *Fmt { - f.pad(f.integer(int64(v), 16, false, &ldigits)); - f.clearflags(); - return f; -} - -// Fmt_ux32 formats a uint32 in hexadecimal. -func (f *Fmt) Fmt_ux32(v uint32) *Fmt { - return f.Fmt_ux64(uint64(v)); -} - -// Fmt_ux formats a uint in hexadecimal. -func (f *Fmt) Fmt_ux(v uint) *Fmt { - return f.Fmt_ux64(uint64(v)); -} - -// Fmt_X64 formats an int64 in upper case hexadecimal. -func (f *Fmt) Fmt_X64(v int64) *Fmt { - f.pad(f.integer(v, 16, true, &udigits)); - f.clearflags(); - return f; -} - -// Fmt_X32 formats an int32 in upper case hexadecimal. -func (f *Fmt) Fmt_X32(v int32) *Fmt { - return f.Fmt_X64(int64(v)); -} - -// Fmt_X formats an int in upper case hexadecimal. -func (f *Fmt) Fmt_X(v int) *Fmt { - return f.Fmt_X64(int64(v)); -} - -// Fmt_uX64 formats a uint64 in upper case hexadecimal. -func (f *Fmt) Fmt_uX64(v uint64) *Fmt { - f.pad(f.integer(int64(v), 16, false, &udigits)); - f.clearflags(); - return f; -} - -// Fmt_uX32 formats a uint32 in upper case hexadecimal. -func (f *Fmt) Fmt_uX32(v uint32) *Fmt { - return f.Fmt_uX64(uint64(v)); -} - -// Fmt_uX formats a uint in upper case hexadecimal. -func (f *Fmt) Fmt_uX(v uint) *Fmt { - return f.Fmt_uX64(uint64(v)); -} - -// Fmt_o64 formats an int64 in octal. -func (f *Fmt) Fmt_o64(v int64) *Fmt { - f.pad(f.integer(v, 8, true, &ldigits)); - f.clearflags(); - return f; -} - -// Fmt_o32 formats an int32 in octal. -func (f *Fmt) Fmt_o32(v int32) *Fmt { - return f.Fmt_o64(int64(v)); -} - -// Fmt_o formats an int in octal. -func (f *Fmt) Fmt_o(v int) *Fmt { - return f.Fmt_o64(int64(v)); -} - -// Fmt_uo64 formats a uint64 in octal. -func (f *Fmt) Fmt_uo64(v uint64) *Fmt { - f.pad(f.integer(int64(v), 8, false, &ldigits)); - f.clearflags(); - return f; -} - -// Fmt_uo32 formats a uint32 in octal. -func (f *Fmt) Fmt_uo32(v uint32) *Fmt { - return f.Fmt_uo64(uint64(v)); -} - -// Fmt_uo formats a uint in octal. -func (f *Fmt) Fmt_uo(v uint) *Fmt { - return f.Fmt_uo64(uint64(v)); -} - -// Fmt_b64 formats a uint64 in binary. -func (f *Fmt) Fmt_b64(v uint64) *Fmt { - f.pad(f.integer(int64(v), 2, false, &ldigits)); - f.clearflags(); - return f; -} - -// Fmt_b32 formats a uint32 in binary. -func (f *Fmt) Fmt_b32(v uint32) *Fmt { - return f.Fmt_b64(uint64(v)); -} - -// Fmt_b formats a uint in binary. -func (f *Fmt) Fmt_b(v uint) *Fmt { - return f.Fmt_b64(uint64(v)); -} - -// Fmt_c formats a Unicode character. -func (f *Fmt) Fmt_c(v int) *Fmt { - f.pad(string(v)); - f.clearflags(); - return f; -} - -// Fmt_s formats a string. -func (f *Fmt) Fmt_s(s string) *Fmt { - if f.prec_present { - if f.prec < len(s) { - s = s[0:f.prec]; - } - } - f.pad(s); - f.clearflags(); - return f; -} - -// Fmt_sx formats a string as a hexadecimal encoding of its bytes. -func (f *Fmt) Fmt_sx(s string) *Fmt { - 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.pad(t); - f.clearflags(); - return f; -} - -// Fmt_sX formats a string as an uppercase hexadecimal encoding of its bytes. -func (f *Fmt) Fmt_sX(s string) *Fmt { - t := ""; - for i := 0; i < len(s); i++ { - v := s[i]; - t += string(udigits[v>>4]); - t += string(udigits[v&0xF]); - } - f.pad(t); - f.clearflags(); - return f; -} - -// Fmt_q formats a string as a double-quoted, escaped Go string constant. -func (f *Fmt) Fmt_q(s string) *Fmt { - var quoted string; - if f.sharp && strconv.CanBackquote(s) { - quoted = "`"+s+"`"; - } else { - quoted = strconv.Quote(s); - } - f.pad(quoted); - f.clearflags(); - return f; -} - -// floating-point - -func doPrec(f *Fmt, def int) int { - if f.prec_present { - return f.prec; - } - return def; -} - -func fmtString(f *Fmt, s string) *Fmt { - f.pad(s); - f.clearflags(); - return f; -} - -// Fmt_e64 formats a float64 in the form -1.23e+12. -func (f *Fmt) Fmt_e64(v float64) *Fmt { - return fmtString(f, strconv.Ftoa64(v, 'e', doPrec(f, 6))); -} - -// Fmt_f64 formats a float64 in the form -1.23. -func (f *Fmt) Fmt_f64(v float64) *Fmt { - return fmtString(f, 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) *Fmt { - return fmtString(f, 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) *Fmt { - return fmtString(f, 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) *Fmt { - return fmtString(f, strconv.Ftoa32(v, 'e', doPrec(f, 6))); -} - -// Fmt_f32 formats a float32 in the form -1.23. -func (f *Fmt) Fmt_f32(v float32) *Fmt { - return fmtString(f, 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) *Fmt { - return fmtString(f, 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) *Fmt { - return fmtString(f, strconv.Ftoa32(v, 'b', 0)); -} - -// float -func (x *Fmt) f(a float) *Fmt { - if strconv.FloatSize == 32 { - return x.Fmt_f32(float32(a)) - } - return x.Fmt_f64(float64(a)) -} - -func (x *Fmt) e(a float) *Fmt { - if strconv.FloatSize == 32 { - return x.Fmt_e32(float32(a)) - } - return x.Fmt_e64(float64(a)) -} - -func (x *Fmt) g(a float) *Fmt { - if strconv.FloatSize == 32 { - return x.Fmt_g32(float32(a)) - } - return x.Fmt_g64(float64(a)) -} - -func (x *Fmt) fb(a float) *Fmt { - if strconv.FloatSize == 32 { - return x.Fmt_fb32(float32(a)) - } - return x.Fmt_fb64(float64(a)) -} diff --git a/src/lib/fmt/print.go b/src/lib/fmt/print.go deleted file mode 100644 index 66174c74b..000000000 --- a/src/lib/fmt/print.go +++ /dev/null @@ -1,705 +0,0 @@ -// Copyright 2009 The Go Authors. 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. Because of reflection knowledge it does not need -// to be told about sizes and signedness (no %llud etc. - just %d). -// Still to do: document the formats properly. For now, like C but: -// - don't need l or u flags - type of integer tells that. -// - %v prints any value using its native format. -// - for each Printf-like fn, there is also a Print fn that takes no format -// and is equivalent to saying %v for every operand. -// - another variant Println inserts blanks and appends a newline. -// - if an operand implements method String() that method will -// be used for %v, %s, or Print etc. -// - if an operand implements interface Formatter, that interface can -// be used for fine control of formatting. -package fmt - - -import ( - "fmt"; - "io"; - "os"; - "reflect"; - "utf8"; -) - -// Formatter 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 Formatter 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; -} - -// Format is the interface implemented by objects with a custom formatter. -// The implementation of Format may call Sprintf or Fprintf(f) etc. -// to generate its output. -type Format interface { - Format(f Formatter, c int); -} - -// String represents any object being printed that has a String() method that -// returns a string, which defines the ``native'' format for that object. -// Any such object will be printed using that method if passed -// as operand to a %s or %v format or to an unformatted printer such as Print. -type Stringer interface { - String() string -} - -const runeSelf = utf8.RuneSelf -const allocSize = 32 - -type pp struct { - n int; - buf []byte; - fmt *Fmt; -} - -func newPrinter() *pp { - p := new(pp); - p.fmt = fmt.New(); - return p; -} - -func (p *pp) Width() (wid int, ok bool) { - return p.fmt.wid, p.fmt.wid_present -} - -func (p *pp) Precision() (prec int, ok bool) { - return p.fmt.prec, p.fmt.prec_present -} - -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) ensure(n int) { - if len(p.buf) < n { - newn := allocSize + len(p.buf); - if newn < n { - newn = n + allocSize - } - b := make([]byte, newn); - for i := 0; i < p.n; i++ { - b[i] = p.buf[i]; - } - p.buf = b; - } -} - -func (p *pp) addstr(s string) { - n := len(s); - p.ensure(p.n + n); - for i := 0; i < n; i++ { - p.buf[p.n] = s[i]; - p.n++; - } -} - -func (p *pp) addbytes(b []byte, start, end int) { - p.ensure(p.n + end-start); - for i := start; i < end; i++ { - p.buf[p.n] = b[i]; - p.n++; - } -} - -func (p *pp) add(c int) { - p.ensure(p.n + 1); - if c < runeSelf { - p.buf[p.n] = byte(c); - p.n++; - } else { - p.addstr(string(c)); - } -} - -// Implement Write so we can call fprintf on a P, for -// recursive use in custom verbs. -func (p *pp) Write(b []byte) (ret int, err os.Error) { - p.addbytes(b, 0, len(b)); - return len(b), nil; -} - -func (p *pp) doprintf(format string, v reflect.StructValue); -func (p *pp) doprint(v reflect.StructValue, addspace, addnewline bool); - -// These routines end in 'f' and take a format string. - -// Fprintf formats according to a format specifier and writes to w. -func Fprintf(w io.Writer, format string, a ...) (n int, error os.Error) { - v := reflect.NewValue(a).(reflect.StructValue); - p := newPrinter(); - p.doprintf(format, v); - n, error = w.Write(p.buf[0:p.n]); - return n, error; -} - -// Printf formats according to a format specifier and writes to standard output. -func Printf(format string, v ...) (n int, errno os.Error) { - n, errno = Fprintf(os.Stdout, format, v); - return n, errno; -} - -// Sprintf formats according to a format specifier and returns the resulting string. -func Sprintf(format string, a ...) string { - v := reflect.NewValue(a).(reflect.StructValue); - p := newPrinter(); - p.doprintf(format, v); - s := string(p.buf)[0 : p.n]; - return s; -} - -// 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. -func Fprint(w io.Writer, a ...) (n int, error os.Error) { - v := reflect.NewValue(a).(reflect.StructValue); - p := newPrinter(); - p.doprint(v, false, false); - n, error = w.Write(p.buf[0:p.n]); - return n, 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. -func Print(v ...) (n int, errno os.Error) { - n, errno = Fprint(os.Stdout, v); - 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 ...) string { - v := reflect.NewValue(a).(reflect.StructValue); - p := newPrinter(); - p.doprint(v, false, false); - s := string(p.buf)[0 : p.n]; - 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. -func Fprintln(w io.Writer, a ...) (n int, error os.Error) { - v := reflect.NewValue(a).(reflect.StructValue); - p := newPrinter(); - p.doprint(v, true, true); - n, error = w.Write(p.buf[0:p.n]); - return n, 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. -func Println(v ...) (n int, errno os.Error) { - n, errno = Fprintln(os.Stdout, v); - 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 ...) string { - v := reflect.NewValue(a).(reflect.StructValue); - p := newPrinter(); - p.doprint(v, true, true); - s := string(p.buf)[0 : p.n]; - 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 val.Kind() == reflect.InterfaceKind { - inter := val.(reflect.InterfaceValue).Get(); - return reflect.NewValue(inter); - } - return val; -} - -// Getters for the fields of the argument structure. - -func getBool(v reflect.Value) (val bool, ok bool) { - switch v.Kind() { - case reflect.BoolKind: - return v.(reflect.BoolValue).Get(), true; - } - return false, false -} - -func getInt(v reflect.Value) (val int64, signed, ok bool) { - switch v.Kind() { - case reflect.IntKind: - return int64(v.(reflect.IntValue).Get()), true, true; - case reflect.Int8Kind: - return int64(v.(reflect.Int8Value).Get()), true, true; - case reflect.Int16Kind: - return int64(v.(reflect.Int16Value).Get()), true, true; - case reflect.Int32Kind: - return int64(v.(reflect.Int32Value).Get()), true, true; - case reflect.Int64Kind: - return int64(v.(reflect.Int64Value).Get()), true, true; - case reflect.UintKind: - return int64(v.(reflect.UintValue).Get()), false, true; - case reflect.Uint8Kind: - return int64(v.(reflect.Uint8Value).Get()), false, true; - case reflect.Uint16Kind: - return int64(v.(reflect.Uint16Value).Get()), false, true; - case reflect.Uint32Kind: - return int64(v.(reflect.Uint32Value).Get()), false, true; - case reflect.Uint64Kind: - return int64(v.(reflect.Uint64Value).Get()), false, true; - case reflect.UintptrKind: - return int64(v.(reflect.UintptrValue).Get()), false, true; - } - return 0, false, false; -} - -func getString(v reflect.Value) (val string, ok bool) { - switch v.Kind() { - case reflect.StringKind: - return v.(reflect.StringValue).Get(), true; - case reflect.ArrayKind: - if val, ok := v.Interface().([]byte); ok { - return string(val), true; - } - } - return "", false; -} - -func getFloat32(v reflect.Value) (val float32, ok bool) { - switch v.Kind() { - case reflect.Float32Kind: - return float32(v.(reflect.Float32Value).Get()), true; - case reflect.FloatKind: - if v.Type().Size()*8 == 32 { - return float32(v.(reflect.FloatValue).Get()), true; - } - } - return 0.0, false; -} - -func getFloat64(v reflect.Value) (val float64, ok bool) { - switch v.Kind() { - case reflect.FloatKind: - if v.Type().Size()*8 == 64 { - return float64(v.(reflect.FloatValue).Get()), true; - } - case reflect.Float64Kind: - return float64(v.(reflect.Float64Value).Get()), true; - } - return 0.0, false; -} - -func getPtr(v reflect.Value) (val uintptr, ok bool) { - switch v.Kind() { - case reflect.PtrKind: - return uintptr(v.(reflect.PtrValue).Get()), true; - } - return 0, false; -} - -func getArrayPtr(v reflect.Value) (val reflect.ArrayValue, ok bool) { - if v.Kind() == reflect.PtrKind { - v = v.(reflect.PtrValue).Sub(); - if v.Kind() == reflect.ArrayKind { - return v.(reflect.ArrayValue), true; - } - } - return nil, false; -} - -func getArray(v reflect.Value) (val reflect.ArrayValue, ok bool) { - switch v.Kind() { - case reflect.ArrayKind: - return v.(reflect.ArrayValue), true; - } - return nil, false; -} - -// Convert ASCII to integer. n is 0 (and got is false) if no number present. - -func parsenum(s string, start, end int) (n int, got bool, newi int) { - if start >= end { - return 0, false, end - } - isnum := false; - num := 0; - for '0' <= s[start] && s[start] <= '9' { - num = num*10 + int(s[start] - '0'); - start++; - isnum = true; - } - return num, isnum, start; -} - -func (p *pp) printField(field reflect.Value) (was_string bool) { - inter := field.Interface(); - if inter != nil { - if stringer, ok := inter.(Stringer); ok { - p.addstr(stringer.String()); - return false; // this value is not a string - } - } - s := ""; - switch field.Kind() { - case reflect.BoolKind: - s = p.fmt.Fmt_boolean(field.(reflect.BoolValue).Get()).Str(); - case reflect.IntKind, reflect.Int8Kind, reflect.Int16Kind, reflect.Int32Kind, reflect.Int64Kind: - v, signed, ok := getInt(field); - s = p.fmt.Fmt_d64(v).Str(); - case reflect.UintKind, reflect.Uint8Kind, reflect.Uint16Kind, reflect.Uint32Kind, reflect.Uint64Kind: - v, signed, ok := getInt(field); - s = p.fmt.Fmt_ud64(uint64(v)).Str(); - case reflect.UintptrKind: - v, signed, ok := getInt(field); - p.fmt.sharp = !p.fmt.sharp; // turn 0x on by default - s = p.fmt.Fmt_ux64(uint64(v)).Str(); - case reflect.Float32Kind: - v, ok := getFloat32(field); - s = p.fmt.Fmt_g32(v).Str(); - case reflect.Float64Kind: - v, ok := getFloat64(field); - s = p.fmt.Fmt_g64(v).Str(); - case reflect.FloatKind: - if field.Type().Size()*8 == 32 { - v, ok := getFloat32(field); - s = p.fmt.Fmt_g32(v).Str(); - } else { - v, ok := getFloat64(field); - s = p.fmt.Fmt_g64(v).Str(); - } - case reflect.StringKind: - v, ok := getString(field); - s = p.fmt.Fmt_s(v).Str(); - was_string = true; - case reflect.PtrKind: - if v, ok := getPtr(field); v == 0 { - s = "" - } else { - // pointer to array? (TODO(r): holdover; delete?) - if a, ok := getArrayPtr(field); ok { - p.addstr("&["); - for i := 0; i < a.Len(); i++ { - if i > 0 { - p.addstr(" "); - } - p.printField(a.Elem(i)); - } - p.addstr("]"); - } else { - p.fmt.sharp = !p.fmt.sharp; // turn 0x on by default - s = p.fmt.Fmt_uX64(uint64(v)).Str(); - } - } - case reflect.ArrayKind: - if a, ok := getArray(field); ok { - p.addstr("["); - for i := 0; i < a.Len(); i++ { - if i > 0 { - p.addstr(" "); - } - p.printField(a.Elem(i)); - } - p.addstr("]"); - } - case reflect.StructKind: - p.add('{'); - v := field.(reflect.StructValue); - t := v.Type().(reflect.StructType); - donames := p.fmt.plus; - p.fmt.clearflags(); // clear flags for p.printField - for i := 0; i < v.Len(); i++ { - if i > 0 { - p.add(' ') - } - if donames { - if name, typ, tag, off := t.Field(i); name != "" { - p.addstr(name); - p.add('='); - } - } - p.printField(getField(v, i)); - } - p.add('}'); - case reflect.InterfaceKind: - value := field.(reflect.InterfaceValue).Value(); - if value == nil { - s = "" - } else { - return p.printField(value); - } - default: - s = "?" + field.Type().String() + "?"; - } - p.addstr(s); - return was_string; -} - -func (p *pp) doprintf(format string, v reflect.StructValue) { - p.ensure(len(format)); // a good starting size - end := len(format) - 1; - fieldnum := 0; // we process one field per non-trivial format - for i := 0; i <= end; { - c, w := utf8.DecodeRuneInString(format[i:len(format)]); - if c != '%' || i == end { - p.add(c); - i += w; - continue; - } - 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 20 (width)? - p.fmt.wid, p.fmt.wid_present, i = parsenum(format, i, end); - // do we have .20 (precision)? - if i < end && format[i] == '.' { - p.fmt.prec, p.fmt.prec_present, i = parsenum(format, i+1, end); - } - c, w = utf8.DecodeRuneInString(format[i:len(format)]); - i += w; - // percent is special - absorbs no operand - if c == '%' { - p.add('%'); // TODO: should we bother with width & prec? - continue; - } - if fieldnum >= v.Len() { // out of operands - p.add('%'); - p.add(c); - p.addstr("(missing)"); - continue; - } - field := getField(v, fieldnum); - fieldnum++; - inter := field.Interface(); - if inter != nil && c != 'T' { // don't want thing to describe itself if we're asking for its type - if formatter, ok := inter.(Format); ok { - formatter.Format(p, c); - continue; - } - } - s := ""; - switch c { - // bool - case 't': - if v, ok := getBool(field); ok { - if v { - s = "true"; - } else { - s = "false"; - } - } else { - goto badtype; - } - - // int - case 'b': - if v, signed, ok := getInt(field); ok { - s = p.fmt.Fmt_b64(uint64(v)).Str() // always unsigned - } else if v, ok := getFloat32(field); ok { - s = p.fmt.Fmt_fb32(v).Str() - } else if v, ok := getFloat64(field); ok { - s = p.fmt.Fmt_fb64(v).Str() - } else { - goto badtype - } - case 'c': - if v, signed, ok := getInt(field); ok { - s = p.fmt.Fmt_c(int(v)).Str() - } else { - goto badtype - } - case 'd': - if v, signed, ok := getInt(field); ok { - if signed { - s = p.fmt.Fmt_d64(v).Str() - } else { - s = p.fmt.Fmt_ud64(uint64(v)).Str() - } - } else { - goto badtype - } - case 'o': - if v, signed, ok := getInt(field); ok { - if signed { - s = p.fmt.Fmt_o64(v).Str() - } else { - s = p.fmt.Fmt_uo64(uint64(v)).Str() - } - } else { - goto badtype - } - case 'x': - if v, signed, ok := getInt(field); ok { - if signed { - s = p.fmt.Fmt_x64(v).Str() - } else { - s = p.fmt.Fmt_ux64(uint64(v)).Str() - } - } else if v, ok := getString(field); ok { - s = p.fmt.Fmt_sx(v).Str(); - } else { - goto badtype - } - case 'X': - if v, signed, ok := getInt(field); ok { - if signed { - s = p.fmt.Fmt_X64(v).Str() - } else { - s = p.fmt.Fmt_uX64(uint64(v)).Str() - } - } else if v, ok := getString(field); ok { - s = p.fmt.Fmt_sX(v).Str(); - } else { - goto badtype - } - - // float - case 'e': - if v, ok := getFloat32(field); ok { - s = p.fmt.Fmt_e32(v).Str() - } else if v, ok := getFloat64(field); ok { - s = p.fmt.Fmt_e64(v).Str() - } else { - goto badtype - } - case 'f': - if v, ok := getFloat32(field); ok { - s = p.fmt.Fmt_f32(v).Str() - } else if v, ok := getFloat64(field); ok { - s = p.fmt.Fmt_f64(v).Str() - } else { - goto badtype - } - case 'g': - if v, ok := getFloat32(field); ok { - s = p.fmt.Fmt_g32(v).Str() - } else if v, ok := getFloat64(field); ok { - s = p.fmt.Fmt_g64(v).Str() - } else { - goto badtype - } - - // string - case 's': - if inter != nil { - // if object implements String, use the result. - if stringer, ok := inter.(Stringer); ok { - s = p.fmt.Fmt_s(stringer.String()).Str(); - break; - } - } - if v, ok := getString(field); ok { - s = p.fmt.Fmt_s(v).Str() - } else { - goto badtype - } - case 'q': - if v, ok := getString(field); ok { - s = p.fmt.Fmt_q(v).Str() - } else { - goto badtype - } - - // pointer - case 'p': - if v, ok := getPtr(field); ok { - if v == 0 { - s = "" - } else { - s = "0x" + p.fmt.Fmt_uX64(uint64(v)).Str() - } - } else { - goto badtype - } - - // arbitrary value; do your best - case 'v': - p.printField(field); - - // the value's type - case 'T': - s = field.Type().String(); - - default: - badtype: - s = "%" + string(c) + "(" + field.Type().String() + ")%"; - } - p.addstr(s); - } - if fieldnum < v.Len() { - p.addstr("?(extra "); - for ; fieldnum < v.Len(); fieldnum++ { - p.addstr(getField(v, fieldnum).Type().String()); - if fieldnum + 1 < v.Len() { - p.addstr(", "); - } - } - p.addstr(")"); - } -} - -func (p *pp) doprint(v reflect.StructValue, addspace, addnewline bool) { - prev_string := false; - for fieldnum := 0; fieldnum < v.Len(); fieldnum++ { - // always add spaces if we're doing println - field := getField(v, fieldnum); - if fieldnum > 0 { - if addspace { - p.add(' ') - } else if field.Kind() != reflect.StringKind && !prev_string{ - // if not doing println, add spaces if neither side is a string - p.add(' ') - } - } - was_string := p.printField(field); - prev_string = was_string; - } - if addnewline { - p.add('\n') - } -} diff --git a/src/lib/go/ast/Makefile b/src/lib/go/ast/Makefile deleted file mode 100644 index 1fd22ae71..000000000 --- a/src/lib/go/ast/Makefile +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m >Makefile - -D=/go/ - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - ast.$O\ - -O2=\ - format.$O\ - - -phases: a1 a2 -_obj$D/ast.a: phases - -a1: $(O1) - $(AR) grc _obj$D/ast.a ast.$O - rm -f $(O1) - -a2: $(O2) - $(AR) grc _obj$D/ast.a format.$O - rm -f $(O2) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/ast.a - -$(O1): newpkg -$(O2): a1 -$(O3): a2 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/ast.a - -packages: _obj$D/ast.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/ast.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/ast.a diff --git a/src/lib/go/ast/ast.go b/src/lib/go/ast/ast.go deleted file mode 100644 index 6cac8ea1a..000000000 --- a/src/lib/go/ast/ast.go +++ /dev/null @@ -1,772 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// The AST package declares the types used to represent -// syntax trees for Go source files. -// -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. - -// TODO: For comment positioning only the byte position and not -// a complete token.Position field is needed. May be able to trim -// node sizes a bit. - - -type ( - ExprVisitor interface; - StmtVisitor interface; - DeclVisitor interface; -) - - -// All expression nodes implement the Expr interface. -type Expr interface { - // For a (dynamic) node type X, calling Visit with an expression - // visitor v invokes the node-specific DoX function of the visitor. - // - Visit(v ExprVisitor); - - // Pos returns the (beginning) position of the expression. - Pos() token.Position; -} - - -// All statement nodes implement the Stmt interface. -type Stmt interface { - // For a (dynamic) node type X, calling Visit with a statement - // visitor v invokes the node-specific DoX function of the visitor. - // - Visit(v StmtVisitor); - - // Pos returns the (beginning) position of the statement. - Pos() token.Position; -} - - -// All declaration nodes implement the Decl interface. -type Decl interface { - // For a (dynamic) node type X, calling Visit with a declaration - // visitor v invokes the node-specific DoX function of the visitor. - // - Visit(v DeclVisitor); - - // Pos returns the (beginning) position of the declaration. - Pos() token.Position; -} - - -// ---------------------------------------------------------------------------- -// Comments - -// A Comment node represents a single //-style or /*-style comment. -type Comment struct { - token.Position; // beginning position of the comment - Text []byte; // the comment text (without '\n' for //-style comments) - EndLine int; // the line where the comment ends -} - - -// A Comments node represents a sequence of single comments -// with no other tokens and no empty lines between. -// -type Comments []*Comment - - -// ---------------------------------------------------------------------------- -// Expressions and types - -// Support types. -type ( - Ident struct; - StringLit struct; - FuncType struct; - BlockStmt struct; - - // A Field represents a Field declaration list in a struct type, - // a method in an interface type, or a parameter/result declaration - // in a signature. - Field struct { - Doc Comments; // associated documentation; or nil - Names []*Ident; // field/method/parameter names; nil if anonymous field - Type Expr; // field/method/parameter type - Tag []*StringLit; // field tag; nil if no tag - }; -) - - -// 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 { - token.Position; // beginning position of bad expression - }; - - // An Ident node represents an identifier. - Ident struct { - token.Position; // identifier position - Value string; // identifier string (e.g. foobar) - }; - - // An Ellipsis node stands for the "..." type in a - // parameter list or the "..." length in an array type. - // - Ellipsis struct { - token.Position; // position of "..." - }; - - // An IntLit node represents an integer literal. - IntLit struct { - token.Position; // int literal position - Value []byte; // literal string; e.g. 42 or 0x7f - }; - - // A FloatLit node represents a floating-point literal. - FloatLit struct { - token.Position; // float literal position - Value []byte; // literal string; e.g. 3.14 or 1e-9 - }; - - // A CharLit node represents a character literal. - CharLit struct { - token.Position; // char literal position - Value []byte; // literal string, including quotes; e.g. 'a' or '\x7f' - }; - - // A StringLit node represents a string literal. - StringLit struct { - token.Position; // string literal position - Value []byte; // literal string, including quotes; e.g. "foo" or `\m\n\o` - }; - - // A StringList node represents a sequence of adjacent string literals. - // A single string literal (common case) is represented by a StringLit - // node; StringList nodes are used only if there are two or more string - // literals in a sequence. - // - StringList struct { - Strings []*StringLit; // list of strings, len(Strings) > 1 - }; - - // 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 - Lbrace token.Position; // position of "{" - Elts []Expr; // list of composite elements - Rbrace token.Position; // position of "}" - }; - - // A ParenExpr node represents a parenthesized expression. - ParenExpr struct { - token.Position; // position of "(" - X Expr; // parenthesized expression - Rparen token.Position; // 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 or slice. - IndexExpr struct { - X Expr; // expression - Index Expr; // index expression or beginning of slice range - End Expr; // end of slice range; or nil - }; - - // A TypeAssertExpr node represents an expression followed by a - // type assertion. - // - TypeAssertExpr struct { - X Expr; // expression - Type Expr; // asserted type - }; - - // A CallExpr node represents an expression followed by an argument list. - CallExpr struct { - Fun Expr; // function expression - Lparen token.Position; // position of "(" - Args []Expr; // function arguments - Rparen token.Position; // positions of ")" - }; - - // A StarExpr node represents an expression of the form "*" Expression. - // Semantically it could be a unary "*" expression, or a pointer type. - StarExpr struct { - token.Position; // position of "*" - X Expr; // operand - }; - - // A UnaryExpr node represents a unary expression. - // Unary "*" expressions are represented via StarExpr nodes. - // - UnaryExpr struct { - token.Position; // position of Op - Op token.Token; // operator - X Expr; // operand - }; - - // A BinaryExpr node represents a binary expression. - // - BinaryExpr struct { - X Expr; // left operand - OpPos token.Position; // position of Op - Op token.Token; // operator - Y Expr; // right operand - }; - - // A KeyValueExpr node represents (key : value) pairs - // in composite literals. - // - KeyValueExpr struct { - Key Expr; - Colon token.Position; // 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 { - token.Position; // position of "[" - Len Expr; // Ellipsis node for [...]T array types, nil for slice types - Elt Expr; // element type - }; - - // A StructType node represents a struct type. - StructType struct { - token.Position; // position of "struct" keyword - Lbrace token.Position; // position of "{" - Fields []*Field; // list of field declarations; nil if forward declaration - Rbrace token.Position; // position of "}" - }; - - // Pointer types are represented via StarExpr nodes. - - // A FuncType node represents a function type. - FuncType struct { - token.Position; // position of "func" keyword - Params []*Field; // (incoming) parameters - Results []*Field; // (outgoing) results - }; - - // An InterfaceType node represents an interface type. - InterfaceType struct { - token.Position; // position of "interface" keyword - Lbrace token.Position; // position of "{" - Methods []*Field; // list of methods; nil if forward declaration - Rbrace token.Position; // position of "}" - }; - - // A MapType node represents a map type. - MapType struct { - token.Position; // position of "map" keyword - Key Expr; - Value Expr; - }; - - // A ChanType node represents a channel type. - ChanType struct { - token.Position; // position of "chan" keyword or "<-" (whichever comes first) - Dir ChanDir; // channel direction - Value Expr; // value type - }; -) - - -// Pos() implementations for expression/type where the position -// corresponds to the position of a sub-node. -// -func (x *StringList) Pos() token.Position { return x.Strings[0].Pos(); } -func (x *FuncLit) Pos() token.Position { return x.Type.Pos(); } -func (x *CompositeLit) Pos() token.Position { return x.Type.Pos(); } -func (x *SelectorExpr) Pos() token.Position { return x.X.Pos(); } -func (x *IndexExpr) Pos() token.Position { return x.X.Pos(); } -func (x *TypeAssertExpr) Pos() token.Position { return x.X.Pos(); } -func (x *CallExpr) Pos() token.Position { return x.Fun.Pos(); } -func (x *BinaryExpr) Pos() token.Position { return x.X.Pos(); } -func (x *KeyValueExpr) Pos() token.Position { return x.Key.Pos(); } - - -// All expression/type nodes implement a Visit method which takes -// an ExprVisitor as argument. For a given node x of type X, and -// an implementation v of an ExprVisitor, calling x.Visit(v) will -// result in a call of v.DoX(x) (through a double-dispatch). -// -type ExprVisitor interface { - // Expressions - DoBadExpr(x *BadExpr); - DoIdent(x *Ident); - DoIntLit(x *IntLit); - DoFloatLit(x *FloatLit); - DoCharLit(x *CharLit); - DoStringLit(x *StringLit); - DoStringList(x *StringList); - DoFuncLit(x *FuncLit); - DoCompositeLit(x *CompositeLit); - DoParenExpr(x *ParenExpr); - DoSelectorExpr(x *SelectorExpr); - DoIndexExpr(x *IndexExpr); - DoTypeAssertExpr(x *TypeAssertExpr); - DoCallExpr(x *CallExpr); - DoStarExpr(x *StarExpr); - DoUnaryExpr(x *UnaryExpr); - DoBinaryExpr(x *BinaryExpr); - DoKeyValueExpr(x *KeyValueExpr); - - // Type expressions - DoEllipsis(x *Ellipsis); - DoArrayType(x *ArrayType); - DoStructType(x *StructType); - DoFuncType(x *FuncType); - DoInterfaceType(x *InterfaceType); - DoMapType(x *MapType); - DoChanType(x *ChanType); -} - - -// Visit() implementations for all expression/type nodes. -// -func (x *BadExpr) Visit(v ExprVisitor) { v.DoBadExpr(x); } -func (x *Ident) Visit(v ExprVisitor) { v.DoIdent(x); } -func (x *Ellipsis) Visit(v ExprVisitor) { v.DoEllipsis(x); } -func (x *IntLit) Visit(v ExprVisitor) { v.DoIntLit(x); } -func (x *FloatLit) Visit(v ExprVisitor) { v.DoFloatLit(x); } -func (x *CharLit) Visit(v ExprVisitor) { v.DoCharLit(x); } -func (x *StringLit) Visit(v ExprVisitor) { v.DoStringLit(x); } -func (x *StringList) Visit(v ExprVisitor) { v.DoStringList(x); } -func (x *FuncLit) Visit(v ExprVisitor) { v.DoFuncLit(x); } -func (x *CompositeLit) Visit(v ExprVisitor) { v.DoCompositeLit(x); } -func (x *ParenExpr) Visit(v ExprVisitor) { v.DoParenExpr(x); } -func (x *SelectorExpr) Visit(v ExprVisitor) { v.DoSelectorExpr(x); } -func (x *IndexExpr) Visit(v ExprVisitor) { v.DoIndexExpr(x); } -func (x *TypeAssertExpr) Visit(v ExprVisitor) { v.DoTypeAssertExpr(x); } -func (x *CallExpr) Visit(v ExprVisitor) { v.DoCallExpr(x); } -func (x *StarExpr) Visit(v ExprVisitor) { v.DoStarExpr(x); } -func (x *UnaryExpr) Visit(v ExprVisitor) { v.DoUnaryExpr(x); } -func (x *BinaryExpr) Visit(v ExprVisitor) { v.DoBinaryExpr(x); } -func (x *KeyValueExpr) Visit(v ExprVisitor) { v.DoKeyValueExpr(x); } - -func (x *ArrayType) Visit(v ExprVisitor) { v.DoArrayType(x); } -func (x *StructType) Visit(v ExprVisitor) { v.DoStructType(x); } -func (x *FuncType) Visit(v ExprVisitor) { v.DoFuncType(x); } -func (x *InterfaceType) Visit(v ExprVisitor) { v.DoInterfaceType(x); } -func (x *MapType) Visit(v ExprVisitor) { v.DoMapType(x); } -func (x *ChanType) Visit(v ExprVisitor) { v.DoChanType(x); } - - -// IsExported returns whether name is an exported Go symbol -// (i.e., whether it begins with an uppercase letter). -func IsExported(name string) bool { - ch, len := utf8.DecodeRuneInString(name); - return unicode.IsUpper(ch); -} - -// IsExported returns whether name is an exported Go symbol -// (i.e., whether it begins with an uppercase letter). -func (name *ast.Ident) IsExported() bool { - return IsExported(name.Value); -} - -func (name *ast.Ident) String() string { - return name.Value; -} - - -// ---------------------------------------------------------------------------- -// 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 { - token.Position; // beginning position of bad statement - }; - - // A DeclStmt node represents a declaration in a statement list. - DeclStmt struct { - Decl Decl; - }; - - // An EmptyStmt node represents an empty statement. - // The "position" of the empty statement is the position - // of the immediately preceeding semicolon. - // - EmptyStmt struct { - token.Position; // position of preceeding ";" - }; - - // A LabeledStmt node represents a labeled statement. - LabeledStmt struct { - Label *Ident; - Stmt Stmt; - }; - - // An ExprStmt node represents a (stand-alone) expression - // in a statement list. - // - ExprStmt struct { - X Expr; // expression - }; - - // An IncDecStmt node represents an increment or decrement statement. - IncDecStmt struct { - X Expr; - Tok token.Token; // INC or DEC - }; - - // An AssignStmt node represents an assignment or - // a short variable declaration. - AssignStmt struct { - Lhs []Expr; - TokPos token.Position; // position of Tok - Tok token.Token; // assignment token, DEFINE - Rhs []Expr; - }; - - // A GoStmt node represents a go statement. - GoStmt struct { - token.Position; // position of "go" keyword - Call *CallExpr; - }; - - // A DeferStmt node represents a defer statement. - DeferStmt struct { - token.Position; // position of "defer" keyword - Call *CallExpr; - }; - - // A ReturnStmt node represents a return statement. - ReturnStmt struct { - token.Position; // position of "return" keyword - Results []Expr; - }; - - // A BranchStmt node represents a break, continue, goto, - // or fallthrough statement. - // - BranchStmt struct { - token.Position; // position of Tok - Tok token.Token; // keyword token (BREAK, CONTINUE, GOTO, FALLTHROUGH) - Label *Ident; - }; - - // A BlockStmt node represents a braced statement list. - BlockStmt struct { - token.Position; // position of "{" - List []Stmt; - Rbrace token.Position; // position of "}" - }; - - // An IfStmt node represents an if statement. - IfStmt struct { - token.Position; // position of "if" keyword - Init Stmt; - Cond Expr; - Body *BlockStmt; - Else Stmt; - }; - - // A CaseClause represents a case of an expression switch statement. - CaseClause struct { - token.Position; // position of "case" or "default" keyword - Values []Expr; // nil means default case - Colon token.Position; // position of ":" - Body []Stmt; // statement list; or nil - }; - - // A SwitchStmt node represents an expression switch statement. - SwitchStmt struct { - token.Position; // position of "switch" keyword - Init Stmt; - Tag Expr; - Body *BlockStmt; // CaseClauses only - }; - - // A TypeCaseClause represents a case of a type switch statement. - TypeCaseClause struct { - token.Position; // position of "case" or "default" keyword - Type Expr; // nil means default case - Colon token.Position; // position of ":" - Body []Stmt; // statement list; or nil - }; - - // An TypeSwitchStmt node represents a type switch statement. - TypeSwitchStmt struct { - token.Position; // position of "switch" keyword - Init Stmt; - Assign Stmt; // x := y.(type) - Body *BlockStmt; // TypeCaseClauses only - }; - - // A CommClause node represents a case of a select statement. - CommClause struct { - token.Position; // position of "case" or "default" keyword - Tok token.Token; // ASSIGN or DEFINE (valid only if Lhs != nil) - Lhs, Rhs Expr; // Rhs == nil means default case - Colon token.Position; // position of ":" - Body []Stmt; // statement list; or nil - }; - - // An SelectStmt node represents a select statement. - SelectStmt struct { - token.Position; // position of "select" keyword - Body *BlockStmt; // CommClauses only - }; - - // A ForStmt represents a for statement. - ForStmt struct { - token.Position; // position of "for" keyword - Init Stmt; - Cond Expr; - Post Stmt; - Body *BlockStmt; - }; - - // A RangeStmt represents a for statement with a range clause. - RangeStmt struct { - token.Position; // position of "for" keyword - Key, Value Expr; // Value may be nil - TokPos token.Position; // position of Tok - Tok token.Token; // ASSIGN, DEFINE - X Expr; // value to range over - Body *BlockStmt; - }; -) - - -// Pos() implementations for statement nodes where the position -// corresponds to the position of a sub-node. -// -func (s *DeclStmt) Pos() token.Position { return s.Decl.Pos(); } -func (s *LabeledStmt) Pos() token.Position { return s.Label.Pos(); } -func (s *ExprStmt) Pos() token.Position { return s.X.Pos(); } -func (s *IncDecStmt) Pos() token.Position { return s.X.Pos(); } -func (s *AssignStmt) Pos() token.Position { return s.Lhs[0].Pos(); } - - -// All statement nodes implement a Visit method which takes -// a StmtVisitor as argument. For a given node x of type X, and -// an implementation v of a StmtVisitor, calling x.Visit(v) will -// result in a call of v.DoX(x) (through a double-dispatch). -// -type StmtVisitor interface { - DoBadStmt(s *BadStmt); - DoDeclStmt(s *DeclStmt); - DoEmptyStmt(s *EmptyStmt); - DoLabeledStmt(s *LabeledStmt); - DoExprStmt(s *ExprStmt); - DoIncDecStmt(s *IncDecStmt); - DoAssignStmt(s *AssignStmt); - DoGoStmt(s *GoStmt); - DoDeferStmt(s *DeferStmt); - DoReturnStmt(s *ReturnStmt); - DoBranchStmt(s *BranchStmt); - DoBlockStmt(s *BlockStmt); - DoIfStmt(s *IfStmt); - DoCaseClause(s *CaseClause); - DoSwitchStmt(s *SwitchStmt); - DoTypeCaseClause(s *TypeCaseClause); - DoTypeSwitchStmt(s *TypeSwitchStmt); - DoCommClause(s *CommClause); - DoSelectStmt(s *SelectStmt); - DoForStmt(s *ForStmt); - DoRangeStmt(s *RangeStmt); -} - - -// Visit() implementations for all statement nodes. -// -func (s *BadStmt) Visit(v StmtVisitor) { v.DoBadStmt(s); } -func (s *DeclStmt) Visit(v StmtVisitor) { v.DoDeclStmt(s); } -func (s *EmptyStmt) Visit(v StmtVisitor) { v.DoEmptyStmt(s); } -func (s *LabeledStmt) Visit(v StmtVisitor) { v.DoLabeledStmt(s); } -func (s *ExprStmt) Visit(v StmtVisitor) { v.DoExprStmt(s); } -func (s *IncDecStmt) Visit(v StmtVisitor) { v.DoIncDecStmt(s); } -func (s *AssignStmt) Visit(v StmtVisitor) { v.DoAssignStmt(s); } -func (s *GoStmt) Visit(v StmtVisitor) { v.DoGoStmt(s); } -func (s *DeferStmt) Visit(v StmtVisitor) { v.DoDeferStmt(s); } -func (s *ReturnStmt) Visit(v StmtVisitor) { v.DoReturnStmt(s); } -func (s *BranchStmt) Visit(v StmtVisitor) { v.DoBranchStmt(s); } -func (s *BlockStmt) Visit(v StmtVisitor) { v.DoBlockStmt(s); } -func (s *IfStmt) Visit(v StmtVisitor) { v.DoIfStmt(s); } -func (s *CaseClause) Visit(v StmtVisitor) { v.DoCaseClause(s); } -func (s *SwitchStmt) Visit(v StmtVisitor) { v.DoSwitchStmt(s); } -func (s *TypeCaseClause) Visit(v StmtVisitor) { v.DoTypeCaseClause(s); } -func (s *TypeSwitchStmt) Visit(v StmtVisitor) { v.DoTypeSwitchStmt(s); } -func (s *CommClause) Visit(v StmtVisitor) { v.DoCommClause(s); } -func (s *SelectStmt) Visit(v StmtVisitor) { v.DoSelectStmt(s); } -func (s *ForStmt) Visit(v StmtVisitor) { v.DoForStmt(s); } -func (s *RangeStmt) Visit(v StmtVisitor) { v.DoRangeStmt(s); } - - -// ---------------------------------------------------------------------------- -// 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 {}; - - // An ImportSpec node represents a single package import. - ImportSpec struct { - Doc Comments; // associated documentation; or nil - Name *Ident; // local package name (including "."); or nil - Path []*StringLit; // package path - }; - - // A ValueSpec node represents a constant or variable declaration - // (ConstSpec or VarSpec production). - ValueSpec struct { - Doc Comments; // associated documentation; or nil - Names []*Ident; - Type Expr; // value type; or nil - Values []Expr; - }; - - // A TypeSpec node represents a type declaration (TypeSpec production). - TypeSpec struct { - Doc Comments; // associated documentation; or nil - Name *Ident; // type name - Type Expr; - }; -) - - -// 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 { - token.Position; // beginning position 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 Comments; // associated documentation; or nil - token.Position; // position of Tok - Tok token.Token; // IMPORT, CONST, TYPE, VAR - Lparen token.Position; // position of '(', if any - Specs []Spec; - Rparen token.Position; // position of ')', if any - }; - - // A FuncDecl node represents a function declaration. - FuncDecl struct { - Doc Comments; // associated documentation; or nil - Recv *Field; // 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) - }; -) - - -// The position of a FuncDecl node is the position of its function type. -func (d *FuncDecl) Pos() token.Position { return d.Type.Pos(); } - - -// All declaration nodes implement a Visit method which takes -// a DeclVisitor as argument. For a given node x of type X, and -// an implementation v of a DeclVisitor, calling x.Visit(v) will -// result in a call of v.DoX(x) (through a double-dispatch). -// -type DeclVisitor interface { - DoBadDecl(d *BadDecl); - DoGenDecl(d *GenDecl); - DoFuncDecl(d *FuncDecl); -} - - -// Visit() implementations for all declaration nodes. -// -func (d *BadDecl) Visit(v DeclVisitor) { v.DoBadDecl(d); } -func (d *GenDecl) Visit(v DeclVisitor) { v.DoGenDecl(d); } -func (d *FuncDecl) Visit(v DeclVisitor) { v.DoFuncDecl(d); } - - -// ---------------------------------------------------------------------------- -// Programs - -// A Program node represents the root node of an AST -// for an entire source file. -// -type Program struct { - Doc Comments; // associated documentation; or nil - token.Position; // position of "package" keyword - Name *Ident; // package name - Decls []Decl; // top-level declarations - Comments []*Comment; // list of unassociated comments -} diff --git a/src/lib/go/ast/format.go b/src/lib/go/ast/format.go deleted file mode 100644 index caeca19aa..000000000 --- a/src/lib/go/ast/format.go +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package ast - -import ( - "datafmt"; - "go/ast"; - "go/token"; - "io"; - "os"; -) - - -// Format is a customized datafmt.Format for printing of ASTs. -type Format datafmt.Format; - - -// ---------------------------------------------------------------------------- -// Custom formatters - -// The AST-specific formatting state is maintained by a state variable. -type state struct { - // for now we have very little state - // TODO maintain list of unassociated comments - optSemi bool -} - - -func (s *state) Copy() datafmt.Environment { - copy := *s; - return © -} - - -func isValidPos(s *datafmt.State, value interface{}, ruleName string) bool { - pos := value.(token.Position); - return pos.IsValid(); -} - - -func isSend(s *datafmt.State, value interface{}, ruleName string) bool { - return value.(ast.ChanDir) & ast.SEND != 0; -} - - -func isRecv(s *datafmt.State, value interface{}, ruleName string) bool { - return value.(ast.ChanDir) & ast.RECV != 0; -} - - -func isMultiLineComment(s *datafmt.State, value interface{}, ruleName string) bool { - return value.([]byte)[1] == '*'; -} - - -func clearOptSemi(s *datafmt.State, value interface{}, ruleName string) bool { - s.Env().(*state).optSemi = false; - return true; -} - - -func setOptSemi(s *datafmt.State, value interface{}, ruleName string) bool { - s.Env().(*state).optSemi = true; - return true; -} - - -func optSemi(s *datafmt.State, value interface{}, ruleName string) bool { - if !s.Env().(*state).optSemi { - s.Write([]byte{';'}); - } - return true; -} - - -var fmap = datafmt.FormatterMap { - "isValidPos": isValidPos, - "isSend": isSend, - "isRecv": isRecv, - "isMultiLineComment": isMultiLineComment, - "/": clearOptSemi, - "clearOptSemi": clearOptSemi, - "setOptSemi": setOptSemi, - "optSemi": optSemi, -} - - -// ---------------------------------------------------------------------------- -// Printing - -// NewFormat parses a datafmt format specification from a file -// and adds AST-specific custom formatter rules. The result is -// the customized format or an os.Error, if any. -// -func NewFormat(filename string) (Format, os.Error) { - src, err := io.ReadFile(filename); - if err != nil { - return nil, err; - } - f, err := datafmt.Parse(src, fmap); - return Format(f), err; -} - - -// Fprint formats each AST node provided as 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) Fprint(w io.Writer, nodes ...) (int, os.Error) { - var s state; - return datafmt.Format(f).Fprint(w, &s, nodes); -} - - -// Fprint formats each AST node provided as 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) Print(nodes ...) (int, os.Error) { - return f.Fprint(os.Stdout, nodes); -} diff --git a/src/lib/go/doc/Makefile b/src/lib/go/doc/Makefile deleted file mode 100644 index d7c6acaac..000000000 --- a/src/lib/go/doc/Makefile +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m >Makefile - -D=/go/ - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - comment.$O\ - -O2=\ - doc.$O\ - - -phases: a1 a2 -_obj$D/doc.a: phases - -a1: $(O1) - $(AR) grc _obj$D/doc.a comment.$O - rm -f $(O1) - -a2: $(O2) - $(AR) grc _obj$D/doc.a doc.$O - rm -f $(O2) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/doc.a - -$(O1): newpkg -$(O2): a1 -$(O3): a2 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/doc.a - -packages: _obj$D/doc.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/doc.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/doc.a diff --git a/src/lib/go/doc/comment.go b/src/lib/go/doc/comment.go deleted file mode 100644 index 19a65a227..000000000 --- a/src/lib/go/doc/comment.go +++ /dev/null @@ -1,310 +0,0 @@ -// Copyright 2009 The Go 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 ( - "fmt"; - "io"; - "once"; - "regexp"; - "strings"; - "template"; // for htmlEscape -) - -// Comment extraction - -var ( - comment_markers *regexp.Regexp; - trailing_whitespace *regexp.Regexp; - comment_junk *regexp.Regexp; -) - -func makeRex(s string) *regexp.Regexp { - re, err := regexp.Compile(s); - if err != nil { - panic("MakeRegexp ", s, " ", err.String()); - } - return re; -} - -// TODO(rsc): Cannot use var initialization for regexps, -// because Regexp constructor needs threads. -func setupRegexps() { - comment_markers = makeRex("^/(/|\\*) ?"); - trailing_whitespace = makeRex("[ \t\r]+$"); - comment_junk = makeRex("^[ \t]*(/\\*|\\*/)[ \t]*$"); -} - -// Aggregate comment text, without comment markers. -func commentText(comments []string) string { - once.Do(setupRegexps); - lines := make([]string, 0, 20); - for i, c := range comments { - // split on newlines - cl := strings.Split(c, "\n"); - - // walk lines, stripping comment markers - w := 0; - for j, l := range cl { - // remove /* and */ lines - if comment_junk.Match(l) { - continue; - } - - // strip trailing white space - m := trailing_whitespace.Execute(l); - if len(m) > 0 { - l = l[0 : m[1]]; - } - - // strip leading comment markers - m = comment_markers.Execute(l); - if len(m) > 0 { - l = l[m[1] : len(l)]; - } - - // throw away leading blank lines - if w == 0 && l == "" { - continue; - } - - cl[w] = l; - w++; - } - - // throw away trailing blank lines - for w > 0 && cl[w-1] == "" { - w--; - } - cl = cl[0 : w]; - - // add this comment to total list - // TODO: maybe separate with a single blank line - // if there is already a comment and len(cl) > 0? - for j, l := range cl { - n := len(lines); - if n+1 >= cap(lines) { - newlines := make([]string, n, 2*cap(lines)); - for k := range newlines { - newlines[k] = lines[k]; - } - lines = newlines; - } - lines = lines[0 : n+1]; - lines[n] = l; - } - } - - // add final "" entry to get trailing newline. - // loop always leaves room for one more. - n := len(lines); - lines = lines[0 : n+1]; - - 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 : len(text)]; - } - - return out; -} - - -var ( - ldquo = io.StringBytes("“"); - rdquo = io.StringBytes("”"); -) - -// Escape comment text for HTML. -// Also, turn `` into “ and '' into ”. -func commentEscape(w io.Writer, s []byte) { - last := 0; - for i := 0; i < len(s)-1; i++ { - if s[i] == s[i+1] && (s[i] == '`' || s[i] == '\'') { - template.HtmlEscape(w, s[last : i]); - last = i+2; - switch s[i] { - case '`': - w.Write(ldquo); - case '\'': - w.Write(rdquo); - } - i++; // loop will add one more - } - } - template.HtmlEscape(w, s[last : len(s)]); -} - - -var ( - html_p = io.StringBytes("

\n"); - html_endp = io.StringBytes("

\n"); - html_pre = io.StringBytes("
");
-	html_endpre = io.StringBytes("
\n"); -) - - -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 i, 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 : len(line)]; - } - } -} - - -// 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

-// Turn each run of indented lines into

 without indent.
-//
-// TODO(rsc): I'd like to pass in an array of variable names []string
-// and then italicize those strings when they appear as words.
-func ToHtml(w io.Writer, s []byte) {
-	inpara := false;
-
-	/* TODO(rsc): 6g cant generate code for these
-	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
-			if inpara {
-				w.Write(html_endp);
-				inpara = false;
-			}
-			i++;
-			continue;
-		}
-		if indentLen(line) > 0 {
-			// close paragraph
-			if inpara {
-				w.Write(html_endp);
-				inpara = false;
-			}
-
-			// 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.
-			// they don't get the nice text formatting,
-			// just html escaping
-			w.Write(html_pre);
-			for k, line := range block {
-				template.HtmlEscape(w, line);
-			}
-			w.Write(html_endpre);
-			continue;
-		}
-		// open paragraph
-		if !inpara {
-			w.Write(html_p);
-			inpara = true;
-		}
-		commentEscape(w, lines[i]);
-		i++;
-	}
-	if inpara {
-		w.Write(html_endp);
-		inpara = false;
-	}
-}
-
diff --git a/src/lib/go/doc/doc.go b/src/lib/go/doc/doc.go
deleted file mode 100644
index 03872fd14..000000000
--- a/src/lib/go/doc/doc.go
+++ /dev/null
@@ -1,486 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package doc
-
-import (
-	"container/vector";
-	"fmt";
-	"go/ast";
-	"go/doc";
-	"go/token";
-	"io";
-	"regexp";
-	"sort";
-	"strings";
-)
-
-
-// ----------------------------------------------------------------------------
-// Elementary support
-
-func hasExportedNames(names []*ast.Ident) bool {
-	for i, name := range names {
-		if name.IsExported() {
-			return true;
-		}
-	}
-	return false;
-}
-
-
-func hasExportedSpecs(specs []ast.Spec) bool {
-	for i, s := range specs {
-		// only called for []astSpec lists of *ast.ValueSpec
-		return hasExportedNames(s.(*ast.ValueSpec).Names);
-	}
-	return false;
-}
-
-
-// ----------------------------------------------------------------------------
-
-type typeDoc struct {
-	decl *ast.GenDecl;  // len(decl.Specs) == 1, and the element type is *ast.TypeSpec
-	factories map[string] *ast.FuncDecl;
-	methods map[string] *ast.FuncDecl;
-}
-
-
-// DocReader accumulates documentation for a single package.
-//
-type DocReader struct {
-	name string;  // package name
-	path string;  // import path
-	doc ast.Comments;  // package documentation, if any
-	consts *vector.Vector;  // list of *ast.GenDecl
-	types map[string] *typeDoc;
-	vars *vector.Vector;  // list of *ast.GenDecl
-	funcs map[string] *ast.FuncDecl;
-}
-
-
-// Init initializes a DocReader to collect package documentation
-// for the package with the given package name and import path.
-//
-func (doc *DocReader) Init(pkg, imp string) {
-	doc.name = pkg;
-	doc.path = imp;
-	doc.consts = vector.New(0);
-	doc.types = make(map[string] *typeDoc);
-	doc.vars = vector.New(0);
-	doc.funcs = make(map[string] *ast.FuncDecl);
-}
-
-
-func baseTypeName(typ ast.Expr) string {
-	switch t := typ.(type) {
-	case *ast.Ident:
-		return string(t.Value);
-	case *ast.StarExpr:
-		return baseTypeName(t.X);
-	}
-	return "";
-}
-
-
-func (doc *DocReader) lookupTypeDoc(typ ast.Expr) *typeDoc {
-	tdoc, found := doc.types[baseTypeName(typ)];
-	if found {
-		return tdoc;
-	}
-	return nil;
-}
-
-
-func (doc *DocReader) addType(decl *ast.GenDecl) {
-	typ := decl.Specs[0].(*ast.TypeSpec);
-	name := typ.Name.Value;
-	tdoc := &typeDoc{decl, make(map[string] *ast.FuncDecl), make(map[string] *ast.FuncDecl)};
-	doc.types[name] = tdoc;
-}
-
-
-func (doc *DocReader) addFunc(fun *ast.FuncDecl) {
-	name := fun.Name.Value;
-
-	// determine if it should be associated with a type
-	var typ *typeDoc;
-	if fun.Recv != nil {
-		// method
-		// (all receiver types must be declared before they are used)
-		typ = doc.lookupTypeDoc(fun.Recv.Type);
-		if typ != nil {
-			// type found (i.e., exported)
-			typ.methods[name] = fun;
-		}
-		// if the type wasn't found, it wasn't exported
-		// TODO(gri): a non-exported type may still have exported functions
-		//            determine what to do in that case
-		return;
-	}
-
-	// perhaps a factory function
-	// determine result type, if any
-	if len(fun.Type.Results) >= 1 {
-		res := fun.Type.Results[0];
-		if len(res.Names) <= 1 {
-			// exactly one (named or anonymous) result type
-			typ = doc.lookupTypeDoc(res.Type);
-			if typ != nil {
-				typ.factories[name] = fun;
-				return;
-			}
-		}
-	}
-
-	// ordinary function
-	doc.funcs[name] = 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.IMPORT:
-				// ignore
-			case token.CONST:
-				// constants are always handled as a group
-				if hasExportedSpecs(d.Specs) {
-					doc.consts.Push(d);
-				}
-			case token.TYPE:
-				// types are handled individually
-				for i, spec := range d.Specs {
-					s := spec.(*ast.TypeSpec);
-					if s.Name.IsExported() {
-						// make a (fake) GenDecl node for this TypeSpec
-						// (we need to do this here - as opposed to just
-						// for printing - so we don't loose the GenDecl
-						// documentation)
-						var noPos token.Position;
-						doc.addType(&ast.GenDecl{d.Doc, d.Pos(), token.TYPE, noPos, []ast.Spec{s}, noPos});
-					}
-				}
-			case token.VAR:
-				// variables are always handled as a group
-				if hasExportedSpecs(d.Specs) {
-					doc.vars.Push(d);
-				}
-			}
-		}
-	case *ast.FuncDecl:
-		if d.Name.IsExported() {
-			doc.addFunc(d);
-		}
-	}
-}
-
-
-// AddProgram adds the AST for a source file to the DocReader.
-// Adding the same AST multiple times is a no-op.
-//
-func (doc *DocReader) AddProgram(prog *ast.Program) {
-	if doc.name != prog.Name.Value {
-		panic("package names don't match");
-	}
-
-	// add package documentation
-	// TODO(gri) what to do if there are multiple files?
-	if prog.Doc != nil {
-		doc.doc = prog.Doc
-	}
-
-	// add all exported declarations
-	for i, decl := range prog.Decls {
-		doc.addDecl(decl);
-	}
-}
-
-// ----------------------------------------------------------------------------
-// Conversion to external representation
-
-func astComment(comments ast.Comments) string {
-	text := make([]string, len(comments));
-	for i, c := range comments {
-		text[i] = string(c.Text);
-	}
-	return commentText(text);
-}
-
-// 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].Value;
-	case *ast.TypeSpec:
-		return v.Name.Value;
-	}
-
-	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(v *vector.Vector) []*ValueDoc {
-	d := make([]*ValueDoc, v.Len());
-	for i := range d {
-		decl := v.At(i).(*ast.GenDecl);
-		d[i] = &ValueDoc{astComment(decl.Doc), decl, i};
-	}
-	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 name, f := range m {
-		doc := new(FuncDoc);
-		doc.Doc = astComment(f.Doc);
-		if f.Recv != nil {
-			doc.Recv = f.Recv.Type;
-		}
-		doc.Name = f.Name.Value;
-		doc.Decl = f;
-		d[i] = doc;
-		i++;
-	}
-	sort.Sort(sortFuncDoc(d));
-	return d;
-}
-
-
-// TypeDoc is the documentation for a declared 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;
-	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.Value, p[j].Type.Name.Value; 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 statements.
-func makeTypeDocs(m map[string] *typeDoc) []*TypeDoc {
-	d := make([]*TypeDoc, len(m));
-	i := 0;
-	for name, old := range m {
-		typespec := old.decl.Specs[0].(*ast.TypeSpec);
-		t := new(TypeDoc);
-		t.Doc = astComment(typespec.Doc);
-		t.Type = typespec;
-		t.Factories = makeFuncDocs(old.factories);
-		t.Methods = makeFuncDocs(old.methods);
-		t.Decl = old.decl;
-		t.order = i;
-		d[i] = t;
-		i++;
-	}
-	sort.Sort(sortTypeDoc(d));
-	return d;
-}
-
-
-// PackageDoc is the documentation for an entire package.
-//
-type PackageDoc struct {
-	PackageName string;
-	ImportPath string;
-	Doc string;
-	Consts []*ValueDoc;
-	Types []*TypeDoc;
-	Vars []*ValueDoc;
-	Funcs []*FuncDoc;
-}
-
-
-// Doc returns the accumulated documentation for the package.
-//
-func (doc *DocReader) Doc() *PackageDoc {
-	p := new(PackageDoc);
-	p.PackageName = doc.name;
-	p.ImportPath = doc.path;
-	p.Doc = astComment(doc.doc);
-	p.Consts = makeValueDocs(doc.consts);
-	p.Vars = makeValueDocs(doc.vars);
-	p.Types = makeTypeDocs(doc.types);
-	p.Funcs = makeFuncDocs(doc.funcs);
-	return p;
-}
-
-
-// ----------------------------------------------------------------------------
-// Filtering by name
-
-// Does s look like a regular expression?
-func isRegexp(s string) bool {
-	metachars := ".(|)*+?^$[]";
-	for i, c := range s {
-		for j, m := range metachars {
-			if c == m {
-				return true
-			}
-		}
-	}
-	return false
-}
-
-
-func match(s string, a []string) bool {
-	for i, t := range a {
-		if isRegexp(t) {
-			if matched, err := regexp.Match(t, s); matched {
-				return true;
-			}
-		}
-		if s == t {
-			return true;
-		}
-	}
-	return false;
-}
-
-
-func matchDecl(d *ast.GenDecl, names []string) bool {
-	for i, d := range d.Specs {
-		switch v := d.(type) {
-		case *ast.ValueSpec:
-			for j, name := range v.Names {
-				if match(name.Value, names) {
-					return true;
-				}
-			}
-		case *ast.TypeSpec:
-			if match(v.Name.Value, names) {
-				return true;
-			}
-		}
-	}
-	return false;
-}
-
-
-func filterValueDocs(a []*ValueDoc, names []string) []*ValueDoc {
-	w := 0;
-	for i, vd := range a {
-		if matchDecl(vd.Decl, names) {
-			a[w] = vd;
-			w++;
-		}
-	}
-	return a[0 : w];
-}
-
-
-func filterFuncDocs(a []*FuncDoc, names []string) []*FuncDoc {
-	w := 0;
-	for i, fd := range a {
-		if match(fd.Name, names) {
-			a[w] = fd;
-			w++;
-		}
-	}
-	return a[0 : w];
-}
-
-
-func filterTypeDocs(a []*TypeDoc, names []string) []*TypeDoc {
-	w := 0;
-	for i, td := range a {
-		match := false;
-		if matchDecl(td.Decl, names) {
-			match = true;
-		} else {
-			// type name doesn't match, but we may have matching factories or methods
-			td.Factories = filterFuncDocs(td.Factories, names);
-			td.Methods = filterFuncDocs(td.Methods, names);
-			match = len(td.Factories) > 0 || len(td.Methods) > 0;
-		}
-		if match {
-			a[w] = td;
-			w++;
-		}
-	}
-	return a[0 : w];
-}
-
-
-// Filter eliminates information from d that is not
-// about one of the given names.
-// TODO: Recognize "Type.Method" as a name.
-// TODO(r): maybe precompile the regexps.
-//
-func (p *PackageDoc) Filter(names []string) {
-	p.Consts = filterValueDocs(p.Consts, names);
-	p.Vars = filterValueDocs(p.Vars, names);
-	p.Types = filterTypeDocs(p.Types, names);
-	p.Funcs = filterFuncDocs(p.Funcs, names);
-	p.Doc = "";	// don't show top-level package doc
-}
-
diff --git a/src/lib/go/parser/Makefile b/src/lib/go/parser/Makefile
deleted file mode 100644
index 08d83646f..000000000
--- a/src/lib/go/parser/Makefile
+++ /dev/null
@@ -1,60 +0,0 @@
-# Copyright 2009 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-# DO NOT EDIT.  Automatically generated by gobuild.
-# gobuild -m >Makefile
-
-D=/go/
-
-include $(GOROOT)/src/Make.$(GOARCH)
-AR=gopack
-
-default: packages
-
-clean:
-	rm -rf *.[$(OS)] *.a [$(OS)].out _obj
-
-test: packages
-	gotest
-
-coverage: packages
-	gotest
-	6cov -g `pwd` | grep -v '_test\.go:'
-
-%.$O: %.go
-	$(GC) -I_obj $*.go
-
-%.$O: %.c
-	$(CC) $*.c
-
-%.$O: %.s
-	$(AS) $*.s
-
-O1=\
-	parser.$O\
-
-
-phases: a1
-_obj$D/parser.a: phases
-
-a1: $(O1)
-	$(AR) grc _obj$D/parser.a parser.$O
-	rm -f $(O1)
-
-
-newpkg: clean
-	mkdir -p _obj$D
-	$(AR) grc _obj$D/parser.a
-
-$(O1): newpkg
-$(O2): a1
-
-nuke: clean
-	rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/parser.a
-
-packages: _obj$D/parser.a
-
-install: packages
-	test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D
-	cp _obj$D/parser.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/parser.a
diff --git a/src/lib/go/parser/parser.go b/src/lib/go/parser/parser.go
deleted file mode 100644
index 056868695..000000000
--- a/src/lib/go/parser/parser.go
+++ /dev/null
@@ -1,1975 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// A parser for Go source text. The input is a stream of lexical tokens
-// provided via the Scanner interface. The output is an abstract syntax
-// tree (AST) representing the Go source. The parser is invoked by calling
-// Parse.
-//
-package parser
-
-import (
-	"container/vector";
-	"fmt";
-	"go/ast";
-	"go/scanner";
-	"go/token";
-	"io";
-	"os";
-)
-
-
-// A parser 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 {
-	pos := "";
-	if e.Pos.IsValid() {
-		pos = fmt.Sprintf("%d:%d: ", e.Pos.Line, e.Pos.Column);
-	}
-	return pos + e.Msg;
-}
-
-
-// Parser errors are returned as an ErrorList.
-type ErrorList []*Error
-
-
-// ErrorList implements the SortInterface.
-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  { return p[i].Pos.Offset < p[j].Pos.Offset; }
-
-
-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);
-}
-
-
-type interval struct {
-	beg, end int;
-}
-
-
-// The parser structure holds the parser's internal state.
-type parser struct {
-	errors vector.Vector;
-	scanner scanner.Scanner;
-
-	// Tracing/debugging
-	mode uint;  // parsing mode
-	trace bool;  // == (mode & Trace != 0)
-	indent uint;  // indentation used for tracing output
-
-	// Comments
-	comments vector.Vector;  // list of collected, unassociated comments
-	last_doc interval;  // last comments interval of consecutive comments
-
-	// The next token
-	pos token.Position;  // token position
-	tok token.Token;  // one token look-ahead
-	lit []byte;  // token literal
-
-	// Non-syntactic parser control
-	opt_semi bool;  // true if semicolon separator is optional in statement list
-	expr_lev int;  // < 0: in control clause, >= 0: in expression
-};
-
-
-// noPos is used when there is no corresponding source position for a token
-var noPos token.Position;
-
-
-// ----------------------------------------------------------------------------
-// Parsing support
-
-func (p *parser) printTrace(a ...) {
-	const dots =
-		". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . "
-		". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ";
-	const n = uint(len(dots));
-	fmt.Printf("%5d:%3d: ", p.pos.Line, p.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;
-}
-
-
-func un/*trace*/(p *parser) {
-	p.indent--;
-	p.printTrace(")");
-}
-
-
-func (p *parser) next0() {
-	// Because of one-token look-ahead, print the previous token
-	// when tracing as it provides a more readable output. The
-	// very first token (p.pos.Line == 0) is not initialized (it
-	// is token.ILLEGAL), so don't print it .
-	if p.trace && p.pos.Line > 0 {
-		s := p.tok.String();
-		switch {
-		case p.tok.IsLiteral():
-			p.printTrace(s, string(p.lit));
-		case p.tok.IsOperator(), p.tok.IsKeyword():
-			p.printTrace("\"" + s + "\"");
-		default:
-			p.printTrace(s);
-		}
-	}
-
-	p.pos, p.tok, p.lit = p.scanner.Scan();
-	p.opt_semi = false;
-}
-
-
-// Collect a comment in the parser's comment list and return the line
-// on which the comment ends.
-//
-func (p *parser) collectComment() int {
-	// For /*-style comments, the comment may end on a different line.
-	// Scan the comment for '\n' chars and adjust the end line accordingly.
-	// (Note that the position of the next token may be even further down
-	// as there may be more whitespace lines after the comment.)
-	endline := p.pos.Line;
-	if p.lit[1] == '*' {
-		for _, b := range p.lit {
-			if b == '\n' {
-				endline++;
-			}
-		}
-	}
-	p.comments.Push(&ast.Comment{p.pos, p.lit, endline});
-	p.next0();
-
-	return endline;
-}
-
-
-func (p *parser) getComments() interval {
-	// group adjacent comments, an empty line terminates a group
-	beg := p.comments.Len();
-	endline := p.pos.Line;
-	for p.tok == token.COMMENT && endline+1 >= p.pos.Line {
-		endline = p.collectComment();
-	}
-	end := p.comments.Len();
-	return interval {beg, end};
-}
-
-
-func (p *parser) getDoc() ast.Comments {
-	doc := p.last_doc;
-	n := doc.end - doc.beg;
-
-	if n <= 0 || p.comments.At(doc.end - 1).(*ast.Comment).EndLine + 1 < p.pos.Line {
-		// no comments or empty line between last comment and current token;
-		// do not use as documentation
-		return nil;
-	}
-
-	// found immediately adjacent comment interval;
-	// use as documentation
-	c := make(ast.Comments, n);
-	for i := 0; i < n; i++ {
-		c[i] = p.comments.At(doc.beg + i).(*ast.Comment);
-	}
-
-	// remove comments from the general list
-	p.comments.Cut(doc.beg, doc.end);
-
-	return c;
-}
-
-
-func (p *parser) next() {
-	p.next0();
-	p.last_doc = interval{0, 0};
-	for p.tok == token.COMMENT {
-		p.last_doc = p.getComments();
-	}
-}
-
-
-// The parser implements scanner.Error.
-func (p *parser) Error(pos token.Position, msg string) {
-	// Don't collect errors that are on the same line as the previous error
-	// in the hope to reduce the number of spurious errors due to incorrect
-	// parser synchronization.
-	if p.errors.Len() == 0 || p.errors.Last().(*Error).Pos.Line != pos.Line {
-		p.errors.Push(&Error{pos, msg});
-	}
-}
-
-
-func (p *parser) error_expected(pos token.Position, msg string) {
-	msg = "expected " + msg;
-	if pos.Offset == p.pos.Offset {
-		// the error happened at the current position;
-		// make the error message more specific
-		msg += ", found '" + p.tok.String() + "'";
-		if p.tok.IsLiteral() {
-			msg += " " + string(p.lit);
-		}
-	}
-	p.Error(pos, msg);
-}
-
-
-func (p *parser) expect(tok token.Token) token.Position {
-	pos := p.pos;
-	if p.tok != tok {
-		p.error_expected(pos, "'" + tok.String() + "'");
-	}
-	p.next();  // make progress in any case
-	return pos;
-}
-
-
-// ----------------------------------------------------------------------------
-// Common productions
-
-func (p *parser) tryType() ast.Expr;
-func (p *parser) parseStringList(x *ast.StringLit) []*ast.StringLit
-func (p *parser) parseExpression() ast.Expr;
-func (p *parser) parseStatement() ast.Stmt;
-func (p *parser) parseDeclaration() ast.Decl;
-
-
-func (p *parser) parseIdent() *ast.Ident {
-	if p.tok == token.IDENT {
-		x := &ast.Ident{p.pos, string(p.lit)};
-		p.next();
-		return x;
-	}
-	p.expect(token.IDENT);  // use expect() error handling
-	return &ast.Ident{p.pos, ""};
-}
-
-
-func (p *parser) parseIdentList(x ast.Expr) []*ast.Ident {
-	if p.trace {
-		defer un(trace(p, "IdentList"));
-	}
-
-	list := vector.New(0);
-	if x == nil {
-		x = p.parseIdent();
-	}
-	list.Push(x);
-	for p.tok == token.COMMA {
-		p.next();
-		list.Push(p.parseIdent());
-	}
-
-	// convert vector
-	idents := make([]*ast.Ident, list.Len());
-	for i := 0; i < list.Len(); i++ {
-		idents[i] = list.At(i).(*ast.Ident);
-	}
-
-	return idents;
-}
-
-
-func (p *parser) parseExpressionList() []ast.Expr {
-	if p.trace {
-		defer un(trace(p, "ExpressionList"));
-	}
-
-	list := vector.New(0);
-	list.Push(p.parseExpression());
-	for p.tok == token.COMMA {
-		p.next();
-		list.Push(p.parseExpression());
-	}
-
-	// convert list
-	exprs := make([]ast.Expr, list.Len());
-	for i := 0; i < list.Len(); i++ {
-		exprs[i] = list.At(i).(ast.Expr);
-	}
-
-	return exprs;
-}
-
-
-// ----------------------------------------------------------------------------
-// Types
-
-func (p *parser) parseType() ast.Expr {
-	if p.trace {
-		defer un(trace(p, "Type"));
-	}
-
-	typ := p.tryType();
-
-	if typ == nil {
-		p.error_expected(p.pos, "type");
-		p.next();  // make progress
-		return &ast.BadExpr{p.pos};
-	}
-
-	return typ;
-}
-
-
-func (p *parser) parseQualifiedIdent() ast.Expr {
-	if p.trace {
-		defer un(trace(p, "QualifiedIdent"));
-	}
-
-	var x ast.Expr = p.parseIdent();
-	if p.tok == token.PERIOD {
-		// first identifier is a package identifier
-		p.next();
-		sel := p.parseIdent();
-		x = &ast.SelectorExpr{x, sel};
-	}
-	return x;
-}
-
-
-func (p *parser) parseTypeName() ast.Expr {
-	if p.trace {
-		defer un(trace(p, "TypeName"));
-	}
-
-	return p.parseQualifiedIdent();
-}
-
-
-func (p *parser) parseArrayType(ellipsis_ok bool) ast.Expr {
-	if p.trace {
-		defer un(trace(p, "ArrayType"));
-	}
-
-	lbrack := p.expect(token.LBRACK);
-	var len ast.Expr;
-	if ellipsis_ok && p.tok == token.ELLIPSIS {
-		len = &ast.Ellipsis{p.pos};
-		p.next();
-	} else if p.tok != token.RBRACK {
-		len = p.parseExpression();
-	}
-	p.expect(token.RBRACK);
-	elt := p.parseType();
-
-	return &ast.ArrayType{lbrack, len, elt};
-}
-
-
-func (p *parser) makeIdentList(list *vector.Vector) []*ast.Ident {
-	idents := make([]*ast.Ident, list.Len());
-	for i := 0; i < list.Len(); i++ {
-		ident, is_ident := list.At(i).(*ast.Ident);
-		if !is_ident {
-			pos := list.At(i).(ast.Expr).Pos();
-			p.error_expected(pos, "identifier");
-			idents[i] = &ast.Ident{pos, ""};
-		}
-		idents[i] = ident;
-	}
-	return idents;
-}
-
-
-func (p *parser) parseFieldDecl() *ast.Field {
-	if p.trace {
-		defer un(trace(p, "FieldDecl"));
-	}
-
-	doc := p.getDoc();
-
-	// a list of identifiers looks like a list of type names
-	list := vector.New(0);
-	for {
-		// TODO do not allow ()'s here
-		list.Push(p.parseType());
-		if p.tok == token.COMMA {
-			p.next();
-		} else {
-			break;
-		}
-	}
-
-	// if we had a list of identifiers, it must be followed by a type
-	typ := p.tryType();
-
-	// optional tag
-	var tag []*ast.StringLit;
-	if p.tok == token.STRING {
-		tag = p.parseStringList(nil);
-	}
-
-	// analyze case
-	var idents []*ast.Ident;
-	if typ != nil {
-		// IdentifierList Type
-		idents = p.makeIdentList(list);
-	} else {
-		// Type (anonymous field)
-		if list.Len() == 1 {
-			// TODO check that this looks like a type
-			typ = list.At(0).(ast.Expr);
-		} else {
-			p.error_expected(p.pos, "anonymous field");
-			typ = &ast.BadExpr{p.pos};
-		}
-	}
-
-	return &ast.Field{doc, idents, typ, tag};
-}
-
-
-func (p *parser) parseStructType() *ast.StructType {
-	if p.trace {
-		defer un(trace(p, "StructType"));
-	}
-
-	pos := p.expect(token.STRUCT);
-	var lbrace, rbrace token.Position;
-	var fields []*ast.Field;
-	if p.tok == token.LBRACE {
-		lbrace = p.pos;
-		p.next();
-
-		list := vector.New(0);
-		for p.tok != token.RBRACE && p.tok != token.EOF {
-			list.Push(p.parseFieldDecl());
-			if p.tok == token.SEMICOLON {
-				p.next();
-			} else {
-				break;
-			}
-		}
-		if p.tok == token.SEMICOLON {
-			p.next();
-		}
-
-		rbrace = p.expect(token.RBRACE);
-		p.opt_semi = true;
-
-		// convert vector
-		fields = make([]*ast.Field, list.Len());
-		for i := list.Len() - 1; i >= 0; i-- {
-			fields[i] = list.At(i).(*ast.Field);
-		}
-	}
-
-	return &ast.StructType{pos, lbrace, fields, rbrace};
-}
-
-
-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) tryParameterType(ellipsis_ok bool) ast.Expr {
-	if ellipsis_ok && p.tok == token.ELLIPSIS {
-		pos := p.pos;
-		p.next();
-		if p.tok != token.RPAREN {
-			// "..." always must be at the very end of a parameter list
-			p.Error(pos, "expected type, found '...'");
-		}
-		return &ast.Ellipsis{pos};
-	}
-	return p.tryType();
-}
-
-
-func (p *parser) parseParameterType(ellipsis_ok bool) ast.Expr {
-	typ := p.tryParameterType(ellipsis_ok);
-	if typ == nil {
-		p.error_expected(p.pos, "type");
-		p.next();  // make progress
-		typ = &ast.BadExpr{p.pos};
-	}
-	return typ;
-}
-
-
-func (p *parser) parseParameterDecl(ellipsis_ok bool) (*vector.Vector, ast.Expr) {
-	if p.trace {
-		defer un(trace(p, "ParameterDecl"));
-	}
-
-	// a list of identifiers looks like a list of type names
-	list := vector.New(0);
-	for {
-		// TODO do not allow ()'s here
-		list.Push(p.parseParameterType(ellipsis_ok));
-		if p.tok == token.COMMA {
-			p.next();
-		} else {
-			break;
-		}
-	}
-
-	// if we had a list of identifiers, it must be followed by a type
-	typ := p.tryParameterType(ellipsis_ok);
-
-	return list, typ;
-}
-
-
-func (p *parser) parseParameterList(ellipsis_ok bool) []*ast.Field {
-	if p.trace {
-		defer un(trace(p, "ParameterList"));
-	}
-
-	list, typ := p.parseParameterDecl(ellipsis_ok);
-	if typ != nil {
-		// IdentifierList Type
-		idents := p.makeIdentList(list);
-		list.Init(0);
-		list.Push(&ast.Field{nil, idents, typ, nil});
-
-		for p.tok == token.COMMA {
-			p.next();
-			idents := p.parseIdentList(nil);
-			typ := p.parseParameterType(ellipsis_ok);
-			list.Push(&ast.Field{nil, idents, typ, nil});
-		}
-
-	} else {
-		// Type { "," Type } (anonymous parameters)
-		// convert list of types into list of *Param
-		for i := 0; i < list.Len(); i++ {
-			list.Set(i, &ast.Field{nil, nil, list.At(i).(ast.Expr), nil});
-		}
-	}
-
-	// convert list
-	params := make([]*ast.Field, list.Len());
-	for i := 0; i < list.Len(); i++ {
-		params[i] = list.At(i).(*ast.Field);
-	}
-
-	return params;
-}
-
-
-func (p *parser) parseParameters(ellipsis_ok bool) []*ast.Field {
-	if p.trace {
-		defer un(trace(p, "Parameters"));
-	}
-
-	var params []*ast.Field;
-	p.expect(token.LPAREN);
-	if p.tok != token.RPAREN {
-		params = p.parseParameterList(ellipsis_ok);
-	}
-	p.expect(token.RPAREN);
-
-	return params;
-}
-
-
-func (p *parser) parseResult() []*ast.Field {
-	if p.trace {
-		defer un(trace(p, "Result"));
-	}
-
-	var results []*ast.Field;
-	if p.tok == token.LPAREN {
-		results = p.parseParameters(false);
-	} else if p.tok != token.FUNC {
-		typ := p.tryType();
-		if typ != nil {
-			results = make([]*ast.Field, 1);
-			results[0] = &ast.Field{nil, nil, typ, nil};
-		}
-	}
-
-	return results;
-}
-
-
-func (p *parser) parseSignature() (params []*ast.Field, results []*ast.Field) {
-	if p.trace {
-		defer un(trace(p, "Signature"));
-	}
-
-	params = p.parseParameters(true);
-	results = p.parseResult();
-
-	return params, results;
-}
-
-
-func (p *parser) parseFuncType() *ast.FuncType {
-	if p.trace {
-		defer un(trace(p, "FuncType"));
-	}
-
-	pos := p.expect(token.FUNC);
-	params, results := p.parseSignature();
-
-	return &ast.FuncType{pos, params, results};
-}
-
-
-func (p *parser) parseMethodSpec() *ast.Field {
-	if p.trace {
-		defer un(trace(p, "MethodSpec"));
-	}
-
-	doc := p.getDoc();
-	var idents []*ast.Ident;
-	var typ ast.Expr;
-	x := p.parseQualifiedIdent();
-	if tmp, is_ident := x.(*ast.Ident); is_ident && (p.tok == token.COMMA || p.tok == token.LPAREN) {
-		// methods
-		idents = p.parseIdentList(x);
-		params, results := p.parseSignature();
-		typ = &ast.FuncType{noPos, params, results};
-	} else {
-		// embedded interface
-		typ = x;
-	}
-
-	return &ast.Field{doc, idents, typ, nil};
-}
-
-
-func (p *parser) parseInterfaceType() *ast.InterfaceType {
-	if p.trace {
-		defer un(trace(p, "InterfaceType"));
-	}
-
-	pos := p.expect(token.INTERFACE);
-	var lbrace, rbrace token.Position;
-	var methods []*ast.Field;
-	if p.tok == token.LBRACE {
-		lbrace = p.pos;
-		p.next();
-
-		list := vector.New(0);
-		for p.tok == token.IDENT {
-			list.Push(p.parseMethodSpec());
-			if p.tok != token.RBRACE {
-				p.expect(token.SEMICOLON);
-			}
-		}
-
-		rbrace = p.expect(token.RBRACE);
-		p.opt_semi = true;
-
-		// convert vector
-		methods = make([]*ast.Field, list.Len());
-		for i := list.Len() - 1; i >= 0; i-- {
-			methods[i] = list.At(i).(*ast.Field);
-		}
-	}
-
-	return &ast.InterfaceType{pos, lbrace, methods, rbrace};
-}
-
-
-func (p *parser) parseMapType() *ast.MapType {
-	if p.trace {
-		defer un(trace(p, "MapType"));
-	}
-
-	pos := p.expect(token.MAP);
-	p.expect(token.LBRACK);
-	key := p.parseType();
-	p.expect(token.RBRACK);
-	value := p.parseType();
-
-	return &ast.MapType{pos, key, value};
-}
-
-
-func (p *parser) parseChanType() *ast.ChanType {
-	if p.trace {
-		defer un(trace(p, "ChanType"));
-	}
-
-	pos := p.pos;
-	dir := ast.SEND | ast.RECV;
-	if p.tok == token.CHAN {
-		p.next();
-		if p.tok == token.ARROW {
-			p.next();
-			dir = ast.SEND;
-		}
-	} else {
-		p.expect(token.ARROW);
-		p.expect(token.CHAN);
-		dir = ast.RECV;
-	}
-	value := p.parseType();
-
-	return &ast.ChanType{pos, dir, value};
-}
-
-
-func (p *parser) tryRawType(ellipsis_ok bool) ast.Expr {
-	switch p.tok {
-	case token.IDENT: return p.parseTypeName();
-	case token.LBRACK: return p.parseArrayType(ellipsis_ok);
-	case token.STRUCT: return p.parseStructType();
-	case token.MUL: return p.parsePointerType();
-	case token.FUNC: return p.parseFuncType();
-	case token.INTERFACE: return p.parseInterfaceType();
-	case token.MAP: return p.parseMapType();
-	case token.CHAN, token.ARROW: return p.parseChanType();
-	case token.LPAREN:
-		lparen := p.pos;
-		p.next();
-		typ := p.parseType();
-		rparen := p.expect(token.RPAREN);
-		return &ast.ParenExpr{lparen, typ, rparen};
-	}
-
-	// no type found
-	return nil;
-}
-
-
-func (p *parser) tryType() ast.Expr {
-	return p.tryRawType(false);
-}
-
-
-// ----------------------------------------------------------------------------
-// Blocks
-
-func makeStmtList(list *vector.Vector) []ast.Stmt {
-	stats := make([]ast.Stmt, list.Len());
-	for i := 0; i < list.Len(); i++ {
-		stats[i] = list.At(i).(ast.Stmt);
-	}
-	return stats;
-}
-
-
-func (p *parser) parseStatementList() []ast.Stmt {
-	if p.trace {
-		defer un(trace(p, "StatementList"));
-	}
-
-	list := vector.New(0);
-	expect_semi := false;
-	for p.tok != token.CASE && p.tok != token.DEFAULT && p.tok != token.RBRACE && p.tok != token.EOF {
-		if expect_semi {
-			p.expect(token.SEMICOLON);
-			expect_semi = false;
-		}
-		list.Push(p.parseStatement());
-		if p.tok == token.SEMICOLON {
-			p.next();
-		} else if p.opt_semi {
-			p.opt_semi = false;  // "consume" optional semicolon
-		} else {
-			expect_semi = true;
-		}
-	}
-
-	return makeStmtList(list);
-}
-
-
-func (p *parser) parseBlockStmt() *ast.BlockStmt {
-	if p.trace {
-		defer un(trace(p, "BlockStmt"));
-	}
-
-	lbrace := p.expect(token.LBRACE);
-	list := p.parseStatementList();
-	rbrace := p.expect(token.RBRACE);
-	p.opt_semi = true;
-
-	return &ast.BlockStmt{lbrace, list, rbrace};
-}
-
-
-// ----------------------------------------------------------------------------
-// Expressions
-
-func (p *parser) parseStringList(x *ast.StringLit) []*ast.StringLit {
-	if p.trace {
-		defer un(trace(p, "StringList"));
-	}
-
-	list := vector.New(0);
-	if x != nil {
-		list.Push(x);
-	}
-
-	for p.tok == token.STRING {
-		list.Push(&ast.StringLit{p.pos, p.lit});
-		p.next();
-	}
-
-	// convert list
-	strings := make([]*ast.StringLit, list.Len());
-	for i := 0; i < list.Len(); i++ {
-		strings[i] = list.At(i).(*ast.StringLit);
-	}
-
-	return strings;
-}
-
-
-func (p *parser) parseFuncLit() ast.Expr {
-	if p.trace {
-		defer un(trace(p, "FuncLit"));
-	}
-
-	typ := p.parseFuncType();
-	p.expr_lev++;
-	body := p.parseBlockStmt();
-	p.opt_semi = false;  // function body requires separating ";"
-	p.expr_lev--;
-
-	return &ast.FuncLit{typ, body};
-}
-
-
-// parseOperand may return an expression or a raw type (incl. array
-// types of the form [...]T. Callers must verify the result.
-//
-func (p *parser) parseOperand() ast.Expr {
-	if p.trace {
-		defer un(trace(p, "Operand"));
-	}
-
-	switch p.tok {
-	case token.IDENT:
-		return p.parseIdent();
-
-	case token.INT:
-		x := &ast.IntLit{p.pos, p.lit};
-		p.next();
-		return x;
-
-	case token.FLOAT:
-		x := &ast.FloatLit{p.pos, p.lit};
-		p.next();
-		return x;
-
-	case token.CHAR:
-		x := &ast.CharLit{p.pos, p.lit};
-		p.next();
-		return x;
-
-	case token.STRING:
-		x := &ast.StringLit{p.pos, p.lit};
-		p.next();
-		if p.tok == token.STRING {
-			return &ast.StringList{p.parseStringList(x)};
-		}
-		return x;
-
-	case token.LPAREN:
-		lparen := p.pos;
-		p.next();
-		p.expr_lev++;
-		x := p.parseExpression();
-		p.expr_lev--;
-		rparen := p.expect(token.RPAREN);
-		return &ast.ParenExpr{lparen, x, rparen};
-
-	case token.FUNC:
-		return p.parseFuncLit();
-
-	default:
-		t := p.tryRawType(true);  // could be type for composite literal
-		if t != nil {
-			return t;
-		}
-	}
-
-	p.error_expected(p.pos, "operand");
-	p.next();  // make progress
-	return &ast.BadExpr{p.pos};
-}
-
-
-func (p *parser) parseSelectorOrTypeAssertion(x ast.Expr) ast.Expr {
-	if p.trace {
-		defer un(trace(p, "SelectorOrTypeAssertion"));
-	}
-
-	p.expect(token.PERIOD);
-	if p.tok == token.IDENT {
-		// selector
-		sel := p.parseIdent();
-		return &ast.SelectorExpr{x, sel};
-	}
-
-	// type assertion
-	p.expect(token.LPAREN);
-	var typ ast.Expr;
-	if p.tok == token.TYPE {
-		// special case for type switch
-		typ = &ast.Ident{p.pos, "type"};
-		p.next();
-	} else {
-		typ = p.parseType();
-	}
-	p.expect(token.RPAREN);
-
-	return &ast.TypeAssertExpr{x, typ};
-}
-
-
-func (p *parser) parseIndex(x ast.Expr) ast.Expr {
-	if p.trace {
-		defer un(trace(p, "Index"));
-	}
-
-	p.expect(token.LBRACK);
-	p.expr_lev++;
-	begin := p.parseExpression();
-	var end ast.Expr;
-	if p.tok == token.COLON {
-		p.next();
-		end = p.parseExpression();
-	}
-	p.expr_lev--;
-	p.expect(token.RBRACK);
-
-	return &ast.IndexExpr{x, begin, end};
-}
-
-
-func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
-	if p.trace {
-		defer un(trace(p, "CallOrConversion"));
-	}
-
-	lparen := p.expect(token.LPAREN);
-	var args []ast.Expr;
-	if p.tok != token.RPAREN {
-		args = p.parseExpressionList();
-	}
-	rparen := p.expect(token.RPAREN);
-
-	return &ast.CallExpr{fun, lparen, args, rparen};
-}
-
-
-func (p *parser) parseElement() ast.Expr {
-	if p.trace {
-		defer un(trace(p, "Element"));
-	}
-
-	x := p.parseExpression();
-	if p.tok == token.COLON {
-		colon := p.pos;
-		p.next();
-		x = &ast.KeyValueExpr{x, colon, p.parseExpression()};
-	}
-
-	return x;
-}
-
-
-func (p *parser) parseElementList() []ast.Expr {
-	if p.trace {
-		defer un(trace(p, "ElementList"));
-	}
-
-	list := vector.New(0);
-	for p.tok != token.RBRACE && p.tok != token.EOF {
-		list.Push(p.parseElement());
-		if p.tok == token.COMMA {
-			p.next();
-		} else {
-			break;
-		}
-	}
-
-	// convert list
-	elts := make([]ast.Expr, list.Len());
-	for i := 0; i < list.Len(); i++ {
-		elts[i] = list.At(i).(ast.Expr);
-	}
-
-	return elts;
-}
-
-
-func (p *parser) parseCompositeLit(typ ast.Expr) ast.Expr {
-	if p.trace {
-		defer un(trace(p, "CompositeLit"));
-	}
-
-	lbrace := p.expect(token.LBRACE);
-	var elts []ast.Expr;
-	if p.tok != token.RBRACE {
-		elts = p.parseElementList();
-	}
-	rbrace := p.expect(token.RBRACE);
-	return &ast.CompositeLit{typ, lbrace, elts, rbrace};
-}
-
-
-// TODO Consider different approach to checking syntax after parsing:
-//      Provide a arguments (set of flags) to parsing functions
-//      restricting what they are syupposed to accept depending
-//      on context.
-
-// checkExpr checks that x is an expression (and not a type).
-func (p *parser) checkExpr(x ast.Expr) ast.Expr {
-	// TODO should provide predicate in AST nodes
-	switch t := x.(type) {
-	case *ast.BadExpr:
-	case *ast.Ident:
-	case *ast.IntLit:
-	case *ast.FloatLit:
-	case *ast.CharLit:
-	case *ast.StringLit:
-	case *ast.StringList:
-	case *ast.FuncLit:
-	case *ast.CompositeLit:
-	case *ast.ParenExpr:
-	case *ast.SelectorExpr:
-	case *ast.IndexExpr:
-	case *ast.TypeAssertExpr:
-	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.error_expected(x.Pos(), "expression");
-			x = &ast.BadExpr{x.Pos()};
-		}
-	case *ast.BinaryExpr:
-	default:
-		// all other nodes are not proper expressions
-		p.error_expected(x.Pos(), "expression");
-		x = &ast.BadExpr{x.Pos()};
-	}
-	return x;
-}
-
-
-// isTypeName returns true iff x is type name.
-func isTypeName(x ast.Expr) bool {
-	// TODO should provide predicate in AST nodes
-	switch t := x.(type) {
-	case *ast.BadExpr:
-	case *ast.Ident:
-	case *ast.ParenExpr: return isTypeName(t.X);  // TODO should (TypeName) be illegal?
-	case *ast.SelectorExpr: return isTypeName(t.X);
-	default: return false;  // all other nodes are not type names
-	}
-	return true;
-}
-
-
-// isCompositeLitType returns true iff x is a legal composite literal type.
-func isCompositeLitType(x ast.Expr) bool {
-	// TODO should provide predicate in AST nodes
-	switch t := x.(type) {
-	case *ast.BadExpr:
-	case *ast.Ident:
-	case *ast.ParenExpr: return isCompositeLitType(t.X);
-	case *ast.SelectorExpr: return isTypeName(t.X);
-	case *ast.ArrayType:
-	case *ast.StructType:
-	case *ast.MapType:
-	default: return false;  // all other nodes are not legal composite literal types
-	}
-	return true;
-}
-
-
-// checkExprOrType checks that x is an expression or a type
-// (and not a raw type such as [...]T).
-//
-func (p *parser) checkExprOrType(x ast.Expr) ast.Expr {
-	// TODO should provide predicate in AST nodes
-	switch t := x.(type) {
-	case *ast.UnaryExpr:
-		if t.Op == token.RANGE {
-			// the range operator is only allowed at the top of a for statement
-			p.error_expected(x.Pos(), "expression");
-			x = &ast.BadExpr{x.Pos()};
-		}
-	case *ast.ArrayType:
-		if len, is_ellipsis := t.Len.(*ast.Ellipsis); is_ellipsis {
-			p.Error(len.Pos(), "expected array length, found '...'");
-			x = &ast.BadExpr{x.Pos()};
-		}
-	}
-
-	// all other nodes are expressions or types
-	return x;
-}
-
-
-func (p *parser) parsePrimaryExpr() ast.Expr {
-	if p.trace {
-		defer un(trace(p, "PrimaryExpr"));
-	}
-
-	x := p.parseOperand();
-L:	for {
-		switch p.tok {
-		case token.PERIOD: x = p.parseSelectorOrTypeAssertion(p.checkExpr(x));
-		case token.LBRACK: x = p.parseIndex(p.checkExpr(x));
-		case token.LPAREN: x = p.parseCallOrConversion(p.checkExprOrType(x));
-		case token.LBRACE:
-			if isCompositeLitType(x) && (p.expr_lev >= 0 || !isTypeName(x)) {
-				x = p.parseCompositeLit(x);
-			} else {
-				break L;
-			}
-		default:
-			break L;
-		}
-	}
-
-	return p.checkExprOrType(x);
-}
-
-
-func (p *parser) parseUnaryExpr() ast.Expr {
-	if p.trace {
-		defer un(trace(p, "UnaryExpr"));
-	}
-
-	switch p.tok {
-	case token.ADD, token.SUB, token.NOT, token.XOR, token.ARROW, token.AND, token.RANGE:
-		pos, op := p.pos, p.tok;
-		p.next();
-		x := p.parseUnaryExpr();
-		return &ast.UnaryExpr{pos, op, p.checkExpr(x)};
-
-	case token.MUL:
-		// unary "*" expression or pointer type
-		pos := p.pos;
-		p.next();
-		x := p.parseUnaryExpr();
-		return &ast.StarExpr{pos, p.checkExprOrType(x)};
-	}
-
-	return p.parsePrimaryExpr();
-}
-
-
-func (p *parser) parseBinaryExpr(prec1 int) ast.Expr {
-	if p.trace {
-		defer un(trace(p, "BinaryExpr"));
-	}
-
-	x := p.parseUnaryExpr();
-	for prec := p.tok.Precedence(); prec >= prec1; prec-- {
-		for p.tok.Precedence() == prec {
-			pos, op := p.pos, p.tok;
-			p.next();
-			y := p.parseBinaryExpr(prec + 1);
-			x = &ast.BinaryExpr{p.checkExpr(x), pos, op, p.checkExpr(y)};
-		}
-	}
-
-	return x;
-}
-
-
-func (p *parser) parseExpression() ast.Expr {
-	if p.trace {
-		defer un(trace(p, "Expression"));
-	}
-
-	return p.parseBinaryExpr(token.LowestPrec + 1);
-}
-
-
-// ----------------------------------------------------------------------------
-// Statements
-
-
-func (p *parser) parseSimpleStmt(label_ok bool) ast.Stmt {
-	if p.trace {
-		defer un(trace(p, "SimpleStmt"));
-	}
-
-	x := p.parseExpressionList();
-
-	switch p.tok {
-	case token.COLON:
-		// labeled statement
-		p.next();
-		if label_ok && len(x) == 1 {
-			if label, is_ident := x[0].(*ast.Ident); is_ident {
-				return &ast.LabeledStmt{label, p.parseStatement()};
-			}
-		}
-		p.Error(x[0].Pos(), "illegal label declaration");
-		return &ast.BadStmt{x[0].Pos()};
-
-	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.parseExpressionList();
-		if len(x) > 1 && len(y) > 1 && len(x) != len(y) {
-			p.Error(x[0].Pos(), "arity of lhs doesn't match rhs");
-		}
-		return &ast.AssignStmt{x, pos, tok, y};
-	}
-
-	if len(x) > 1 {
-		p.Error(x[0].Pos(), "only one expression allowed");
-		// continue with first expression
-	}
-
-	if p.tok == token.INC || p.tok == token.DEC {
-		// increment or decrement
-		s := &ast.IncDecStmt{x[0], p.tok};
-		p.next();  // consume "++" or "--"
-		return s;
-	}
-
-	// expression
-	return &ast.ExprStmt{x[0]};
-}
-
-
-func (p *parser) parseCallExpr() *ast.CallExpr {
-	x := p.parseExpression();
-	if call, is_call := x.(*ast.CallExpr); is_call {
-		return call;
-	}
-	p.error_expected(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();
-	if call != nil {
-		return &ast.GoStmt{pos, call};
-	}
-	return &ast.BadStmt{pos};
-}
-
-
-func (p *parser) parseDeferStmt() ast.Stmt {
-	if p.trace {
-		defer un(trace(p, "DeferStmt"));
-	}
-
-	pos := p.expect(token.DEFER);
-	call := p.parseCallExpr();
-	if call != nil {
-		return &ast.DeferStmt{pos, call};
-	}
-	return &ast.BadStmt{pos};
-}
-
-
-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.parseExpressionList();
-	}
-
-	return &ast.ReturnStmt{pos, x};
-}
-
-
-func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt {
-	if p.trace {
-		defer un(trace(p, "BranchStmt"));
-	}
-
-	s := &ast.BranchStmt{p.pos, tok, nil};
-	p.expect(tok);
-	if tok != token.FALLTHROUGH && p.tok == token.IDENT {
-		s.Label = p.parseIdent();
-	}
-
-	return s;
-}
-
-
-func (p *parser) isExpr(s ast.Stmt) bool {
-	if s == nil {
-		return true;
-	}
-	dummy, is_expr := s.(*ast.ExprStmt);
-	return is_expr;
-}
-
-
-func (p *parser) makeExpr(s ast.Stmt) ast.Expr {
-	if s == nil {
-		return nil;
-	}
-	if es, is_expr := s.(*ast.ExprStmt); is_expr {
-		return p.checkExpr(es.X);
-	}
-	p.Error(s.Pos(), "expected condition, found simple statement");
-	return &ast.BadExpr{s.Pos()};
-}
-
-
-func (p *parser) parseControlClause(isForStmt bool) (s1, s2, s3 ast.Stmt) {
-	if p.tok != token.LBRACE {
-		prev_lev := p.expr_lev;
-		p.expr_lev = -1;
-
-		if p.tok != token.SEMICOLON {
-			s1 = p.parseSimpleStmt(false);
-		}
-		if p.tok == token.SEMICOLON {
-			p.next();
-			if p.tok != token.LBRACE && p.tok != token.SEMICOLON {
-				s2 = p.parseSimpleStmt(false);
-			}
-			if isForStmt {
-				// for statements have a 3rd section
-				p.expect(token.SEMICOLON);
-				if p.tok != token.LBRACE {
-					s3 = p.parseSimpleStmt(false);
-				}
-			}
-		} else {
-			s1, s2 = nil, s1;
-		}
-
-		p.expr_lev = prev_lev;
-	}
-
-	return s1, s2, s3;
-}
-
-
-func (p *parser) parseIfStmt() *ast.IfStmt {
-	if p.trace {
-		defer un(trace(p, "IfStmt"));
-	}
-
-	pos := p.expect(token.IF);
-	s1, s2, dummy := p.parseControlClause(false);
-	body := p.parseBlockStmt();
-	var else_ ast.Stmt;
-	if p.tok == token.ELSE {
-		p.next();
-		else_ = p.parseStatement();
-	}
-
-	return &ast.IfStmt{pos, s1, p.makeExpr(s2), body, else_};
-}
-
-
-func (p *parser) parseCaseClause() *ast.CaseClause {
-	if p.trace {
-		defer un(trace(p, "CaseClause"));
-	}
-
-	// SwitchCase
-	pos := p.pos;
-	var x []ast.Expr;
-	if p.tok == token.CASE {
-		p.next();
-		x = p.parseExpressionList();
-	} else {
-		p.expect(token.DEFAULT);
-	}
-
-	colon := p.expect(token.COLON);
-	body := p.parseStatementList();
-
-	return &ast.CaseClause{pos, x, colon, body};
-}
-
-
-func (p *parser) parseTypeCaseClause() *ast.TypeCaseClause {
-	if p.trace {
-		defer un(trace(p, "CaseClause"));
-	}
-
-	// TypeSwitchCase
-	pos := p.pos;
-	var typ ast.Expr;
-	if p.tok == token.CASE {
-		p.next();
-		typ = p.parseType();
-	} else {
-		p.expect(token.DEFAULT);
-	}
-
-	colon := p.expect(token.COLON);
-	body := p.parseStatementList();
-
-	return &ast.TypeCaseClause{pos, typ, colon, body};
-}
-
-
-func (p *parser) parseSwitchStmt() ast.Stmt {
-	if p.trace {
-		defer un(trace(p, "SwitchStmt"));
-	}
-
-	pos := p.expect(token.SWITCH);
-	s1, s2, dummy := p.parseControlClause(false);
-
-	if p.isExpr(s2) {
-		// expression switch
-		lbrace := p.expect(token.LBRACE);
-		cases := vector.New(0);
-		for p.tok == token.CASE || p.tok == token.DEFAULT {
-			cases.Push(p.parseCaseClause());
-		}
-		rbrace := p.expect(token.RBRACE);
-		p.opt_semi = true;
-		body := &ast.BlockStmt{lbrace, makeStmtList(cases), rbrace};
-		return &ast.SwitchStmt{pos, s1, p.makeExpr(s2), body};
-	}
-
-	// type switch
-	// TODO do all the checks!
-	lbrace := p.expect(token.LBRACE);
-	cases := vector.New(0);
-	for p.tok == token.CASE || p.tok == token.DEFAULT {
-		cases.Push(p.parseTypeCaseClause());
-	}
-	rbrace := p.expect(token.RBRACE);
-	p.opt_semi = true;
-	body := &ast.BlockStmt{lbrace, makeStmtList(cases), rbrace};
-	return &ast.TypeSwitchStmt{pos, s1, s2, body};
-}
-
-
-func (p *parser) parseCommClause() *ast.CommClause {
-	if p.trace {
-		defer un(trace(p, "CommClause"));
-	}
-
-	// CommCase
-	pos := p.pos;
-	var tok token.Token;
-	var lhs, rhs ast.Expr;
-	if p.tok == token.CASE {
-		p.next();
-		if p.tok == token.ARROW {
-			// RecvExpr without assignment
-			rhs = p.parseExpression();
-		} else {
-			// SendExpr or RecvExpr
-			rhs = p.parseExpression();
-			if p.tok == token.ASSIGN || p.tok == token.DEFINE {
-				// RecvExpr with assignment
-				tok = p.tok;
-				p.next();
-				lhs = rhs;
-				if p.tok == token.ARROW {
-					rhs = p.parseExpression();
-				} else {
-					p.expect(token.ARROW);  // use expect() error handling
-				}
-			}
-			// else SendExpr
-		}
-	} else {
-		p.expect(token.DEFAULT);
-	}
-
-	colon := p.expect(token.COLON);
-	body := p.parseStatementList();
-
-	return &ast.CommClause{pos, tok, lhs, rhs, colon, body};
-}
-
-
-func (p *parser) parseSelectStmt() *ast.SelectStmt {
-	if p.trace {
-		defer un(trace(p, "SelectStmt"));
-	}
-
-	pos := p.expect(token.SELECT);
-	lbrace := p.expect(token.LBRACE);
-	cases := vector.New(0);
-	for p.tok == token.CASE || p.tok == token.DEFAULT {
-		cases.Push(p.parseCommClause());
-	}
-	rbrace := p.expect(token.RBRACE);
-	p.opt_semi = true;
-	body := &ast.BlockStmt{lbrace, makeStmtList(cases), rbrace};
-
-	return &ast.SelectStmt{pos, body};
-}
-
-
-func (p *parser) parseForStmt() ast.Stmt {
-	if p.trace {
-		defer un(trace(p, "ForStmt"));
-	}
-
-	pos := p.expect(token.FOR);
-	s1, s2, s3 := p.parseControlClause(true);
-	body := p.parseBlockStmt();
-
-	if as, is_as := s2.(*ast.AssignStmt); is_as {
-		// possibly a for statement with a range clause; check assignment operator
-		if as.Tok != token.ASSIGN && as.Tok != token.DEFINE {
-			p.error_expected(as.TokPos, "'=' or ':='");
-			return &ast.BadStmt{pos};
-		}
-		// check lhs
-		var key, value ast.Expr;
-		switch len(as.Lhs) {
-		case 2:
-			value = as.Lhs[1];
-			fallthrough;
-		case 1:
-			key = as.Lhs[0];
-		default:
-			p.error_expected(as.Lhs[0].Pos(), "1 or 2 expressions");
-			return &ast.BadStmt{pos};
-		}
-		// check rhs
-		if len(as.Rhs) != 1 {
-			p.error_expected(as.Rhs[0].Pos(), "1 expressions");
-			return &ast.BadStmt{pos};
-		}
-		if rhs, is_unary := as.Rhs[0].(*ast.UnaryExpr); is_unary && rhs.Op == token.RANGE {
-			// rhs is range expression; check lhs
-			return &ast.RangeStmt{pos, key, value, as.TokPos, as.Tok, rhs.X, body}
-		} else {
-			p.error_expected(s2.Pos(), "range clause");
-			return &ast.BadStmt{pos};
-		}
-	} else {
-		// regular for statement
-		return &ast.ForStmt{pos, s1, p.makeExpr(s2), s3, body};
-	}
-
-	panic();  // unreachable
-	return nil;
-}
-
-
-func (p *parser) parseStatement() ast.Stmt {
-	if p.trace {
-		defer un(trace(p, "Statement"));
-	}
-
-	switch p.tok {
-	case token.CONST, token.TYPE, token.VAR:
-		return &ast.DeclStmt{p.parseDeclaration()};
-	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:  // unary operators
-		return p.parseSimpleStmt(true);
-	case token.GO:
-		return p.parseGoStmt();
-	case token.DEFER:
-		return p.parseDeferStmt();
-	case token.RETURN:
-		return p.parseReturnStmt();
-	case token.BREAK, token.CONTINUE, token.GOTO, token.FALLTHROUGH:
-		return p.parseBranchStmt(p.tok);
-	case token.LBRACE:
-		return p.parseBlockStmt();
-	case token.IF:
-		return p.parseIfStmt();
-	case token.SWITCH:
-		return p.parseSwitchStmt();
-	case token.SELECT:
-		return p.parseSelectStmt();
-	case token.FOR:
-		return p.parseForStmt();
-	case token.SEMICOLON, token.RBRACE:
-		// don't consume the ";", it is the separator following the empty statement
-		return &ast.EmptyStmt{p.pos};
-	}
-
-	// no statement found
-	p.error_expected(p.pos, "statement");
-	p.next();  // make progress
-	return &ast.BadStmt{p.pos};
-}
-
-
-// ----------------------------------------------------------------------------
-// Declarations
-
-type parseSpecFunction func(p *parser, doc ast.Comments) ast.Spec
-
-func parseImportSpec(p *parser, doc ast.Comments) ast.Spec {
-	if p.trace {
-		defer un(trace(p, "ImportSpec"));
-	}
-
-	var ident *ast.Ident;
-	if p.tok == token.PERIOD {
-		ident = &ast.Ident{p.pos, "."};
-		p.next();
-	} else if p.tok == token.IDENT {
-		ident = p.parseIdent();
-	}
-
-	var path []*ast.StringLit;
-	if p.tok == token.STRING {
-		path = p.parseStringList(nil);
-	} else {
-		p.expect(token.STRING);  // use expect() error handling
-	}
-
-	return &ast.ImportSpec{doc, ident, path};
-}
-
-
-func parseConstSpec(p *parser, doc ast.Comments) ast.Spec {
-	if p.trace {
-		defer un(trace(p, "ConstSpec"));
-	}
-
-	idents := p.parseIdentList(nil);
-	typ := p.tryType();
-	var values []ast.Expr;
-	if typ != nil || p.tok == token.ASSIGN {
-		p.expect(token.ASSIGN);
-		values = p.parseExpressionList();
-	}
-
-	return &ast.ValueSpec{doc, idents, typ, values};
-}
-
-
-func parseTypeSpec(p *parser, doc ast.Comments) ast.Spec {
-	if p.trace {
-		defer un(trace(p, "TypeSpec"));
-	}
-
-	ident := p.parseIdent();
-	typ := p.parseType();
-
-	return &ast.TypeSpec{doc, ident, typ};
-}
-
-
-func parseVarSpec(p *parser, doc ast.Comments) ast.Spec {
-	if p.trace {
-		defer un(trace(p, "VarSpec"));
-	}
-
-	idents := p.parseIdentList(nil);
-	typ := p.tryType();
-	var values []ast.Expr;
-	if typ == nil || p.tok == token.ASSIGN {
-		p.expect(token.ASSIGN);
-		values = p.parseExpressionList();
-	}
-
-	return &ast.ValueSpec{doc, idents, typ, values};
-}
-
-
-func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.GenDecl {
-	if p.trace {
-		defer un(trace(p, keyword.String() + "Decl"));
-	}
-
-	doc := p.getDoc();
-	pos := p.expect(keyword);
-	var lparen, rparen token.Position;
-	list := vector.New(0);
-	if p.tok == token.LPAREN {
-		lparen = p.pos;
-		p.next();
-		for p.tok != token.RPAREN && p.tok != token.EOF {
-			doc := p.getDoc();
-			list.Push(f(p, doc));
-			if p.tok == token.SEMICOLON {
-				p.next();
-			} else {
-				break;
-			}
-		}
-		rparen = p.expect(token.RPAREN);
-		p.opt_semi = true;
-	} else {
-		list.Push(f(p, doc));
-	}
-
-	// convert vector
-	specs := make([]ast.Spec, list.Len());
-	for i := 0; i < list.Len(); i++ {
-		specs[i] = list.At(i);
-	}
-	return &ast.GenDecl{doc, pos, keyword, lparen, specs, rparen};
-}
-
-
-func (p *parser) parseReceiver() *ast.Field {
-	if p.trace {
-		defer un(trace(p, "Receiver"));
-	}
-
-	pos := p.pos;
-	par := p.parseParameters(false);
-
-	// must have exactly one receiver
-	if len(par) != 1 || len(par) == 1 && len(par[0].Names) > 1 {
-		p.error_expected(pos, "exactly one receiver");
-		return &ast.Field{nil, nil, &ast.BadExpr{noPos}, nil};
-	}
-
-	recv := par[0];
-
-	// recv type must be TypeName or *TypeName
-	base := recv.Type;
-	if ptr, is_ptr := base.(*ast.StarExpr); is_ptr {
-		base = ptr.X;
-	}
-	if !isTypeName(base) {
-		p.error_expected(base.Pos(), "type name");
-	}
-
-	return recv;
-}
-
-
-func (p *parser) parseFunctionDecl() *ast.FuncDecl {
-	if p.trace {
-		defer un(trace(p, "FunctionDecl"));
-	}
-
-	doc := p.getDoc();
-	pos := p.expect(token.FUNC);
-
-	var recv *ast.Field;
-	if p.tok == token.LPAREN {
-		recv = p.parseReceiver();
-	}
-
-	ident := p.parseIdent();
-	params, results := p.parseSignature();
-
-	var body *ast.BlockStmt;
-	if p.tok == token.LBRACE {
-		body = p.parseBlockStmt();
-	}
-
-	return &ast.FuncDecl{doc, recv, ident, &ast.FuncType{pos, params, results}, body};
-}
-
-
-func (p *parser) parseDeclaration() 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.parseFunctionDecl();
-	default:
-		pos := p.pos;
-		p.error_expected(pos, "declaration");
-		p.next();  // make progress
-		return &ast.BadDecl{pos};
-	}
-
-	return p.parseGenDecl(p.tok, f);
-}
-
-
-// ----------------------------------------------------------------------------
-// Packages
-
-// The mode parameter to the Parse function 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
-)
-
-
-func (p *parser) parsePackage() *ast.Program {
-	if p.trace {
-		defer un(trace(p, "Program"));
-	}
-
-	// package clause
-	comment := p.getDoc();
-	pos := p.expect(token.PACKAGE);
-	ident := p.parseIdent();
-	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.errors.Len() == 0 && p.mode & PackageClauseOnly == 0 {
-		// import decls
-		list := vector.New(0);
-		for p.tok == token.IMPORT {
-			list.Push(p.parseGenDecl(token.IMPORT, parseImportSpec));
-			if p.tok == token.SEMICOLON {
-				p.next();
-			}
-		}
-
-		if p.mode & ImportsOnly == 0 {
-			// rest of package body
-			for p.tok != token.EOF {
-				list.Push(p.parseDeclaration());
-				if p.tok == token.SEMICOLON {
-					p.next();
-				}
-			}
-		}
-
-		// convert declaration list
-		decls = make([]ast.Decl, list.Len());
-		for i := 0; i < list.Len(); i++ {
-			decls[i] = list.At(i).(ast.Decl);
-		}
-	}
-
-	// convert comments list
-	comments := make([]*ast.Comment, p.comments.Len());
-	for i := 0; i < p.comments.Len(); i++ {
-		comments[i] = p.comments.At(i).(*ast.Comment);
-	}
-
-	return &ast.Program{comment, pos, ident, decls, comments};
-}
-
-
-// ----------------------------------------------------------------------------
-// Parsing of entire programs.
-
-func readSource(src interface{}) ([]byte, os.Error) {
-	if src != nil {
-		switch s := src.(type) {
-		case string:
-			return io.StringBytes(s), nil;
-		case []byte:
-			return s, nil;
-		case *io.ByteBuffer:
-			// is io.Read, but src is already available in []byte form
-			if s != nil {
-				return s.Data(), nil;
-			}
-		case io.Reader:
-			var buf io.ByteBuffer;
-			n, err := io.Copy(s, &buf);
-			if err != nil {
-				return nil, err;
-			}
-			return buf.Data(), nil;
-		}
-	}
-	return nil, os.ErrorString("invalid source");
-}
-
-
-// scannerMode returns the scanner mode bits given the parser's mode bits.
-func scannerMode(mode uint) uint {
-	if mode & ParseComments != 0 {
-		return scanner.ScanComments;
-	}
-	return 0;
-}
-
-
-// Parse parses a Go program.
-//
-// The program source src may be provided in a variety of formats. At the
-// moment the following types are supported: string, []byte, and io.Read.
-// The mode parameter controls the amount of source text parsed and other
-// optional parser functionality.
-//
-// Parse returns a complete AST if no error occured. Otherwise, if the
-// source couldn't be read, the returned program 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) and an ErrorList
-// describing the syntax errors.
-//
-func Parse(src interface{}, mode uint) (*ast.Program, os.Error) {
-	data, err := readSource(src);
-	if err != nil {
-		return nil, err;
-	}
-
-	// initialize parser state
-	var p parser;
-	p.errors.Init(0);
-	p.scanner.Init(data, &p, scannerMode(mode));
-	p.mode = mode;
-	p.trace = mode & Trace != 0;  // for convenience (p.trace is used frequently)
-	p.comments.Init(0);
-	p.next();
-
-	// parse program
-	prog := p.parsePackage();
-
-	// convert errors list, if any
-	if p.errors.Len() > 0 {
-		errors := make(ErrorList, p.errors.Len());
-		for i := 0; i < p.errors.Len(); i++ {
-			errors[i] = p.errors.At(i).(*Error);
-		}
-		return prog, errors;
-	}
-
-	return prog, nil;
-}
diff --git a/src/lib/go/parser/parser_test.go b/src/lib/go/parser/parser_test.go
deleted file mode 100644
index 887fcf80f..000000000
--- a/src/lib/go/parser/parser_test.go
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2009 The Go Authors. 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/ast";
-	"go/parser";
-	"os";
-	"testing";
-)
-
-
-var illegalInputs = []interface{} {
-	nil,
-	3.14,
-	[]byte(nil),
-	"foo!",
-}
-
-
-func TestParseIllegalInputs(t *testing.T) {
-	for _, src := range illegalInputs {
-		prog, err := Parse(src, 0);
-		if err == nil {
-			t.Errorf("Parse(%v) should have failed", src);
-		}
-	}
-}
-
-
-var validPrograms = []interface{} {
-	`package main`,
-	`package main import "fmt" func main() { fmt.Println("Hello, World!") }`,
-}
-
-
-func TestParseValidPrograms(t *testing.T) {
-	for _, src := range validPrograms {
-		prog, err := Parse(src, 0);
-		if err != nil {
-			t.Errorf("Parse(%q) failed: %v", src, err);
-		}
-	}
-}
-
-
-var validFiles = []string {
-	"parser.go",
-	"parser_test.go",
-}
-
-
-func TestParse3(t *testing.T) {
-	for _, filename := range validFiles {
-		src, err := os.Open(filename, os.O_RDONLY, 0);
-		defer src.Close();
-		if err != nil {
-			t.Fatalf("os.Open(%s): %v\n", filename, err);
-		}
-
-		prog, err := Parse(src, 0);
-		if err != nil {
-			t.Errorf("Parse(%q): %v", src, err);
-		}
-	}
-}
diff --git a/src/lib/go/scanner/Makefile b/src/lib/go/scanner/Makefile
deleted file mode 100644
index d47fecb7c..000000000
--- a/src/lib/go/scanner/Makefile
+++ /dev/null
@@ -1,60 +0,0 @@
-# Copyright 2009 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-# DO NOT EDIT.  Automatically generated by gobuild.
-# gobuild -m >Makefile
-
-D=/go/
-
-include $(GOROOT)/src/Make.$(GOARCH)
-AR=gopack
-
-default: packages
-
-clean:
-	rm -rf *.[$(OS)] *.a [$(OS)].out _obj
-
-test: packages
-	gotest
-
-coverage: packages
-	gotest
-	6cov -g `pwd` | grep -v '_test\.go:'
-
-%.$O: %.go
-	$(GC) -I_obj $*.go
-
-%.$O: %.c
-	$(CC) $*.c
-
-%.$O: %.s
-	$(AS) $*.s
-
-O1=\
-	scanner.$O\
-
-
-phases: a1
-_obj$D/scanner.a: phases
-
-a1: $(O1)
-	$(AR) grc _obj$D/scanner.a scanner.$O
-	rm -f $(O1)
-
-
-newpkg: clean
-	mkdir -p _obj$D
-	$(AR) grc _obj$D/scanner.a
-
-$(O1): newpkg
-$(O2): a1
-
-nuke: clean
-	rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/scanner.a
-
-packages: _obj$D/scanner.a
-
-install: packages
-	test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D
-	cp _obj$D/scanner.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/scanner.a
diff --git a/src/lib/go/scanner/scanner.go b/src/lib/go/scanner/scanner.go
deleted file mode 100644
index a90e6f259..000000000
--- a/src/lib/go/scanner/scanner.go
+++ /dev/null
@@ -1,501 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// A scanner for Go source text. Takes a []byte as source which can
-// then be tokenized through repeated calls to the Scan function.
-// For a sample use of a scanner, see the implementation of Tokenize.
-//
-package scanner
-
-import (
-	"go/token";
-	"strconv";
-	"unicode";
-	"utf8";
-)
-
-
-// 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);
-}
-
-
-// A Scanner holds the scanner's internal state while processing
-// a given text.  It can be allocated as part of another data
-// structure but must be initialized via Init before use. For
-// a sample use, see the implementation of Tokenize.
-//
-type Scanner struct {
-	// immutable state
-	src []byte;  // source
-	err ErrorHandler;  // error reporting; or nil
-	mode uint;  // scanning mode
-
-	// scanning state
-	pos token.Position;  // previous reading position (position before ch)
-	offset int;  // current reading offset (position after ch)
-	ch int;  // one char look-ahead
-
-	// 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.offset < len(S.src) {
-		S.pos.Offset = S.offset;
-		S.pos.Column++;
-		r, w := int(S.src[S.offset]), 1;
-		switch {
-		case r == '\n':
-			S.pos.Line++;
-			S.pos.Column = 0;
-		case r >= 0x80:
-			// not ASCII
-			r, w = utf8.DecodeRune(S.src[S.offset : len(S.src)]);
-		}
-		S.offset += w;
-		S.ch = r;
-	} else {
-		S.pos.Offset = len(S.src);
-		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
-)
-
-
-// Init prepares the scanner S to tokenize the text src. Calls to Scan
-// will use the error handler err if they encounter a syntax error and
-// err is not nil. Also, for each error encountered, the Scanner field
-// ErrorCount is incremented by one. The mode parameter determines how
-// comments and illegal characters are handled.
-//
-func (S *Scanner) Init(src []byte, err ErrorHandler, mode uint) {
-	// Explicitly initialize all fields since a scanner may be reused.
-	S.src = src;
-	S.err = err;
-	S.mode = mode;
-	S.pos = token.Position{0, 1, 0};
-	S.offset = 0;
-	S.ErrorCount = 0;
-	S.next();
-}
-
-
-func charString(ch int) string {
-	var s string;
-	switch ch {
-	case '\a': s = `\a`;
-	case '\b': s = `\b`;
-	case '\f': s = `\f`;
-	case '\n': s = `\n`;
-	case '\r': s = `\r`;
-	case '\t': s = `\t`;
-	case '\v': s = `\v`;
-	case '\\': s = `\\`;
-	case '\'': s = `\'`;
-	default  : s = string(ch);
-	}
-	return "'" + s + "' (U+" + strconv.Itob(ch, 16) + ")";
-}
-
-
-func (S *Scanner) error(pos token.Position, msg string) {
-	if S.err != nil {
-		S.err.Error(pos, msg);
-	}
-	S.ErrorCount++;
-}
-
-
-func (S *Scanner) expect(ch int) {
-	if S.ch != ch {
-		S.error(S.pos, "expected " + charString(ch) + ", found " + charString(S.ch));
-	}
-	S.next();  // always make progress
-}
-
-
-func (S *Scanner) scanComment(pos token.Position) {
-	// first '/' already consumed
-
-	if S.ch == '/' {
-		//-style comment
-		for S.ch >= 0 {
-			S.next();
-			if S.ch == '\n' {
-				S.next();  // '\n' belongs to the comment
-				return;
-			}
-		}
-
-	} else {
-		/*-style comment */
-		S.expect('*');
-		for S.ch >= 0 {
-			ch := S.ch;
-			S.next();
-			if ch == '*' && S.ch == '/' {
-				S.next();
-				return;
-			}
-		}
-	}
-
-	S.error(pos, "comment not terminated");
-}
-
-
-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.IsDecimalDigit(ch);
-}
-
-
-func (S *Scanner) scanIdentifier() token.Token {
-	pos := S.pos.Offset;
-	for isLetter(S.ch) || isDigit(S.ch) {
-		S.next();
-	}
-	return token.Lookup(S.src[pos : S.pos.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(seen_decimal_point bool) token.Token {
-	tok := token.INT;
-
-	if seen_decimal_point {
-		tok = token.FLOAT;
-		S.scanMantissa(10);
-		goto exponent;
-	}
-
-	if S.ch == '0' {
-		// int or float
-		S.next();
-		if S.ch == 'x' || S.ch == 'X' {
-			// hexadecimal int
-			S.next();
-			S.scanMantissa(16);
-		} else {
-			// octal int or float
-			S.scanMantissa(8);
-			if digitVal(S.ch) < 10 || S.ch == '.' || S.ch == 'e' || S.ch == 'E' {
-				// float
-				tok = token.FLOAT;
-				goto mantissa;
-			}
-			// octal int
-		}
-		goto exit;
-	}
-
-mantissa:
-	// decimal int or float
-	S.scanMantissa(10);
-
-	if S.ch == '.' {
-		// float
-		tok = token.FLOAT;
-		S.next();
-		S.scanMantissa(10)
-	}
-
-exponent:
-	if S.ch == 'e' || S.ch == 'E' {
-		// float
-		tok = token.FLOAT;
-		S.next();
-		if S.ch == '-' || S.ch == '+' {
-			S.next();
-		}
-		S.scanMantissa(10);
-	}
-
-exit:
-	return tok;
-}
-
-
-func (S *Scanner) scanDigits(base, length int) {
-	for length > 0 && digitVal(S.ch) < base {
-		S.next();
-		length--;
-	}
-	if length > 0 {
-		S.error(S.pos, "illegal char escape");
-	}
-}
-
-
-func (S *Scanner) scanEscape(quote int) {
-	pos := S.pos;
-	ch := S.ch;
-	S.next();
-	switch ch {
-	case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', quote:
-		// nothing to do
-	case '0', '1', '2', '3', '4', '5', '6', '7':
-		S.scanDigits(8, 3 - 1);  // 1 char read already
-	case 'x':
-		S.scanDigits(16, 2);
-	case 'u':
-		S.scanDigits(16, 4);
-	case 'U':
-		S.scanDigits(16, 8);
-	default:
-		S.error(pos, "illegal char escape");
-	}
-}
-
-
-func (S *Scanner) scanChar() {
-	// '\'' already consumed
-
-	ch := S.ch;
-	S.next();
-	if ch == '\\' {
-		S.scanEscape('\'');
-	}
-
-	S.expect('\'');
-}
-
-
-func (S *Scanner) scanString(pos token.Position) {
-	// '"' already consumed
-
-	for S.ch != '"' {
-		ch := S.ch;
-		S.next();
-		if ch == '\n' || ch < 0 {
-			S.error(pos, "string not terminated");
-			break;
-		}
-		if ch == '\\' {
-			S.scanEscape('"');
-		}
-	}
-
-	S.next();
-}
-
-
-func (S *Scanner) scanRawString(pos token.Position) {
-	// '`' already consumed
-
-	for S.ch != '`' {
-		ch := S.ch;
-		S.next();
-		if ch == '\n' || ch < 0 {
-			S.error(pos, "string not terminated");
-			break;
-		}
-	}
-
-	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 pos,
-// the token tok, and the literal text lit corresponding to the
-// token. The source end is indicated by token.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.
-//
-func (S *Scanner) Scan() (pos token.Position, tok token.Token, lit []byte) {
-scan_again:
-	// skip white space
-	for S.ch == ' ' || S.ch == '\t' || S.ch == '\n' || S.ch == '\r' {
-		S.next();
-	}
-
-	// current token start
-	pos, tok = S.pos, token.ILLEGAL;
-
-	// determine token value
-	switch ch := S.ch; {
-	case isLetter(ch):
-		tok = S.scanIdentifier();
-	case digitVal(ch) < 10:
-		tok = S.scanNumber(false);
-	default:
-		S.next();  // always make progress
-		switch ch {
-		case -1  : tok = token.EOF;
-		case '"' : tok = token.STRING; S.scanString(pos);
-		case '\'': tok = token.CHAR; S.scanChar();
-		case '`' : tok = token.STRING; S.scanRawString(pos);
-		case ':' : tok = S.switch2(token.COLON, token.DEFINE);
-		case '.' :
-			if digitVal(S.ch) < 10 {
-				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 ')': tok = token.RPAREN;
-		case '[': tok = token.LBRACK;
-		case ']': tok = token.RBRACK;
-		case '{': tok = token.LBRACE;
-		case '}': tok = token.RBRACE;
-		case '+': tok = S.switch3(token.ADD, token.ADD_ASSIGN, '+', token.INC);
-		case '-': tok = S.switch3(token.SUB, token.SUB_ASSIGN, '-', token.DEC);
-		case '*': tok = S.switch2(token.MUL, token.MUL_ASSIGN);
-		case '/':
-			if S.ch == '/' || S.ch == '*' {
-				S.scanComment(pos);
-				tok = token.COMMENT;
-				if S.mode & ScanComments == 0 {
-					goto scan_again;
-				}
-			} 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(pos, "illegal character " + charString(ch));
-			}
-		}
-	}
-
-	return pos, tok, S.src[pos.Offset : S.pos.Offset];
-}
-
-
-// Tokenize calls a function f with the token position, token value, and token
-// text for each token in the source src. The other parameters have the same
-// meaning as for the Init function. Tokenize keeps scanning until f returns
-// false (usually when the token value is token.EOF). The result is the number
-// of errors encountered.
-//
-func Tokenize(src []byte, err ErrorHandler, mode uint, f func (pos token.Position, tok token.Token, lit []byte) bool) int {
-	var s Scanner;
-	s.Init(src, err, mode);
-	for f(s.Scan()) {
-		// action happens in f
-	}
-	return s.ErrorCount;
-}
diff --git a/src/lib/go/scanner/scanner_test.go b/src/lib/go/scanner/scanner_test.go
deleted file mode 100644
index 0defece8b..000000000
--- a/src/lib/go/scanner/scanner_test.go
+++ /dev/null
@@ -1,276 +0,0 @@
-// Copyright 2009 The Go Authors. 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/scanner";
-	"go/token";
-	"io";
-	"testing";
-)
-
-
-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
-	elt{ token.COMMENT, "/* a comment */", special },
-	elt{ token.COMMENT, "// a comment \n", special },
-
-	// Identifiers and basic type literals
-	elt{ token.IDENT, "foobar", literal },
-	elt{ token.IDENT, "a۰۱۸", literal },
-	elt{ token.IDENT, "foo६४", literal },
-	elt{ token.IDENT, "bar9876", literal },
-	elt{ token.INT, "0", literal },
-	elt{ token.INT, "01234567", literal },
-	elt{ token.INT, "0xcafebabe", literal },
-	elt{ token.FLOAT, "0.", literal },
-	elt{ token.FLOAT, ".0", literal },
-	elt{ token.FLOAT, "3.14159265", literal },
-	elt{ token.FLOAT, "1e0", literal },
-	elt{ token.FLOAT, "1e+100", literal },
-	elt{ token.FLOAT, "1e-100", literal },
-	elt{ token.FLOAT, "2.71828e-1000", literal },
-	elt{ token.CHAR, "'a'", literal },
-	elt{ token.CHAR, "'\\000'", literal },
-	elt{ token.CHAR, "'\\xFF'", literal },
-	elt{ token.CHAR, "'\\uff16'", literal },
-	elt{ token.CHAR, "'\\U0000ff16'", literal },
-	elt{ token.STRING, "`foobar`", literal },
-
-	// Operators and delimitors
-	elt{ token.ADD, "+", operator },
-	elt{ token.SUB, "-", operator },
-	elt{ token.MUL, "*", operator },
-	elt{ token.QUO, "/", operator },
-	elt{ token.REM, "%", operator },
-
-	elt{ token.AND, "&", operator },
-	elt{ token.OR, "|", operator },
-	elt{ token.XOR, "^", operator },
-	elt{ token.SHL, "<<", operator },
-	elt{ token.SHR, ">>", operator },
-	elt{ token.AND_NOT, "&^", operator },
-
-	elt{ token.ADD_ASSIGN, "+=", operator },
-	elt{ token.SUB_ASSIGN, "-=", operator },
-	elt{ token.MUL_ASSIGN, "*=", operator },
-	elt{ token.QUO_ASSIGN, "/=", operator },
-	elt{ token.REM_ASSIGN, "%=", operator },
-
-	elt{ token.AND_ASSIGN, "&=", operator },
-	elt{ token.OR_ASSIGN, "|=", operator },
-	elt{ token.XOR_ASSIGN, "^=", operator },
-	elt{ token.SHL_ASSIGN, "<<=", operator },
-	elt{ token.SHR_ASSIGN, ">>=", operator },
-	elt{ token.AND_NOT_ASSIGN, "&^=", operator },
-
-	elt{ token.LAND, "&&", operator },
-	elt{ token.LOR, "||", operator },
-	elt{ token.ARROW, "<-", operator },
-	elt{ token.INC, "++", operator },
-	elt{ token.DEC, "--", operator },
-
-	elt{ token.EQL, "==", operator },
-	elt{ token.LSS, "<", operator },
-	elt{ token.GTR, ">", operator },
-	elt{ token.ASSIGN, "=", operator },
-	elt{ token.NOT, "!", operator },
-
-	elt{ token.NEQ, "!=", operator },
-	elt{ token.LEQ, "<=", operator },
-	elt{ token.GEQ, ">=", operator },
-	elt{ token.DEFINE, ":=", operator },
-	elt{ token.ELLIPSIS, "...", operator },
-
-	elt{ token.LPAREN, "(", operator },
-	elt{ token.LBRACK, "[", operator },
-	elt{ token.LBRACE, "{", operator },
-	elt{ token.COMMA, ",", operator },
-	elt{ token.PERIOD, ".", operator },
-
-	elt{ token.RPAREN, ")", operator },
-	elt{ token.RBRACK, "]", operator },
-	elt{ token.RBRACE, "}", operator },
-	elt{ token.SEMICOLON, ";", operator },
-	elt{ token.COLON, ":", operator },
-
-	// Keywords
-	elt{ token.BREAK, "break", keyword },
-	elt{ token.CASE, "case", keyword },
-	elt{ token.CHAN, "chan", keyword },
-	elt{ token.CONST, "const", keyword },
-	elt{ token.CONTINUE, "continue", keyword },
-
-	elt{ token.DEFAULT, "default", keyword },
-	elt{ token.DEFER, "defer", keyword },
-	elt{ token.ELSE, "else", keyword },
-	elt{ token.FALLTHROUGH, "fallthrough", keyword },
-	elt{ token.FOR, "for", keyword },
-
-	elt{ token.FUNC, "func", keyword },
-	elt{ token.GO, "go", keyword },
-	elt{ token.GOTO, "goto", keyword },
-	elt{ token.IF, "if", keyword },
-	elt{ token.IMPORT, "import", keyword },
-
-	elt{ token.INTERFACE, "interface", keyword },
-	elt{ token.MAP, "map", keyword },
-	elt{ token.PACKAGE, "package", keyword },
-	elt{ token.RANGE, "range", keyword },
-	elt{ token.RETURN, "return", keyword },
-
-	elt{ token.SELECT, "select", keyword },
-	elt{ token.STRUCT, "struct", keyword },
-	elt{ token.SWITCH, "switch", keyword },
-	elt{ token.TYPE, "type", keyword },
-	elt{ token.VAR, "var", keyword },
-}
-
-
-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;
-}
-
-
-// Verify that calling Scan() provides the correct results.
-func TestScan(t *testing.T) {
-	// make source
-	var src string;
-	for i, e := range tokens {
-		src += e.lit + whitespace;
-	}
-	whitespace_linecount := NewlineCount(whitespace);
-
-	// verify scan
-	index := 0;
-	eloc := token.Position{0, 1, 1};
-	nerrors := scanner.Tokenize(io.StringBytes(src), &TestErrorHandler{t}, scanner.ScanComments,
-		func (pos token.Position, tok token.Token, litb []byte) bool {
-			e := elt{token.EOF, "", special};
-			if index < len(tokens) {
-				e = tokens[index];
-			}
-			lit := string(litb);
-			if tok == token.EOF {
-				lit = "";
-				eloc.Column = 0;
-			}
-			if pos.Offset != eloc.Offset {
-				t.Errorf("bad position for %s: got %d, expected %d", lit, pos.Offset, eloc.Offset);
-			}
-			if pos.Line != eloc.Line {
-				t.Errorf("bad line for %s: got %d, expected %d", lit, pos.Line, eloc.Line);
-			}
-			if pos.Column!= eloc.Column {
-				t.Errorf("bad column for %s: got %d, expected %d", lit, pos.Column, eloc.Column);
-			}
-			if tok != e.tok {
-				t.Errorf("bad token for %s: got %s, expected %s", lit, tok.String(), e.tok.String());
-			}
-			if e.tok.IsLiteral() && lit != e.lit {
-				t.Errorf("bad literal for %s: got %s, expected %s", lit, lit, e.lit);
-			}
-			if tokenclass(tok) != e.class {
-				t.Errorf("bad class for %s: got %d, expected %d", lit, tokenclass(tok), e.class);
-			}
-			eloc.Offset += len(lit) + len(whitespace);
-			eloc.Line += NewlineCount(lit) + whitespace_linecount;
-			index++;
-			return tok != token.EOF;
-		}
-	);
-	if nerrors != 0 {
-		t.Errorf("found %d errors", nerrors);
-	}
-}
-
-
-// Verify that initializing the same scanner more then once works correctly.
-func TestInit(t *testing.T) {
-	var s scanner.Scanner;
-
-	// 1st init
-	s.Init(io.StringBytes("if true { }"), nil, 0);
-	s.Scan();  // if
-	s.Scan();  // true
-	pos, tok, lit := s.Scan();  // {
-	if tok != token.LBRACE {
-		t.Errorf("bad token: got %s, expected %s", tok.String(), token.LBRACE);
-	}
-
-	// 2nd init
-	s.Init(io.StringBytes("go true { ]"), nil, 0);
-	pos, tok, lit = 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.Scanner;
-
-	const src = "*?*$*@*";
-	s.Init(io.StringBytes(src), &TestErrorHandler{t}, scanner.AllowIllegalChars);
-	for offs, ch := range src {
-		pos, tok, lit := s.Scan();
-		if pos.Offset != offs {
-			t.Errorf("bad position for %s: got %d, expected %d", string(lit), pos.Offset, offs);
-		}
-		if tok == token.ILLEGAL && string(lit) != string(ch) {
-			t.Errorf("bad token: got %s, expected %s", string(lit), string(ch));
-		}
-	}
-
-	if s.ErrorCount != 0 {
-		t.Errorf("found %d errors", s.ErrorCount);
-	}
-}
diff --git a/src/lib/go/token/Makefile b/src/lib/go/token/Makefile
deleted file mode 100644
index 12ef2a4aa..000000000
--- a/src/lib/go/token/Makefile
+++ /dev/null
@@ -1,60 +0,0 @@
-# Copyright 2009 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-# DO NOT EDIT.  Automatically generated by gobuild.
-# gobuild -m >Makefile
-
-D=/go/
-
-include $(GOROOT)/src/Make.$(GOARCH)
-AR=gopack
-
-default: packages
-
-clean:
-	rm -rf *.[$(OS)] *.a [$(OS)].out _obj
-
-test: packages
-	gotest
-
-coverage: packages
-	gotest
-	6cov -g `pwd` | grep -v '_test\.go:'
-
-%.$O: %.go
-	$(GC) -I_obj $*.go
-
-%.$O: %.c
-	$(CC) $*.c
-
-%.$O: %.s
-	$(AS) $*.s
-
-O1=\
-	token.$O\
-
-
-phases: a1
-_obj$D/token.a: phases
-
-a1: $(O1)
-	$(AR) grc _obj$D/token.a token.$O
-	rm -f $(O1)
-
-
-newpkg: clean
-	mkdir -p _obj$D
-	$(AR) grc _obj$D/token.a
-
-$(O1): newpkg
-$(O2): a1
-
-nuke: clean
-	rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/token.a
-
-packages: _obj$D/token.a
-
-install: packages
-	test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D
-	cp _obj$D/token.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/token.a
diff --git a/src/lib/go/token/token.go b/src/lib/go/token/token.go
deleted file mode 100644
index a70a75a54..000000000
--- a/src/lib/go/token/token.go
+++ /dev/null
@@ -1,347 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This package defines constants representing the lexical
-// tokens of the Go programming language and basic operations
-// on tokens (printing, predicates).
-//
-package token
-
-import "strconv"
-
-// Token is the set of lexical tokens of the Go programming language.
-type Token int
-
-// The list of tokens.
-const (
-	// Special tokens
-	ILLEGAL Token = iota;
-	EOF;
-	COMMENT;
-
-	// Identifiers and basic type literals
-	// (these tokens stand for classes of literals)
-	literal_beg;
-	IDENT;
-	INT;
-	FLOAT;
-	CHAR;
-	STRING;
-	literal_end;
-
-	// Operators and delimiters
-	operator_beg;
-	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;
-
-	// Keywords
-	keyword_beg;
-	BREAK;
-	CASE;
-	CHAN;
-	CONST;
-	CONTINUE;
-
-	DEFAULT;
-	DEFER;
-	ELSE;
-	FALLTHROUGH;
-	FOR;
-
-	FUNC;
-	GO;
-	GOTO;
-	IF;
-	IMPORT;
-
-	INTERFACE;
-	MAP;
-	PACKAGE;
-	RANGE;
-	RETURN;
-
-	SELECT;
-	STRUCT;
-	SWITCH;
-	TYPE;
-	VAR;
-	keyword_end;
-)
-
-
-// At the moment we have no array literal syntax that lets us describe
-// the index for each element - use a map for now to make sure they are
-// in sync.
-var tokens = map [Token] string {
-	ILLEGAL : "ILLEGAL",
-
-	EOF : "EOF",
-	COMMENT : "COMMENT",
-
-	IDENT : "IDENT",
-	INT : "INT",
-	FLOAT : "FLOAT",
-	CHAR : "CHAR",
-	STRING : "STRING",
-
-	ADD : "+",
-	SUB : "-",
-	MUL : "*",
-	QUO : "/",
-	REM : "%",
-
-	AND : "&",
-	OR : "|",
-	XOR : "^",
-	SHL : "<<",
-	SHR : ">>",
-	AND_NOT : "&^",
-
-	ADD_ASSIGN : "+=",
-	SUB_ASSIGN : "-=",
-	MUL_ASSIGN : "+=",
-	QUO_ASSIGN : "/=",
-	REM_ASSIGN : "%=",
-
-	AND_ASSIGN : "&=",
-	OR_ASSIGN : "|=",
-	XOR_ASSIGN : "^=",
-	SHL_ASSIGN : "<<=",
-	SHR_ASSIGN : ">>=",
-	AND_NOT_ASSIGN : "&^=",
-
-	LAND : "&&",
-	LOR : "||",
-	ARROW : "<-",
-	INC : "++",
-	DEC : "--",
-
-	EQL : "==",
-	LSS : "<",
-	GTR : ">",
-	ASSIGN : "=",
-	NOT : "!",
-
-	NEQ : "!=",
-	LEQ : "<=",
-	GEQ : ">=",
-	DEFINE : ":=",
-	ELLIPSIS : "...",
-
-	LPAREN : "(",
-	LBRACK : "[",
-	LBRACE : "{",
-	COMMA : ",",
-	PERIOD : ".",
-
-	RPAREN : ")",
-	RBRACK : "]",
-	RBRACE : "}",
-	SEMICOLON : ";",
-	COLON : ":",
-
-	BREAK : "break",
-	CASE : "case",
-	CHAN : "chan",
-	CONST : "const",
-	CONTINUE : "continue",
-
-	DEFAULT : "default",
-	DEFER : "defer",
-	ELSE : "else",
-	FALLTHROUGH : "fallthrough",
-	FOR : "for",
-
-	FUNC : "func",
-	GO : "go",
-	GOTO : "goto",
-	IF : "if",
-	IMPORT : "import",
-
-	INTERFACE : "interface",
-	MAP : "map",
-	PACKAGE : "package",
-	RANGE : "range",
-	RETURN : "return",
-
-	SELECT : "select",
-	STRUCT : "struct",
-	SWITCH : "switch",
-	TYPE : "type",
-	VAR : "var",
-}
-
-
-// String returns the string corresponding to the token tok.
-// For operators, delimiters, and keywords the string is the actual
-// token character sequence (e.g., for the token ADD, the string is
-// "+"). For all other tokens the string corresponds to the token
-// constant name (e.g. for the token IDENT, the string is "IDENT").
-//
-func (tok Token) String() string {
-	if str, exists := tokens[tok]; exists {
-		return str;
-	}
-	return "token(" + strconv.Itoa(int(tok)) + ")";
-}
-
-
-// A set of constants for precedence-based expression parsing.
-// Non-operators have lowest precedence, followed by operators
-// starting with precedence 1 up to unary operators. The highest
-// precedence corresponds serves as "catch-all" precedence for
-// selector, indexing, and other operator and delimiter tokens.
-//
-const (
-	LowestPrec = 0;  // non-operators
-	UnaryPrec = 7;
-	HighestPrec = 8;
-)
-
-
-// Precedence returns the operator precedence of the binary
-// operator op. If op is not a binary operator, the result
-// is LowestPrecedence.
-//
-func (op Token) Precedence() int {
-	switch op {
-	case LOR:
-		return 1;
-	case LAND:
-		return 2;
-	case ARROW:
-		return 3;
-	case EQL, NEQ, LSS, LEQ, GTR, GEQ:
-		return 4;
-	case ADD, SUB, OR, XOR:
-		return 5;
-	case MUL, QUO, REM, SHL, SHR, AND, AND_NOT:
-		return 6;
-	}
-	return LowestPrec;
-}
-
-
-var keywords map [string] Token;
-
-func init() {
-	keywords = make(map [string] Token);
-	for i := keyword_beg + 1; i < keyword_end; i++ {
-		keywords[tokens[i]] = i;
-	}
-}
-
-
-// Lookup maps an identifier to its keyword token or IDENT (if not a keyword).
-//
-func Lookup(ident []byte) Token {
-	// TODO Maps with []byte key are illegal because []byte does not
-	//      support == . Should find a more efficient solution eventually.
-	if tok, is_keyword := keywords[string(ident)]; is_keyword {
-		return tok;
-	}
-	return IDENT;
-}
-
-
-// Predicates
-
-// IsLiteral returns true for tokens corresponding to identifiers
-// and basic type literals; returns false otherwise.
-//
-func (tok Token) IsLiteral() bool {
-	return literal_beg < tok && tok < literal_end;
-}
-
-// IsOperator returns true for tokens corresponding to operators and
-// delimiters; returns false otherwise.
-//
-func (tok Token) IsOperator() bool {
-	return operator_beg < tok && tok < operator_end;
-}
-
-// IsKeyword returns true for tokens corresponding to keywords;
-// returns false otherwise.
-//
-func (tok Token) IsKeyword() bool {
-	return keyword_beg < tok && tok < keyword_end;
-}
-
-
-// Token source positions are represented by a Position value.
-// A Position is valid if the line number is > 0.
-//
-type Position struct {
-	Offset int;  // byte offset, starting at 0
-	Line int;  // line number, starting at 1
-	Column int;  // column number, starting at 1 (character count)
-}
-
-
-// Pos is an accessor method for anonymous Position fields.
-// It returns its receiver.
-//
-func (pos *Position) Pos() Position {
-	return *pos;
-}
-
-
-// IsValid returns true if the position is valid.
-func (pos *Position) IsValid() bool {
-	return pos.Line > 0
-}
diff --git a/src/lib/hash/Makefile b/src/lib/hash/Makefile
deleted file mode 100644
index bdbb6f347..000000000
--- a/src/lib/hash/Makefile
+++ /dev/null
@@ -1,60 +0,0 @@
-# Copyright 2009 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-# DO NOT EDIT.  Automatically generated by gobuild.
-# gobuild -m >Makefile
-
-D=
-
-include $(GOROOT)/src/Make.$(GOARCH)
-AR=gopack
-
-default: packages
-
-clean:
-	rm -rf *.[$(OS)] *.a [$(OS)].out _obj
-
-test: packages
-	gotest
-
-coverage: packages
-	gotest
-	6cov -g `pwd` | grep -v '_test\.go:'
-
-%.$O: %.go
-	$(GC) -I_obj $*.go
-
-%.$O: %.c
-	$(CC) $*.c
-
-%.$O: %.s
-	$(AS) $*.s
-
-O1=\
-	hash.$O\
-
-
-phases: a1
-_obj$D/hash.a: phases
-
-a1: $(O1)
-	$(AR) grc _obj$D/hash.a hash.$O
-	rm -f $(O1)
-
-
-newpkg: clean
-	mkdir -p _obj$D
-	$(AR) grc _obj$D/hash.a
-
-$(O1): newpkg
-$(O2): a1
-
-nuke: clean
-	rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/hash.a
-
-packages: _obj$D/hash.a
-
-install: packages
-	test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D
-	cp _obj$D/hash.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/hash.a
diff --git a/src/lib/hash/adler32/Makefile b/src/lib/hash/adler32/Makefile
deleted file mode 100644
index 134131259..000000000
--- a/src/lib/hash/adler32/Makefile
+++ /dev/null
@@ -1,60 +0,0 @@
-# Copyright 2009 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-# DO NOT EDIT.  Automatically generated by gobuild.
-# gobuild -m >Makefile
-
-D=/hash/
-
-include $(GOROOT)/src/Make.$(GOARCH)
-AR=gopack
-
-default: packages
-
-clean:
-	rm -rf *.[$(OS)] *.a [$(OS)].out _obj
-
-test: packages
-	gotest
-
-coverage: packages
-	gotest
-	6cov -g `pwd` | grep -v '_test\.go:'
-
-%.$O: %.go
-	$(GC) -I_obj $*.go
-
-%.$O: %.c
-	$(CC) $*.c
-
-%.$O: %.s
-	$(AS) $*.s
-
-O1=\
-	adler32.$O\
-
-
-phases: a1
-_obj$D/adler32.a: phases
-
-a1: $(O1)
-	$(AR) grc _obj$D/adler32.a adler32.$O
-	rm -f $(O1)
-
-
-newpkg: clean
-	mkdir -p _obj$D
-	$(AR) grc _obj$D/adler32.a
-
-$(O1): newpkg
-$(O2): a1
-
-nuke: clean
-	rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/adler32.a
-
-packages: _obj$D/adler32.a
-
-install: packages
-	test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D
-	cp _obj$D/adler32.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/adler32.a
diff --git a/src/lib/hash/adler32/adler32.go b/src/lib/hash/adler32/adler32.go
deleted file mode 100644
index fbf9177f8..000000000
--- a/src/lib/hash/adler32/adler32.go
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This package implements the Adler-32 checksum.
-// Defined in RFC 1950:
-//	Adler-32 is composed of two sums accumulated per byte: s1 is
-//	the sum of all bytes, s2 is the sum of all s1 values. Both sums
-//	are done modulo 65521. s1 is initialized to 1, s2 to zero.  The
-//	Adler-32 checksum is stored as s2*65536 + s1 in most-
-//	significant-byte first (network) order.
-package adler32
-
-import (
-	"hash";
-	"os";
-)
-
-const (
-	mod = 65521;
-)
-
-// The size of an Adler-32 checksum in bytes.
-const Size = 4;
-
-// digest represents the partial evaluation of a checksum.
-type digest struct {
-	// invariant: (a < mod && b < mod) || a <= b
-	// invariant: a + b + 255 <= 0xffffffff
-	a, b uint32;
-}
-
-func (d *digest) Reset() {
-	d.a, d.b = 1, 0;
-}
-
-// New returns a new Hash32 computing the Adler-32 checksum.
-func New() hash.Hash32 {
-	d := new(digest);
-	d.Reset();
-	return d;
-}
-
-func (d *digest) Size() int {
-	return Size;
-}
-
-// Add p to the running checksum a, b.
-func update(a, b uint32, p []byte) (aa, bb uint32) {
-	for i := 0; i < len(p); i++ {
-		a += uint32(p[i]);
-		b += a;
-		// invariant: a <= b
-		if b > (0xffffffff - 255) / 2 {
-			a %= mod;
-			b %= mod;
-			// invariant: a < mod && b < mod
-		} else {
-			// invariant: a + b + 255 <= 2 * b + 255 <= 0xffffffff
-		}
-	}
-	return a, b;
-}
-
-// Return the 32-bit checksum corresponding to a, b.
-func finish(a, b uint32) uint32 {
-	if b >= mod {
-		a %= mod;
-		b %= mod;
-	}
-	return b<<16 | a;
-}
-
-func (d *digest) Write(p []byte) (nn int, err os.Error) {
-	d.a, d.b = update(d.a, d.b, p);
-	return len(p), nil;
-}
-
-func (d *digest) Sum32() uint32 {
-	return finish(d.a, d.b);
-}
-
-func (d *digest) Sum() []byte {
-	p := make([]byte, 4);
-	s := d.Sum32();
-	p[0] = byte(s>>24);
-	p[1] = byte(s>>16);
-	p[2] = byte(s>>8);
-	p[3] = byte(s);
-	return p;
-}
-
-// Checksum returns the Adler-32 checksum of data.
-func Checksum(data []byte) uint32 {
-	return finish(update(1, 0, data));
-}
diff --git a/src/lib/hash/adler32/adler32_test.go b/src/lib/hash/adler32/adler32_test.go
deleted file mode 100644
index ce49a110b..000000000
--- a/src/lib/hash/adler32/adler32_test.go
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2009 The Go Authors. 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 (
-	"hash/adler32";
-	"io";
-	"testing";
-)
-
-type _Adler32Test struct {
-	out uint32;
-	in string;
-}
-
-var golden = []_Adler32Test {
-	_Adler32Test{ 0x1, "" },
-	_Adler32Test{ 0x620062, "a" },
-	_Adler32Test{ 0x12600c4, "ab" },
-	_Adler32Test{ 0x24d0127, "abc" },
-	_Adler32Test{ 0x3d8018b, "abcd" },
-	_Adler32Test{ 0x5c801f0, "abcde" },
-	_Adler32Test{ 0x81e0256, "abcdef" },
-	_Adler32Test{ 0xadb02bd, "abcdefg" },
-	_Adler32Test{ 0xe000325, "abcdefgh" },
-	_Adler32Test{ 0x118e038e, "abcdefghi" },
-	_Adler32Test{ 0x158603f8, "abcdefghij" },
-	_Adler32Test{ 0x3f090f02, "Discard medicine more than two years old." },
-	_Adler32Test{ 0x46d81477, "He who has a shady past knows that nice guys finish last." },
-	_Adler32Test{ 0x40ee0ee1, "I wouldn't marry him with a ten foot pole." },
-	_Adler32Test{ 0x16661315, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave" },
-	_Adler32Test{ 0x5b2e1480, "The days of the digital watch are numbered.  -Tom Stoppard" },
-	_Adler32Test{ 0x8c3c09ea, "Nepal premier won't resign." },
-	_Adler32Test{ 0x45ac18fd, "For every action there is an equal and opposite government program." },
-	_Adler32Test{ 0x53c61462, "His money is twice tainted: 'taint yours and 'taint mine." },
-	_Adler32Test{ 0x7e511e63, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977" },
-	_Adler32Test{ 0xe4801a6a, "It's a tiny change to the code and not completely disgusting. - Bob Manchek" },
-	_Adler32Test{ 0x61b507df, "size:  a.out:  bad magic" },
-	_Adler32Test{ 0xb8631171, "The major problem is with sendmail.  -Mark Horton" },
-	_Adler32Test{ 0x8b5e1904, "Give me a rock, paper and scissors and I will move the world.  CCFestoon" },
-	_Adler32Test{ 0x7cc6102b, "If the enemy is within range, then so are you." },
-	_Adler32Test{ 0x700318e7, "It's well we cannot hear the screams/That we create in others' dreams." },
-	_Adler32Test{ 0x1e601747, "You remind me of a TV show, but that's all right: I watch it anyway." },
-	_Adler32Test{ 0xb55b0b09, "C is as portable as Stonehedge!!" },
-	_Adler32Test{ 0x39111dd0, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley" },
-	_Adler32Test{ 0x91dd304f, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction.  Lewis-Randall Rule" },
-	_Adler32Test{ 0x2e5d1316, "How can you write a big system without C++?  -Paul Glick" },
-	_Adler32Test{ 0xd0201df6, "'Invariant assertions' is the most elegant programming technique!  -Tom Szymanski" },
-}
-
-func TestGolden(t *testing.T) {
-	for i := 0; i < len(golden); i++ {
-		g := golden[i];
-		c := New();
-		io.WriteString(c, g.in);
-		s := c.Sum32();
-		if s != g.out {
-			t.Errorf("adler32(%s) = 0x%x want 0x%x", g.in, s, g.out);
-			t.FailNow();
-		}
-	}
-}
-
diff --git a/src/lib/hash/crc32/Makefile b/src/lib/hash/crc32/Makefile
deleted file mode 100644
index 08d4f5e4e..000000000
--- a/src/lib/hash/crc32/Makefile
+++ /dev/null
@@ -1,60 +0,0 @@
-# Copyright 2009 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-# DO NOT EDIT.  Automatically generated by gobuild.
-# gobuild -m >Makefile
-
-D=/hash/
-
-include $(GOROOT)/src/Make.$(GOARCH)
-AR=gopack
-
-default: packages
-
-clean:
-	rm -rf *.[$(OS)] *.a [$(OS)].out _obj
-
-test: packages
-	gotest
-
-coverage: packages
-	gotest
-	6cov -g `pwd` | grep -v '_test\.go:'
-
-%.$O: %.go
-	$(GC) -I_obj $*.go
-
-%.$O: %.c
-	$(CC) $*.c
-
-%.$O: %.s
-	$(AS) $*.s
-
-O1=\
-	crc32.$O\
-
-
-phases: a1
-_obj$D/crc32.a: phases
-
-a1: $(O1)
-	$(AR) grc _obj$D/crc32.a crc32.$O
-	rm -f $(O1)
-
-
-newpkg: clean
-	mkdir -p _obj$D
-	$(AR) grc _obj$D/crc32.a
-
-$(O1): newpkg
-$(O2): a1
-
-nuke: clean
-	rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/crc32.a
-
-packages: _obj$D/crc32.a
-
-install: packages
-	test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D
-	cp _obj$D/crc32.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/crc32.a
diff --git a/src/lib/hash/crc32/crc32.go b/src/lib/hash/crc32/crc32.go
deleted file mode 100644
index 22a0f68f6..000000000
--- a/src/lib/hash/crc32/crc32.go
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This package implements the 32-bit cyclic redundancy check, or CRC-32, checksum.
-// See http://en.wikipedia.org/wiki/Cyclic_redundancy_check for information.
-package crc32
-
-import (
-	"hash";
-	"os";
-)
-
-// The size of a CRC-32 checksum in bytes.
-const Size = 4;
-
-// Predefined polynomials.
-const (
-	// Far and away the most common CRC-32 polynomial.
-	// Used by ethernet (IEEE 802.3), v.42, fddi, gzip, zip, png, mpeg-2, ...
-	IEEE = 0xedb88320;
-
-	// Castagnoli's polynomial, used in iSCSI.
-	// Has better error detection characteristics than IEEE.
-	// http://dx.doi.org/10.1109/26.231911
-	Castagnoli = 0x82f63b78;
-
-	// Koopman's polynomial.
-	// Also has better error detection characteristics than IEEE.
-	// http://dx.doi.org/10.1109/DSN.2002.1028931
-	Koopman = 0xeb31d82e;
-)
-
-// Table is a 256-word table representing the polynomial for efficient processing.
-type Table [256]uint32
-
-// MakeTable returns the Table constructed from the specified polynomial.
-func MakeTable(poly uint32) *Table {
-	t := new(Table);
-	for i := 0; i < 256; i++ {
-		crc := uint32(i);
-		for j := 0; j < 8; j++ {
-			if crc&1 == 1 {
-				crc = (crc>>1) ^ poly;
-			} else {
-				crc >>= 1;
-			}
-		}
-		t[i] = crc;
-	}
-	return t;
-}
-
-// IEEETable is the table for the IEEE polynomial.
-var IEEETable = MakeTable(IEEE);
-
-// digest represents the partial evaluation of a checksum.
-type digest struct {
-	crc uint32;
-	tab *Table;
-}
-
-// New creates a new Hash 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 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 i := 0; i < len(p); i++ {
-		crc = tab[byte(crc) ^ p[i]] ^ (crc >> 8);
-	}
-	return ^crc;
-}
-
-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/lib/hash/crc32/crc32_test.go b/src/lib/hash/crc32/crc32_test.go
deleted file mode 100644
index c037da600..000000000
--- a/src/lib/hash/crc32/crc32_test.go
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2009 The Go Authors. 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 (
-	"hash/crc32";
-	"io";
-	"testing";
-)
-
-type _Crc32Test struct {
-	out uint32;
-	in string;
-}
-
-var golden = []_Crc32Test {
-	_Crc32Test{ 0x0, "" },
-	_Crc32Test{ 0xe8b7be43, "a" },
-	_Crc32Test{ 0x9e83486d, "ab" },
-	_Crc32Test{ 0x352441c2, "abc" },
-	_Crc32Test{ 0xed82cd11, "abcd" },
-	_Crc32Test{ 0x8587d865, "abcde" },
-	_Crc32Test{ 0x4b8e39ef, "abcdef" },
-	_Crc32Test{ 0x312a6aa6, "abcdefg" },
-	_Crc32Test{ 0xaeef2a50, "abcdefgh" },
-	_Crc32Test{ 0x8da988af, "abcdefghi" },
-	_Crc32Test{ 0x3981703a, "abcdefghij" },
-	_Crc32Test{ 0x6b9cdfe7, "Discard medicine more than two years old." },
-	_Crc32Test{ 0xc90ef73f, "He who has a shady past knows that nice guys finish last." },
-	_Crc32Test{ 0xb902341f, "I wouldn't marry him with a ten foot pole." },
-	_Crc32Test{ 0x42080e8, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave" },
-	_Crc32Test{ 0x154c6d11, "The days of the digital watch are numbered.  -Tom Stoppard" },
-	_Crc32Test{ 0x4c418325, "Nepal premier won't resign." },
-	_Crc32Test{ 0x33955150, "For every action there is an equal and opposite government program." },
-	_Crc32Test{ 0x26216a4b, "His money is twice tainted: 'taint yours and 'taint mine." },
-	_Crc32Test{ 0x1abbe45e, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977" },
-	_Crc32Test{ 0xc89a94f7, "It's a tiny change to the code and not completely disgusting. - Bob Manchek" },
-	_Crc32Test{ 0xab3abe14, "size:  a.out:  bad magic" },
-	_Crc32Test{ 0xbab102b6, "The major problem is with sendmail.  -Mark Horton" },
-	_Crc32Test{ 0x999149d7, "Give me a rock, paper and scissors and I will move the world.  CCFestoon" },
-	_Crc32Test{ 0x6d52a33c, "If the enemy is within range, then so are you." },
-	_Crc32Test{ 0x90631e8d, "It's well we cannot hear the screams/That we create in others' dreams." },
-	_Crc32Test{ 0x78309130, "You remind me of a TV show, but that's all right: I watch it anyway." },
-	_Crc32Test{ 0x7d0a377f, "C is as portable as Stonehedge!!" },
-	_Crc32Test{ 0x8c79fd79, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley" },
-	_Crc32Test{ 0xa20b7167, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction.  Lewis-Randall Rule" },
-	_Crc32Test{ 0x8e0bb443, "How can you write a big system without C++?  -Paul Glick" },
-}
-
-func TestGolden(t *testing.T) {
-	for i := 0; i < len(golden); i++ {
-		g := golden[i];
-		c := NewIEEE();
-		io.WriteString(c, g.in);
-		s := c.Sum32();
-		if s != g.out {
-			t.Errorf("crc32(%s) = 0x%x want 0x%x", g.in, s, g.out);
-			t.FailNow();
-		}
-	}
-}
-
diff --git a/src/lib/hash/hash.go b/src/lib/hash/hash.go
deleted file mode 100644
index a7c08cfed..000000000
--- a/src/lib/hash/hash.go
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package hash
-
-import "io";
-
-// Hash is the common interface implemented by all hash functions.
-// The Write method never returns an error.
-// Sum returns the bytes of integer hash codes in big-endian order.
-type Hash interface {
-	io.Writer;
-	Sum() []byte;
-	Reset();
-	Size() int;	// number of bytes Sum returns
-}
-
-// Hash32 is the common interface implemented by all 32-bit hash functions.
-type Hash32 interface {
-	Hash;
-	Sum32() uint32;
-}
-
diff --git a/src/lib/hash/test_cases.txt b/src/lib/hash/test_cases.txt
deleted file mode 100644
index 26d3ccc05..000000000
--- a/src/lib/hash/test_cases.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-
-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/lib/hash/test_gen.awk b/src/lib/hash/test_gen.awk
deleted file mode 100644
index 804f78679..000000000
--- a/src/lib/hash/test_gen.awk
+++ /dev/null
@@ -1,14 +0,0 @@
-# Copyright 2009 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-# 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/lib/http/Makefile b/src/lib/http/Makefile
deleted file mode 100644
index 0a029497c..000000000
--- a/src/lib/http/Makefile
+++ /dev/null
@@ -1,85 +0,0 @@
-# Copyright 2009 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-# DO NOT EDIT.  Automatically generated by gobuild.
-# gobuild -m >Makefile
-
-D=
-
-include $(GOROOT)/src/Make.$(GOARCH)
-AR=gopack
-
-default: packages
-
-clean:
-	rm -rf *.[$(OS)] *.a [$(OS)].out _obj
-
-test: packages
-	gotest
-
-coverage: packages
-	gotest
-	6cov -g `pwd` | grep -v '_test\.go:'
-
-%.$O: %.go
-	$(GC) -I_obj $*.go
-
-%.$O: %.c
-	$(CC) $*.c
-
-%.$O: %.s
-	$(AS) $*.s
-
-O1=\
-	status.$O\
-	url.$O\
-
-O2=\
-	request.$O\
-
-O3=\
-	server.$O\
-
-O4=\
-	fs.$O\
-
-
-phases: a1 a2 a3 a4
-_obj$D/http.a: phases
-
-a1: $(O1)
-	$(AR) grc _obj$D/http.a status.$O url.$O
-	rm -f $(O1)
-
-a2: $(O2)
-	$(AR) grc _obj$D/http.a request.$O
-	rm -f $(O2)
-
-a3: $(O3)
-	$(AR) grc _obj$D/http.a server.$O
-	rm -f $(O3)
-
-a4: $(O4)
-	$(AR) grc _obj$D/http.a fs.$O
-	rm -f $(O4)
-
-
-newpkg: clean
-	mkdir -p _obj$D
-	$(AR) grc _obj$D/http.a
-
-$(O1): newpkg
-$(O2): a1
-$(O3): a2
-$(O4): a3
-$(O5): a4
-
-nuke: clean
-	rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/http.a
-
-packages: _obj$D/http.a
-
-install: packages
-	test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D
-	cp _obj$D/http.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/http.a
diff --git a/src/lib/http/fs.go b/src/lib/http/fs.go
deleted file mode 100644
index 108734c47..000000000
--- a/src/lib/http/fs.go
+++ /dev/null
@@ -1,184 +0,0 @@
-// Copyright 2009 The Go 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";
-	"http";
-	"io";
-	"os";
-	"path";
-	"strings";
-	"utf8";
-)
-
-// TODO this should be in a mime package somewhere
-var contentByExt = map[string] string {
-	".css":	"text/css",
-	".gif":	"image/gif",
-	".html":	"text/html; charset=utf-8",
-	".jpg":	"image/jpeg",
-	".js":	"application/x-javascript",
-	".png":	"image/png",
-}
-
-// 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 0x80 <= rune && rune <= 0x9F {
-			return false;
-		}
-		if rune < ' ' {
-			switch rune {
-			case '\n', '\r', '\t':
-				// okay
-			default:
-				// binary garbage
-				return false;
-			}
-		}
-		b = b[size:len(b)];
-	}
-	return true;
-}
-
-func dirList(c *Conn, f *os.File) {
-	fmt.Fprintf(c, "
\n");
-	for {
-		dirs, err := f.Readdir(100);
-		if err != nil || len(dirs) == 0 {
-			break
-		}
-		for i, d := range dirs {
-			name := d.Name;
-			if d.IsDirectory() {
-				name += "/"
-			}
-			// TODO htmlescape
-			fmt.Fprintf(c, "%s\n", name, name);
-		}
-	}
-	fmt.Fprintf(c, "
\n"); -} - - -func serveFileInternal(c *Conn, r *Request, name string, redirect bool) { - const indexPage = "/index.html"; - - // redirect to strip off any index.html - n := len(name) - len(indexPage); - if n >= 0 && name[n:len(name)] == indexPage { - http.Redirect(c, name[0:n+1], StatusMovedPermanently); - return; - } - - f, err := os.Open(name, os.O_RDONLY, 0); - if err != nil { - // TODO expose actual error? - NotFound(c, r); - return; - } - defer f.Close(); - - d, err1 := f.Stat(); - if err1 != nil { - // TODO expose actual error? - NotFound(c, 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] != '/' { - http.Redirect(c, url + "/", StatusMovedPermanently); - return; - } - } else { - if url[len(url)-1] == '/' { - http.Redirect(c, url[0:len(url)-1], StatusMovedPermanently); - return; - } - } - } - - // use contents of index.html for directory, if present - if d.IsDirectory() { - index := name + indexPage; - ff, err := os.Open(index, os.O_RDONLY, 0); - if err == nil { - defer ff.Close(); - dd, err := ff.Stat(); - if err == nil { - name = index; - d = dd; - f = ff; - } - } - } - - if d.IsDirectory() { - dirList(c, f); - return; - } - - // serve file - // use extension to find content type. - ext := path.Ext(name); - if ctype, ok := contentByExt[ext]; ok { - c.SetHeader("Content-Type", ctype); - } else { - // read first chunk to decide between utf-8 text and binary - var buf [1024]byte; - n, err := io.FullRead(f, &buf); - b := buf[0:n]; - if isText(b) { - c.SetHeader("Content-Type", "text-plain; charset=utf-8"); - } else { - c.SetHeader("Content-Type", "application/octet-stream"); // generic binary - } - c.Write(b); - } - io.Copy(f, c); -} - -// ServeFile replies to the request with the contents of the named file or directory. -func ServeFile(c *Conn, r *Request, name string) { - serveFileInternal(c, r, name, false); -} - -type fileHandler struct { - root string; - prefix string; -} - -// FileServer returns a handler that serves HTTP requests -// with the contents of the file system rooted at root. -// It strips prefix from the incoming requests before -// looking up the file name in the file system. -func FileServer(root, prefix string) Handler { - return &fileHandler{root, prefix}; -} - -func (f *fileHandler) ServeHTTP(c *Conn, r *Request) { - path := r.Url.Path; - if !strings.HasPrefix(path, f.prefix) { - NotFound(c, r); - return; - } - path = path[len(f.prefix):len(path)]; - serveFileInternal(c, r, f.root + "/" + path, true); -} - diff --git a/src/lib/http/request.go b/src/lib/http/request.go deleted file mode 100644 index 76dd6f30c..000000000 --- a/src/lib/http/request.go +++ /dev/null @@ -1,413 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// HTTP Request reading and parsing. - -// The http package implements parsing of HTTP requests and URLs -// and provides an extensible HTTP server. -// -// In the future it should also implement parsing of HTTP replies -// and provide methods to fetch URLs via HTTP. -package http - -import ( - "bufio"; - "fmt"; - "http"; - "io"; - "os"; - "strconv"; - "strings"; -) - -const ( - maxLineLength = 1024; // assumed < bufio.DefaultBufSize - maxValueLength = 1024; - maxHeaderLines = 1024; -) - -// HTTP request parsing errors. -type ProtocolError struct { - os.ErrorString -} -var ( - LineTooLong = &ProtocolError{"http header line too long"}; - ValueTooLong = &ProtocolError{"http header value too long"}; - HeaderTooLong = &ProtocolError{"http header too long"}; - BadContentLength = &ProtocolError{"invalid content length"}; - ShortEntityBody = &ProtocolError{"entity body too short"}; - BadHeader = &ProtocolError{"malformed http header"}; - BadRequest = &ProtocolError{"invalid http request"}; - BadHTTPVersion = &ProtocolError{"unsupported http version"}; -) - -// A Request represents a parsed HTTP request header. -type Request struct { - Method string; // GET, POST, PUT, etc. - RawUrl string; // The raw URL given in the request. - Url *URL; // Parsed URL. - Proto string; // "HTTP/1.0" - ProtoMajor int; // 1 - ProtoMinor int; // 0 - - // A header mapping request lines to their values. - // If the header says - // - // Accept-Language: en-us - // accept-encoding: gzip, deflate - // Connection: keep-alive - // - // then - // - // Header = map[string]string{ - // "Accept-Encoding": "en-us", - // "Accept-Language": "gzip, deflate", - // "Connection": "keep-alive" - // } - // - // HTTP defines that header names are case-insensitive. - // The request parser implements this by canonicalizing the - // name, making the first character and any characters - // following a hyphen uppercase and the rest lowercase. - Header map[string] string; - - // The message body. - Body io.Reader; - - // Whether to close the connection after replying to this request. - Close bool; - - // The host on which the URL is sought. - // Per RFC 2616, this is either the value of the Host: header - // or the host name given in the URL itself. - Host string; - - // The referring URL, if sent in the request. - // - // Referer is misspelled as in the request itself, - // a mistake from the earliest days of HTTP. - // This value can also be fetched from the Header map - // as Header["Referer"]; the benefit of making it - // available as a structure field is that the compiler - // can diagnose programs that use the alternate - // (correct English) spelling req.Referrer but cannot - // diagnose programs that use Header["Referrer"]. - Referer string; - - // The User-Agent: header string, if sent in the request. - UserAgent string; -} - -// 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 -} - -// 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.ReadLineSlice('\n'); err != nil { - return nil, err - } - if len(p) >= maxLineLength { - return nil, LineTooLong - } - - // 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 -} - -// Read a key/value pair from b. -// A key/value has the form Key: Value\r\n -// and the Value can continue on multiple lines if each continuation line -// starts with a space. -func readKeyValue(b *bufio.Reader) (key, value string, err os.Error) { - line, e := readLineBytes(b); - if e != nil { - return "", "", e - } - if len(line) == 0 { - return "", "", nil - } - - // Scan first line for colon. - for i := 0; i < len(line); i++ { - switch line[i] { - case ' ': - // Key field has space - no good. - return "", "", BadHeader; - case ':': - key = string(line[0:i]); - // Skip initial space before value. - for i++; i < len(line); i++ { - if line[i] != ' ' { - break - } - } - value = string(line[i:len(line)]); - - // Look for extension lines, which must begin with space. - for { - var c byte; - - if c, e = b.ReadByte(); e != nil { - return "", "", e - } - if c != ' ' { - // Not leading space; stop. - b.UnreadByte(); - break - } - - // Eat leading space. - for c == ' ' { - if c, e = b.ReadByte(); e != nil { - return "", "", e - } - } - b.UnreadByte(); - - // Read the rest of the line and add to value. - if line, e = readLineBytes(b); e != nil { - return "", "", e - } - value += " " + string(line); - - if len(value) >= maxValueLength { - return "", "", ValueTooLong - } - } - return key, value, nil - } - } - - // Line ended before space or colon. - return "", "", BadHeader; -} - -// Convert decimal at s[i:len(s)] to integer, -// returning value, string position where the digits stopped, -// and whether there was a valid number (digits, not too big). -func atoi(s string, i int) (n, i1 int, ok bool) { - const Big = 1000000; - if i >= len(s) || s[i] < '0' || s[i] > '9' { - return 0, 0, false - } - n = 0; - for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ { - n = n*10 + int(s[i]-'0'); - if n > Big { - return 0, 0, false - } - } - return n, i, true -} - -// Parse HTTP version: "HTTP/1.2" -> (1, 2, true). -func parseHTTPVersion(vers string) (int, int, bool) { - if vers[0:5] != "HTTP/" { - return 0, 0, false - } - major, i, ok := atoi(vers, 5); - if !ok || i >= len(vers) || vers[i] != '.' { - return 0, 0, false - } - var minor int; - minor, i, ok = atoi(vers, i+1); - if !ok || i != len(vers) { - return 0, 0, false - } - return major, minor, true -} - -var cmap = make(map[string]string) - -// CanonicalHeaderKey returns the canonical format of the -// HTTP header key s. The canonicalization converts the first -// letter and any letter following a hyphen to upper case; -// the rest are converted to lowercase. For example, the -// canonical key for "accept-encoding" is "Accept-Encoding". -func CanonicalHeaderKey(s string) string { - if t, ok := cmap[s]; ok { - return t; - } - - // canonicalize: first letter upper case - // and upper case after each dash. - // (Host, User-Agent, If-Modified-Since). - // HTTP headers are ASCII only, so no Unicode issues. - a := io.StringBytes(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 = false; - if v == '-' { - upper = true; - } - } - t := string(a); - cmap[s] = t; - return t; -} - -// ReadRequest reads and parses a request from b. -func ReadRequest(b *bufio.Reader) (req *Request, err os.Error) { - req = new(Request); - - // First line: GET /index.html HTTP/1.0 - var s string; - if s, err = readLine(b); err != nil { - return nil, err - } - - var f []string; - if f = strings.Split(s, " "); len(f) != 3 { - return nil, BadRequest - } - 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, BadHTTPVersion - } - - if req.Url, err = ParseURL(req.RawUrl); err != nil { - return nil, err - } - - // Subsequent lines: Key: value. - nheader := 0; - req.Header = make(map[string] string); - for { - var key, value string; - if key, value, err = readKeyValue(b); err != nil { - return nil, err - } - if key == "" { - break - } - if nheader++; nheader >= maxHeaderLines { - return nil, HeaderTooLong - } - - key = CanonicalHeaderKey(key); - - // RFC 2616 says that if you send the same header key - // multiple times, it has to be semantically equivalent - // to concatenating the values separated by commas. - oldvalue, present := req.Header[key]; - if present { - req.Header[key] = oldvalue+","+value - } else { - req.Header[key] = value - } - } - - // RFC2616: Must treat - // GET /index.html HTTP/1.1 - // Host: www.google.com - // and - // GET http://www.google.com/index.html HTTP/1.1 - // Host: doesntmatter - // the same. In the second case, any Host line is ignored. - if v, present := req.Header["Host"]; present && req.Url.Host == "" { - req.Host = v - } - - // RFC2616: Should treat - // Pragma: no-cache - // like - // Cache-Control: no-cache - if v, present := req.Header["Pragma"]; present && v == "no-cache" { - if cc, presentcc := req.Header["Cache-Control"]; !presentcc { - req.Header["Cache-Control"] = "no-cache" - } - } - - // Determine whether to hang up after sending the reply. - if req.ProtoMajor < 1 || (req.ProtoMajor == 1 && req.ProtoMinor < 1) { - req.Close = true - } else if v, present := req.Header["Connection"]; present { - // TODO: Should split on commas, toss surrounding white space, - // and check each field. - if v == "close" { - req.Close = true - } - } - - // Pull out useful fields as a convenience to clients. - if v, present := req.Header["Referer"]; present { - req.Referer = v - } - if v, present := req.Header["User-Agent"]; present { - req.UserAgent = v - } - - // 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 - - // A message body exists when either Content-Length or Transfer-Encoding - // headers are present. TODO: Handle Transfer-Encoding. - if v, present := req.Header["Content-Length"]; present { - length, err := strconv.Btoui64(v, 10); - if err != nil { - return nil, BadContentLength - } - // TODO: limit the Content-Length. This is an easy DoS vector. - raw := make([]byte, length); - n, err := b.Read(raw); - if err != nil || uint64(n) < length { - return nil, ShortEntityBody - } - req.Body = io.NewByteReader(raw); - } - - return req, nil -} diff --git a/src/lib/http/server.go b/src/lib/http/server.go deleted file mode 100644 index c1de5de78..000000000 --- a/src/lib/http/server.go +++ /dev/null @@ -1,575 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// HTTP server. See RFC 2616. - -// TODO(rsc): -// logging -// cgi support -// post support - -package http - -import ( - "bufio"; - "fmt"; - "http"; - "io"; - "log"; - "net"; - "os"; - "path"; - "strconv"; - "strings"; -) - -// Errors introduced by the HTTP server. -var ( - ErrWriteAfterFlush = os.NewError("Conn.Write called after Flush"); - ErrHijacked = os.NewError("Conn has been hijacked"); -) - -type Conn struct - -// Objects implemeting the Handler interface can be -// registered to serve a particular path or subtree -// in the HTTP server. -type Handler interface { - ServeHTTP(*Conn, *Request); -} - -// A Conn represents the server side of a single active HTTP connection. -type Conn struct { - RemoteAddr string; // network address of remote side - Req *Request; // current HTTP request - - rwc io.ReadWriteCloser; // i/o connection - buf *bufio.ReadWriter; // buffered rwc - handler Handler; // request handler - hijacked bool; // connection has been hijacked by handler - - // state for the current reply - closeAfterReply bool; // close connection after this reply - chunking bool; // using chunked transfer encoding for reply body - wroteHeader bool; // reply header has been written - header map[string] string; // reply header parameters - written int64; // number of bytes written in body - status int; // status code passed to WriteHeader -} - -// Create new connection from rwc. -func newConn(rwc io.ReadWriteCloser, raddr string, handler Handler) (c *Conn, err os.Error) { - c = new(Conn); - c.RemoteAddr = raddr; - c.handler = handler; - c.rwc = rwc; - br := bufio.NewReader(rwc); - bw := bufio.NewWriter(rwc); - c.buf = bufio.NewReadWriter(br, bw); - return c, nil -} - -func (c *Conn) SetHeader(hdr, val string) - -// Read next request from connection. -func (c *Conn) readRequest() (req *Request, err os.Error) { - if c.hijacked { - return nil, ErrHijacked - } - if req, err = ReadRequest(c.buf.Reader); err != nil { - return nil, err - } - - // Reset per-request connection state. - c.header = make(map[string] string); - c.wroteHeader = false; - c.Req = req; - - // Default output is HTML encoded in UTF-8. - c.SetHeader("Content-Type", "text/html; charset=utf-8"); - - if req.ProtoAtLeast(1, 1) { - // HTTP/1.1 or greater: use chunked transfer encoding - // to avoid closing the connection at EOF. - c.chunking = true; - c.SetHeader("Transfer-Encoding", "chunked"); - } else { - // HTTP version < 1.1: cannot do chunked transfer - // encoding, so signal EOF by closing connection. - // Could avoid closing the connection if there is - // a Content-Length: header in the response, - // but everyone who expects persistent connections - // does HTTP/1.1 now. - c.closeAfterReply = true; - c.chunking = false; - } - - return req, nil -} - -// SetHeader sets a header line in the eventual reply. -// For example, SetHeader("Content-Type", "text/html; charset=utf-8") -// will result in the header line -// -// Content-Type: text/html; charset=utf-8 -// -// being sent. UTF-8 encoded HTML is the default setting for -// Content-Type in this library, so users need not make that -// particular call. Calls to SetHeader after WriteHeader (or Write) -// are ignored. -func (c *Conn) SetHeader(hdr, val string) { - c.header[CanonicalHeaderKey(hdr)] = val; -} - -// WriteHeader sends an HTTP response header with status code. -// If WriteHeader is not called explicitly, the first call to Write -// will trigger an implicit WriteHeader(http.StatusOK). -// Thus explicit calls to WriteHeader are mainly used to -// send error codes. -func (c *Conn) WriteHeader(code int) { - if c.hijacked { - log.Stderr("http: Conn.WriteHeader on hijacked connection"); - return - } - if c.wroteHeader { - log.Stderr("http: multiple Conn.WriteHeader calls"); - return - } - c.wroteHeader = true; - c.status = code; - c.written = 0; - if !c.Req.ProtoAtLeast(1, 0) { - return - } - proto := "HTTP/1.0"; - if c.Req.ProtoAtLeast(1, 1) { - proto = "HTTP/1.1"; - } - codestring := strconv.Itoa(code); - text, ok := statusText[code]; - if !ok { - text = "status code " + codestring; - } - io.WriteString(c.buf, proto + " " + codestring + " " + text + "\r\n"); - for k,v := range c.header { - io.WriteString(c.buf, k + ": " + v + "\r\n"); - } - io.WriteString(c.buf, "\r\n"); -} - -// Write writes the data to the connection as part of an HTTP reply. -// If WriteHeader has not yet been called, Write calls WriteHeader(http.StatusOK) -// before writing the data. -func (c *Conn) Write(data []byte) (n int, err os.Error) { - if c.hijacked { - log.Stderr("http: Conn.Write on hijacked connection"); - return 0, ErrHijacked - } - if !c.wroteHeader { - c.WriteHeader(StatusOK); - } - if len(data) == 0 { - return 0, nil - } - - c.written += int64(len(data)); // ignoring errors, for errorKludge - - // TODO(rsc): if chunking happened after the buffering, - // then there would be fewer chunk headers. - // On the other hand, it would make hijacking more difficult. - if c.chunking { - fmt.Fprintf(c.buf, "%x\r\n", len(data)); // TODO(rsc): use strconv not fmt - } - n, err = c.buf.Write(data); - if err == nil && c.chunking { - if n != len(data) { - err = io.ErrShortWrite; - } - if err == nil { - io.WriteString(c.buf, "\r\n"); - } - } - - return n, err; -} - -// If this is an error reply (4xx or 5xx) -// and the handler wrote some data explaining the error, -// some browsers (i.e., Chrome, Internet Explorer) -// will show their own error instead unless the error is -// long enough. The minimum lengths used in those -// browsers are in the 256-512 range. -// Pad to 1024 bytes. -func errorKludge(c *Conn, req *Request) { - const min = 1024; - - // Is this an error? - if kind := c.status/100; kind != 4 && kind != 5 { - return; - } - - // Did the handler supply any info? Enough? - if c.written == 0 || c.written >= min { - return; - } - - // Is it text? ("Content-Type" is always in the map) - if s := c.header["Content-Type"]; len(s) < 5 || s[0:5] != "text/" { - return; - } - - // Is it a broken browser? - var msg string; - switch agent := req.UserAgent; { - case strings.Index(agent, "MSIE") >= 0: - msg = "Internet Explorer"; - case strings.Index(agent, "Chrome/") >= 0: - msg = "Chrome"; - default: - return; - } - msg += " would ignore this error page if this text weren't here.\n"; - io.WriteString(c, "\n"); - for c.written < min { - io.WriteString(c, msg); - } -} - -func (c *Conn) flush() { - if !c.wroteHeader { - c.WriteHeader(StatusOK); - } - errorKludge(c, c.Req); - if c.chunking { - io.WriteString(c.buf, "0\r\n"); - // trailer key/value pairs, followed by blank line - io.WriteString(c.buf, "\r\n"); - } - c.buf.Flush(); -} - -// Close the connection. -func (c *Conn) close() { - if c.buf != nil { - c.buf.Flush(); - c.buf = nil; - } - if c.rwc != nil { - c.rwc.Close(); - c.rwc = nil; - } -} - -// Serve a new connection. -func (c *Conn) serve() { - for { - req, err := c.readRequest(); - if err != nil { - break - } - // HTTP cannot have multiple simultaneous active requests. - // Until the server replies to this request, it can't read another, - // so we might as well run the handler in this goroutine. - c.handler.ServeHTTP(c, req); - if c.hijacked { - return; - } - c.flush(); - if c.closeAfterReply { - break; - } - } - c.close(); -} - -// Hijack lets the caller take over the connection. -// After a call to c.Hijack(), the HTTP server library -// will not do anything else with the connection. -// It becomes the caller's responsibility to manage -// and close the connection. -func (c *Conn) Hijack() (rwc io.ReadWriteCloser, buf *bufio.ReadWriter, err os.Error) { - if c.hijacked { - return nil, nil, ErrHijacked; - } - c.hijacked = true; - rwc = c.rwc; - buf = c.buf; - c.rwc = nil; - c.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(*Conn, *Request) - -// ServeHTTP calls f(c, req). -func (f HandlerFunc) ServeHTTP(c *Conn, req *Request) { - f(c, req); -} - -// Helper handlers - -// NotFound replies to the request with an HTTP 404 not found error. -func NotFound(c *Conn, req *Request) { - c.SetHeader("Content-Type", "text/plain; charset=utf-8"); - c.WriteHeader(StatusNotFound); - io.WriteString(c, "404 page not found\n"); -} - -// NotFoundHandler returns a simple request handler -// that replies to each request with a ``404 page not found'' reply. -func NotFoundHandler() Handler { - return HandlerFunc(NotFound) -} - -// Redirect replies to the request with a redirect to url, -// which may be a path relative to the request path. -func Redirect(c *Conn, url string, code int) { - // RFC2616 recommends that a short note "SHOULD" be included in the - // response because older user agents may not understand 301/307. - note := "" + statusText[code] + ".\n"; - if c.Req.Method == "POST" { - note = ""; - } - - u, err := ParseURL(url); - if err != nil { - goto finish - } - - // If url was relative, make absolute by - // combining with request path. - // The browser would probably do this for us, - // but doing it ourselves is more reliable. - - // NOTE(rsc): RFC 2616 says that the Location - // line must be an absolute URI, like - // "http://www.google.com/redirect/", - // not a path like "/redirect/". - // Unfortunately, we don't know what to - // put in the host name section to get the - // client to connect to us again, so we can't - // know the right absolute URI to send back. - // Because of this problem, no one pays attention - // to the RFC; they all send back just a new path. - // So do we. - oldpath := c.Req.Url.Path; - if oldpath == "" { // should not happen, but avoid a crash if it does - oldpath = "/" - } - if u.Scheme == "" { - // no leading http://server - if url == "" || url[0] != '/' { - // make relative path absolute - olddir, oldfile := path.Split(oldpath); - url = olddir + url; - } - - // clean up but preserve trailing slash - trailing := url[len(url) - 1] == '/'; - url = path.Clean(url); - if trailing && url[len(url) - 1] != '/' { - url += "/"; - } - } - -finish: - c.SetHeader("Location", url); - c.WriteHeader(code); - fmt.Fprintf(c, note, url); -} - -// Redirect to a fixed URL -type redirectHandler struct { - url string; - code int; -} -func (rh *redirectHandler) ServeHTTP(c *Conn, req *Request) { - Redirect(c, rh.url, rh.code); -} - -// RedirectHandler returns a request handler that redirects -// each request it receives to the given url using the given -// status code. -func RedirectHandler(url string, code int) Handler { - return &redirectHandler{ url, code } -} - -// ServeMux is an HTTP request multiplexer. -// It matches the URL of each incoming request against a list of registered -// patterns and calls the handler for the pattern that -// most closely matches the URL. -// -// Patterns named fixed paths, like "/favicon.ico", -// or subtrees, like "/images/" (note the trailing slash). -// Patterns must begin with /. -// Longer patterns take precedence over shorter ones, so that -// if there are handlers registered for both "/images/" -// and "/images/thumbnails/", the latter handler will be -// called for paths beginning "/images/thumbnails/" and the -// former will receiver requests for any other paths in the -// "/images/" subtree. -// -// In the future, the pattern syntax may be relaxed to allow -// an optional host-name at the beginning of the pattern, -// so that a handler might register for the two patterns -// "/codesearch" and "codesearch.google.com/" -// without taking over requests for http://www.google.com/. -// -// ServeMux also takes care of sanitizing the URL request path, -// redirecting any request containing . or .. elements to an -// equivalent .- and ..-free URL. -type ServeMux struct { - m map[string] Handler -} - -// NewServeMux allocates and returns a new ServeMux. -func NewServeMux() *ServeMux { - return &ServeMux{make(map[string] Handler)}; -} - -// DefaultServeMux is the default ServeMux used by Serve. -var DefaultServeMux = NewServeMux(); - -// Does path match pattern? -func pathMatch(pattern, path string) bool { - if len(pattern) == 0 { - // should not happen - return false - } - n := len(pattern); - if pattern[n-1] != '/' { - return pattern == path - } - return len(path) >= n && path[0:n] == pattern; -} - -// Return the canonical path for p, eliminating . and .. elements. -func cleanPath(p string) string { - if p == "" { - return "/"; - } - if p[0] != '/' { - p = "/" + p; - } - np := path.Clean(p); - // path.Clean removes trailing slash except for root; - // put the trailing slash back if necessary. - if p[len(p)-1] == '/' && np != "/" { - np += "/"; - } - return np; -} - -// ServeHTTP dispatches the request to the handler whose -// pattern most closely matches the request URL. -func (mux *ServeMux) ServeHTTP(c *Conn, req *Request) { - // Clean path to canonical form and redirect. - if p := cleanPath(req.Url.Path); p != req.Url.Path { - c.SetHeader("Location", p); - c.WriteHeader(StatusMovedPermanently); - return; - } - - // Most-specific (longest) pattern wins. - var h Handler; - var n = 0; - for k, v := range mux.m { - if !pathMatch(k, req.Url.Path) { - continue; - } - if h == nil || len(k) > n { - n = len(k); - h = v; - } - } - if h == nil { - h = NotFoundHandler(); - } - h.ServeHTTP(c, req); -} - -// Handle registers the handler for the given pattern. -func (mux *ServeMux) Handle(pattern string, handler Handler) { - if pattern == "" || pattern[0] != '/' { - panicln("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); - } -} - -// Handle registers the handler for the given pattern -// in the DefaultServeMux. -func Handle(pattern string, handler Handler) { - DefaultServeMux.Handle(pattern, handler); -} - -// Serve accepts incoming HTTP connections on the listener l, -// creating a new service thread for each. The service threads -// read requests and then call handler to reply to them. -// Handler is typically nil, in which case the DefaultServeMux is used. -func Serve(l net.Listener, handler Handler) os.Error { - if handler == nil { - handler = DefaultServeMux; - } - for { - rw, raddr, e := l.Accept(); - if e != nil { - return e - } - c, err := newConn(rw, raddr, handler); - if err != nil { - continue; - } - go c.serve(); - } - panic("not reached") -} - -// ListenAndServe listens on the TCP network address addr -// and then calls Serve with handler to handle requests -// on incoming connections. Handler is typically nil, -// in which case the DefaultServeMux is used. -// -// A trivial example server is: -// -// package main -// -// import ( -// "http"; -// "io"; -// ) -// -// // hello world, the web server -// func HelloServer(c *http.Conn, req *http.Request) { -// io.WriteString(c, "hello, world!\n"); -// } -// -// func main() { -// http.Handle("/hello", http.HandlerFunc(HelloServer)); -// err := http.ListenAndServe(":12345", nil); -// if err != nil { -// panic("ListenAndServe: ", err.String()) -// } -// } -func ListenAndServe(addr string, handler Handler) os.Error { - l, e := net.Listen("tcp", addr); - if e != nil { - return e - } - e = Serve(l, handler); - l.Close(); - return e -} - diff --git a/src/lib/http/status.go b/src/lib/http/status.go deleted file mode 100644 index 6d1c5ab28..000000000 --- a/src/lib/http/status.go +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2009 The Go Authors. 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", -} - diff --git a/src/lib/http/triv.go b/src/lib/http/triv.go deleted file mode 100644 index fc9501769..000000000 --- a/src/lib/http/triv.go +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import ( - "bufio"; - "exvar"; - "flag"; - "fmt"; - "http"; - "io"; - "log"; - "net"; - "os"; - "strconv"; -) - - -// hello world, the web server -var helloRequests = exvar.NewInt("hello-requests"); -func HelloServer(c *http.Conn, req *http.Request) { - helloRequests.Add(1); - io.WriteString(c, "hello, world!\n"); -} - -// Simple counter server. POSTing to it will set the value. -type Counter struct { - n int; -} - -// This makes Counter satisfy the exvar.Var interface, so we can export -// it directly. -func (ctr *Counter) String() string { - return fmt.Sprintf("%d", ctr.n) -} - -func (ctr *Counter) ServeHTTP(c *http.Conn, req *http.Request) { - switch req.Method { - case "GET": - ctr.n++; - case "POST": - buf := new(io.ByteBuffer); - io.Copy(req.Body, buf); - body := string(buf.Data()); - if n, err := strconv.Atoi(body); err != nil { - fmt.Fprintf(c, "bad POST: %v\nbody: [%v]\n", err, body); - } else { - ctr.n = n; - fmt.Fprint(c, "counter reset\n"); - } - } - fmt.Fprintf(c, "counter = %d\n", ctr.n); -} - -// simple file server -var webroot = flag.String("root", "/home/rsc", "web root directory") -var pathVar = exvar.NewMap("file-requests"); -func FileServer(c *http.Conn, req *http.Request) { - c.SetHeader("content-type", "text/plain; charset=utf-8"); - pathVar.Add(req.Url.Path, 1); - path := *webroot + req.Url.Path; // TODO: insecure: use os.CleanName - f, err := os.Open(path, os.O_RDONLY, 0); - if err != nil { - c.WriteHeader(http.StatusNotFound); - fmt.Fprintf(c, "open %s: %v\n", path, err); - return; - } - n, err1 := io.Copy(f, c); - fmt.Fprintf(c, "[%d bytes]\n", n); - f.Close(); -} - -// simple flag server -var booleanflag = flag.Bool("boolean", true, "another flag for testing") -func FlagServer(c *http.Conn, req *http.Request) { - c.SetHeader("content-type", "text/plain; charset=utf-8"); - fmt.Fprint(c, "Flags:\n"); - flag.VisitAll(func (f *flag.Flag) { - if f.Value.String() != f.DefValue { - fmt.Fprintf(c, "%s = %s [default = %s]\n", f.Name, f.Value.String(), f.DefValue); - } else { - fmt.Fprintf(c, "%s = %s\n", f.Name, f.Value.String()); - } - }); -} - -// simple argument server -func ArgServer(c *http.Conn, req *http.Request) { - for i, s := range os.Args { - fmt.Fprint(c, 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(c *http.Conn, req *http.Request) { - io.WriteString(c, fmt.Sprintf("channel send #%d\n", <-ch)); -} - -// exec a program, redirecting output -func DateServer(c *http.Conn, req *http.Request) { - c.SetHeader("content-type", "text/plain; charset=utf-8"); - r, w, err := os.Pipe(); - if err != nil { - fmt.Fprintf(c, "pipe: %s\n", err); - return; - } - pid, err := os.ForkExec("/bin/date", []string{"date"}, os.Environ(), "", []*os.File{nil, w, w}); - defer r.Close(); - w.Close(); - if err != nil { - fmt.Fprintf(c, "fork/exec: %s\n", err); - return; - } - io.Copy(r, c); - wait, err := os.Wait(pid, 0); - if err != nil { - fmt.Fprintf(c, "wait: %s\n", err); - return; - } - if !wait.Exited() || wait.ExitStatus() != 0 { - fmt.Fprintf(c, "date: %v\n", wait); - return; - } -} - -func main() { - flag.Parse(); - - // The counter is published as a variable directly. - ctr := new(Counter); - http.Handle("/counter", ctr); - exvar.Publish("counter", ctr); - - http.Handle("/go/", http.HandlerFunc(FileServer)); - 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.Crash("ListenAndServe: ", err) - } -} - diff --git a/src/lib/http/url.go b/src/lib/http/url.go deleted file mode 100644 index 0325b04ee..000000000 --- a/src/lib/http/url.go +++ /dev/null @@ -1,303 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Parse URLs (actually URIs, but that seems overly pedantic). -// RFC 2396 - -package http - -import ( - "os"; - "strings" -) - -// Errors introduced by ParseURL. -type BadURL struct { - os.ErrorString -} - -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 -} - -// Return true if the specified character should be escaped when appearing in a -// URL string. -// -// TODO: for now, this is a hack; it only flags a few common characters that have -// special meaning in URLs. That will get the job done in the common cases. -func shouldEscape(c byte) bool { - switch c { - case ' ', '?', '&', '=', '#', '+', '%': - return true; - } - return false; -} - -// URLUnescape unescapes a URL-encoded string, -// converting %AB into the byte 0xAB and '+' into ' ' (space). -// It returns a BadURL error if any % is not followed -// by two hexadecimal digits. -func URLUnescape(s string) (string, os.Error) { - // Count %, check that they're well-formed. - n := 0; - anyPlusses := 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]) { - return "", BadURL{"invalid hexadecimal escape"} - } - i += 3; - case '+': - anyPlusses = true; - i++; - default: - i++ - } - } - - if n == 0 && !anyPlusses { - 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 '+': - t[j] = ' '; - j++; - i++; - default: - t[j] = s[i]; - j++; - i++; - } - } - return string(t), nil; -} - -// URLEscape converts a string into URL-encoded form. -func URLEscape(s string) string { - spaceCount, hexCount := 0, 0; - for i := 0; i < len(s); i++ { - c := s[i]; - if (shouldEscape(c)) { - if (c == ' ') { - 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++ { - c := s[i]; - if !shouldEscape(c) { - t[j] = s[i]; - j++; - } else if (c == ' ') { - t[j] = '+'; - j++; - } else { - t[j] = '%'; - t[j+1] = "0123456789abcdef"[c>>4]; - t[j+2] = "0123456789abcdef"[c&15]; - j += 3; - } - } - return string(t); -} - -// A URL represents a parsed URL (technically, a URI reference). -// The general form represented is: -// scheme://[userinfo@]host/path[?query][#fragment] -// The Raw, RawPath, and RawQuery fields are in "wire format" (special -// characters must be hex-escaped if not meant to have special meaning). -// All other fields are logical values; '+' or '%' represent themselves. -// -// Note, the reason for using wire format for the query is that it needs -// to be split into key/value pairs before decoding. -type URL struct { - Raw string; // the original string - Scheme string; // scheme - RawPath string; // //[userinfo@]host/path[?query][#fragment] - Authority string; // [userinfo@]host - Userinfo string; // userinfo - Host string; // host - Path string; // /path - 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 "", "", BadURL{"missing protocol scheme"} - } - return rawurl[0:i], rawurl[i+1:len(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:len(s)] - } - return s[0:i], s[i:len(s)] - } - } - return s, "" -} - -// BUG(rsc): ParseURL should canonicalize the path, -// removing unnecessary . and .. elements. - -// ParseURL parses rawurl into a URL structure. -// The string rawurl is assumed not to have a #fragment suffix. -// (Web browsers strip #fragment before sending the URL to a web server.) -func ParseURL(rawurl string) (url *URL, err os.Error) { - if rawurl == "" { - return nil, BadURL{"empty url"} - } - url = new(URL); - url.Raw = rawurl; - - // split off possible leading "http:", "mailto:", etc. - var path string; - if url.Scheme, path, err = getscheme(rawurl); err != nil { - return nil, err - } - url.RawPath = path; - - // RFC 2396: a relative URI (no scheme) has a ?query, - // but absolute URIs only have query if path begins with / - if url.Scheme == "" || len(path) > 0 && path[0] == '/' { - path, url.RawQuery = split(path, '?', true); - } - - // Maybe path is //authority/path - if len(path) > 2 && path[0:2] == "//" { - url.Authority, path = split(path[2:len(path)], '/', false); - } - - // If there's no @, split's default is wrong. Check explicitly. - if strings.Index(url.Authority, "@") < 0 { - url.Host = url.Authority; - } else { - url.Userinfo, url.Host = split(url.Authority, '@', true); - } - - // What's left is the path. - // TODO: Canonicalize (remove . and ..)? - if url.Path, err = URLUnescape(path); err != nil { - return nil, err - } - - // Remove escapes from the Authority and Userinfo fields, and verify - // that Scheme and Host contain no escapes (that would be illegal). - if url.Authority, err = URLUnescape(url.Authority); err != nil { - return nil, err - } - if url.Userinfo, err = URLUnescape(url.Userinfo); err != nil { - return nil, err - } - if (strings.Index(url.Scheme, "%") >= 0) { - return nil, BadURL{"hexadecimal escape in scheme"} - } - if (strings.Index(url.Host, "%") >= 0) { - return nil, BadURL{"hexadecimal escape in host"} - } - - return url, nil -} - -// ParseURLReference is like ParseURL but allows a trailing #fragment. -func ParseURLReference(rawurlref string) (url *URL, err os.Error) { - // Cut off #frag. - rawurl, frag := split(rawurlref, '#', true); - if url, err = ParseURL(rawurl); err != nil { - return nil, err - } - if url.Fragment, err = URLUnescape(frag); err != nil { - return nil, 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, Userinfo, -// RawQuery, and Fragment, but not Raw, RawPath or Authority. -func (url *URL) String() string { - result := ""; - if url.Scheme != "" { - result += url.Scheme + ":"; - } - if url.Host != "" || url.Userinfo != "" { - result += "//"; - if url.Userinfo != "" { - result += URLEscape(url.Userinfo) + "@"; - } - result += url.Host; - } - result += URLEscape(url.Path); - if url.RawQuery != "" { - result += "?" + url.RawQuery; - } - if url.Fragment != "" { - result += "#" + URLEscape(url.Fragment); - } - return result; -} diff --git a/src/lib/http/url_test.go b/src/lib/http/url_test.go deleted file mode 100644 index 8d8fabad5..000000000 --- a/src/lib/http/url_test.go +++ /dev/null @@ -1,348 +0,0 @@ -// Copyright 2009 The Go Authors. 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"; - "http"; - "os"; - "reflect"; - "testing"; -) - -// TODO(rsc): -// test URLUnescape -// test URLEscape -// test ParseURL - -type URLTest struct { - in string; - out *URL; - roundtrip string; // expected result of reserializing the URL; empty means same as "in". -} - -var urltests = []URLTest { - // no path - URLTest{ - "http://www.google.com", - &URL{ - "http://www.google.com", - "http", "//www.google.com", - "www.google.com", "", "www.google.com", - "", "", "" - }, - "" - }, - // path - URLTest{ - "http://www.google.com/", - &URL{ - "http://www.google.com/", - "http", "//www.google.com/", - "www.google.com", "", "www.google.com", - "/", "", "" - }, - "" - }, - // path with hex escaping... note that space roundtrips to + - URLTest{ - "http://www.google.com/file%20one%26two", - &URL{ - "http://www.google.com/file%20one%26two", - "http", "//www.google.com/file%20one%26two", - "www.google.com", "", "www.google.com", - "/file one&two", "", "" - }, - "http://www.google.com/file+one%26two" - }, - // user - URLTest{ - "ftp://webmaster@www.google.com/", - &URL{ - "ftp://webmaster@www.google.com/", - "ftp", "//webmaster@www.google.com/", - "webmaster@www.google.com", "webmaster", "www.google.com", - "/", "", "" - }, - "" - }, - // escape sequence in username - URLTest{ - "ftp://john%20doe@www.google.com/", - &URL{ - "ftp://john%20doe@www.google.com/", - "ftp", "//john%20doe@www.google.com/", - "john doe@www.google.com", "john doe", "www.google.com", - "/", "", "" - }, - "ftp://john+doe@www.google.com/" - }, - // query - URLTest{ - "http://www.google.com/?q=go+language", - &URL{ - "http://www.google.com/?q=go+language", - "http", "//www.google.com/?q=go+language", - "www.google.com", "", "www.google.com", - "/", "q=go+language", "" - }, - "" - }, - // query with hex escaping: NOT parsed - URLTest{ - "http://www.google.com/?q=go%20language", - &URL{ - "http://www.google.com/?q=go%20language", - "http", "//www.google.com/?q=go%20language", - "www.google.com", "", "www.google.com", - "/", "q=go%20language", "" - }, - "" - }, - // path without /, so no query parsing - URLTest{ - "http:www.google.com/?q=go+language", - &URL{ - "http:www.google.com/?q=go+language", - "http", "www.google.com/?q=go+language", - "", "", "", - "www.google.com/?q=go language", "", "" - }, - "http:www.google.com/%3fq%3dgo+language" - }, - // non-authority - URLTest{ - "mailto:/webmaster@golang.org", - &URL{ - "mailto:/webmaster@golang.org", - "mailto", "/webmaster@golang.org", - "", "", "", - "/webmaster@golang.org", "", "" - }, - "" - }, - // non-authority - URLTest{ - "mailto:webmaster@golang.org", - &URL{ - "mailto:webmaster@golang.org", - "mailto", "webmaster@golang.org", - "", "", "", - "webmaster@golang.org", "", "" - }, - "" - }, -} - -var urlnofragtests = []URLTest { - URLTest{ - "http://www.google.com/?q=go+language#foo", - &URL{ - "http://www.google.com/?q=go+language#foo", - "http", "//www.google.com/?q=go+language#foo", - "www.google.com", "", "www.google.com", - "/", "q=go+language#foo", "" - }, - "" - }, -} - -var urlfragtests = []URLTest { - URLTest{ - "http://www.google.com/?q=go+language#foo", - &URL{ - "http://www.google.com/?q=go+language", - "http", "//www.google.com/?q=go+language", - "www.google.com", "", "www.google.com", - "/", "q=go+language", "foo" - }, - "" - }, - URLTest{ - "http://www.google.com/?q=go+language#foo%26bar", - &URL{ - "http://www.google.com/?q=go+language", - "http", "//www.google.com/?q=go+language", - "www.google.com", "", "www.google.com", - "/", "q=go+language", "foo&bar" - }, - "" - }, -} - -// more useful string for debugging than fmt's struct printer -func ufmt(u *URL) string { - return fmt.Sprintf("%q, %q, %q, %q, %q, %q, %q, %q, %q", - u.Raw, u.Scheme, u.RawPath, u.Authority, u.Userinfo, - u.Host, u.Path, u.RawQuery, u.Fragment); -} - -func DoTest(t *testing.T, parse func(string) (*URL, os.Error), name string, tests []URLTest) { - for i, tt := range tests { - u, err := parse(tt.in); - if err != nil { - t.Errorf("%s(%q) returned error %s", name, tt.in, err); - continue; - } - if !reflect.DeepEqual(u, tt.out) { - t.Errorf("%s(%q):\n\thave %v\n\twant %v\n", - name, tt.in, ufmt(u), ufmt(tt.out)); - } - } -} - -func TestParseURL(t *testing.T) { - DoTest(t, ParseURL, "ParseURL", urltests); - DoTest(t, ParseURL, "ParseURL", urlnofragtests); -} - -func TestParseURLReference(t *testing.T) { - DoTest(t, ParseURLReference, "ParseURLReference", urltests); - DoTest(t, ParseURLReference, "ParseURLReference", urlfragtests); -} - -func DoTestString(t *testing.T, parse func(string) (*URL, os.Error), name string, tests []URLTest) { - for i, tt := range tests { - u, err := parse(tt.in); - if err != nil { - t.Errorf("%s(%q) returned error %s", name, tt.in, err); - continue; - } - s := u.String(); - expected := tt.in; - if len(tt.roundtrip) > 0 { - expected = tt.roundtrip; - } - if s != expected { - t.Errorf("%s(%q).String() == %q (expected %q)", name, tt.in, s, expected); - } - } -} - -func TestURLString(t *testing.T) { - DoTestString(t, ParseURL, "ParseURL", urltests); - DoTestString(t, ParseURL, "ParseURL", urlfragtests); - DoTestString(t, ParseURL, "ParseURL", urlnofragtests); - DoTestString(t, ParseURLReference, "ParseURLReference", urltests); - DoTestString(t, ParseURLReference, "ParseURLReference", urlfragtests); - DoTestString(t, ParseURLReference, "ParseURLReference", urlnofragtests); -} - -type URLEscapeTest struct { - in string; - out string; - err os.Error; -} - -var unescapeTests = []URLEscapeTest { - URLEscapeTest{ - "", - "", - nil - }, - URLEscapeTest{ - "abc", - "abc", - nil - }, - URLEscapeTest{ - "1%41", - "1A", - nil - }, - URLEscapeTest{ - "1%41%42%43", - "1ABC", - nil - }, - URLEscapeTest{ - "%4a", - "J", - nil - }, - URLEscapeTest{ - "%6F", - "o", - nil - }, - URLEscapeTest{ - "%", // not enough characters after % - "", - BadURL{"invalid hexadecimal escape"} - }, - URLEscapeTest{ - "%a", // not enough characters after % - "", - BadURL{"invalid hexadecimal escape"} - }, - URLEscapeTest{ - "%1", // not enough characters after % - "", - BadURL{"invalid hexadecimal escape"} - }, - URLEscapeTest{ - "123%45%6", // not enough characters after % - "", - BadURL{"invalid hexadecimal escape"} - }, - URLEscapeTest{ - "%zz", // invalid hex digits - "", - BadURL{"invalid hexadecimal escape"} - }, -} - -func TestURLUnescape(t *testing.T) { - for i, tt := range unescapeTests { - actual, err := URLUnescape(tt.in); - if actual != tt.out || (err != nil) != (tt.err != nil) { - t.Errorf("URLUnescape(%q) = %q, %s; want %q, %s", tt.in, actual, err, tt.out, tt.err); - } - } -} - -var escapeTests = []URLEscapeTest { - URLEscapeTest{ - "", - "", - nil - }, - URLEscapeTest{ - "abc", - "abc", - nil - }, - URLEscapeTest{ - "one two", - "one+two", - nil - }, - URLEscapeTest{ - "10%", - "10%25", - nil - }, - URLEscapeTest{ - " ?&=#+%!", - "+%3f%26%3d%23%2b%25!", - nil - }, -} - -func TestURLEscape(t *testing.T) { - for i, tt := range escapeTests { - actual := URLEscape(tt.in); - if tt.out != actual { - t.Errorf("URLEscape(%q) = %q, want %q", tt.in, actual, tt.out); - } - - // for bonus points, verify that escape:unescape is an identity. - roundtrip, err := URLUnescape(actual); - if roundtrip != tt.in || err != nil { - t.Errorf("URLUnescape(%q) = %q, %s; want %q, %s", actual, roundtrip, err, tt.in, "[no error]"); - } - } -} - diff --git a/src/lib/io/Makefile b/src/lib/io/Makefile deleted file mode 100644 index 219ea776b..000000000 --- a/src/lib/io/Makefile +++ /dev/null @@ -1,70 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m >Makefile - -D= - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - bytebuffer.$O\ - io.$O\ - -O2=\ - pipe.$O\ - utils.$O\ - - -phases: a1 a2 -_obj$D/io.a: phases - -a1: $(O1) - $(AR) grc _obj$D/io.a bytebuffer.$O io.$O - rm -f $(O1) - -a2: $(O2) - $(AR) grc _obj$D/io.a pipe.$O utils.$O - rm -f $(O2) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/io.a - -$(O1): newpkg -$(O2): a1 -$(O3): a2 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/io.a - -packages: _obj$D/io.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/io.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/io.a diff --git a/src/lib/io/bytebuffer.go b/src/lib/io/bytebuffer.go deleted file mode 100644 index 921ddb17a..000000000 --- a/src/lib/io/bytebuffer.go +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package io - -// Simple byte buffer for marshaling data. - -import ( - "io"; - "os"; -) - -func bytecopy(dst []byte, doff int, src []byte, soff int, count int) { - for ; count > 0; count-- { - dst[doff] = src[soff]; - doff++; - soff++; - } -} - -// A ByteBuffer is a simple implementation of the io.Read and io.Write interfaces -// connected to a buffer of bytes. -// The zero value for ByteBuffer is an empty buffer ready to use. -type ByteBuffer struct { - buf []byte; // contents are the bytes buf[off : len(buf)] - off int; // read at &buf[off], write at &buf[len(buf)] -} - -// Data returns the contents of the unread portion of the buffer; -// len(b.Data()) == b.Len(). -func (b *ByteBuffer) Data() []byte { - return b.buf[b.off : len(b.buf)] -} - -// Len returns the number of bytes of the unread portion of the buffer; -// b.Len() == len(b.Data()). -func (b *ByteBuffer) 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 *ByteBuffer) Truncate(n int) { - 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 *ByteBuffer) Reset() { - b.Truncate(0); -} - -// Write appends the contents of p to the buffer. The return -// value n is the length of p; err is always nil. -func (b *ByteBuffer) Write(p []byte) (n int, err os.Error) { - m := b.Len(); - n = len(p); - - if len(b.buf) + n > cap(b.buf) { - // not enough space at end - buf := b.buf; - if m + n > cap(b.buf) { - // not enough space anywhere - buf = make([]byte, 2*cap(b.buf) + n) - } - bytecopy(buf, 0, b.buf, b.off, m); - b.buf = buf; - b.off = 0 - } - - b.buf = b.buf[0 : b.off + m + n]; - bytecopy(b.buf, b.off + m, p, 0, n); - return n, nil -} - -// 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 *ByteBuffer) WriteByte(c byte) os.Error { - b.Write([]byte{c}); - return 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; err is always nil. -func (b *ByteBuffer) Read(p []byte) (n int, err os.Error) { - m := b.Len(); - n = len(p); - - if n > m { - // more bytes requested than available - n = m - } - - bytecopy(p, 0, b.buf, b.off, n); - b.off += n; - return n, nil -} - -// NewByteBufferFromArray creates and initializes a new ByteBuffer -// with buf as its initial contents. -func NewByteBufferFromArray(buf []byte) *ByteBuffer { - return &ByteBuffer{buf, 0}; -} diff --git a/src/lib/io/bytebuffer_test.go b/src/lib/io/bytebuffer_test.go deleted file mode 100644 index 5a5432223..000000000 --- a/src/lib/io/bytebuffer_test.go +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright 2009 The Go Authors. 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 ( - "io"; - "rand"; - "testing"; -) - - -const N = 10000; // make this bigger for a larger (and slower) test -var data []byte; // test data for write tests - - -func init() { - data = make([]byte, N); - for i := 0; i < len(data); i++ { - data[i] = 'a' + byte(i % 26) - } -} - - -// Verify that contents of buf match the string s. -func check(t *testing.T, testname string, buf *ByteBuffer, s string) { - if buf.Len() != len(buf.Data()) { - t.Errorf("%s: buf.Len() == %d, len(buf.Data()) == %d\n", testname, buf.Len(), len(buf.Data())) - } - - if buf.Len() != len(s) { - t.Errorf("%s: buf.Len() == %d, len(s) == %d\n", testname, buf.Len(), len(s)) - } - - if string(buf.Data()) != s { - t.Errorf("%s: string(buf.Data()) == %q, s == %q\n", testname, string(buf.Data()), s) - } -} - - -// Fill buf through n writes of fub. -// The initial contents of buf corresponds to the string s; -// the result is the final contents of buf returned as a string. -func fill(t *testing.T, testname string, buf *ByteBuffer, 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\n", m, len(fub)); - } - if err != nil { - t.Errorf(testname + " (fill 3): err should always be nil, found err == %s\n", err); - } - s += string(fub); - check(t, testname + " (fill 4)", buf, s); - } - return s; -} - - -// 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 *ByteBuffer, 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\n", err); - } - s = s[n : len(s)]; - check(t, testname + " (empty 3)", buf, s); - } - - check(t, testname + " (empty 4)", buf, ""); -} - - -func TestBasicOperations(t *testing.T) { - var buf ByteBuffer; - - 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(data[0 : 1]); - if n != 1 { - t.Errorf("wrote 1 byte, but n == %d\n", n); - } - if err != nil { - t.Errorf("err should always be nil, but err == %s\n", err); - } - check(t, "TestBasicOperations (4)", &buf, "a"); - - buf.WriteByte(data[1]); - check(t, "TestBasicOperations (5)", &buf, "ab"); - - n, err = buf.Write(data[2 : 26]); - if n != 24 { - t.Errorf("wrote 25 bytes, but n == %d\n", 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)); - } -} - - -func TestLargeWrites(t *testing.T) { - var buf ByteBuffer; - for i := 3; i < 30; i += 3 { - s := fill(t, "TestLargeWrites (1)", &buf, "", 5, data); - empty(t, "TestLargeWrites (2)", &buf, s, make([]byte, len(data)/i)); - } - check(t, "TestLargeWrites (3)", &buf, ""); -} - - -func TestLargeReads(t *testing.T) { - var buf ByteBuffer; - for i := 3; i < 30; i += 3 { - s := fill(t, "TestLargeReads (1)", &buf, "", 5, data[0 : len(data)/i]); - empty(t, "TestLargeReads (2)", &buf, s, make([]byte, len(data))); - } - check(t, "TestLargeReads (3)", &buf, ""); -} - - -func TestMixedReadsAndWrites(t *testing.T) { - var buf ByteBuffer; - s := ""; - for i := 0; i < 50; i++ { - wlen := rand.Intn(len(data)); - s = fill(t, "TestMixedReadsAndWrites (1)", &buf, s, 1, data[0 : wlen]); - - rlen := rand.Intn(len(data)); - fub := make([]byte, rlen); - n, err := buf.Read(fub); - s = s[n : len(s)]; - } - empty(t, "TestMixedReadsAndWrites (2)", &buf, s, make([]byte, buf.Len())); -} diff --git a/src/lib/io/io.go b/src/lib/io/io.go deleted file mode 100644 index ba0449ac1..000000000 --- a/src/lib/io/io.go +++ /dev/null @@ -1,223 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// This package provides basic interfaces to I/O primitives. -// Its primary job is to wrap existing implementations of such primitives, -// such as those in package os, into shared public interfaces that -// abstract the functionality. -// It also provides buffering primitives and some other basic operations. -package io - -import ( - "bytes"; - "os"; -) - -// Error represents an unexpected I/O behavior. -type Error struct { - os.ErrorString -} - -// ErrEOF means that data was expected, but a read got EOF instead. -var ErrEOF os.Error = &Error{"EOF"} - -// ErrShortWrite means that a write accepted fewer bytes than requested -// but failed to return an explicit error. -var ErrShortWrite os.Error = &Error{"short write"} - - -// Reader is the interface that wraps the basic Read method. -// An implementation of Read is allowed to use all of p for -// scratch space during the call, even if it eventually returns -// n < len(p). -type Reader interface { - Read(p []byte) (n int, err os.Error); -} - -// Writer is the interface that wraps the basic Write method. -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; -} - -// ReadWrite 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; -} - -// Convert a string to an array of bytes for easy marshaling. -func StringBytes(s string) []byte { - b := make([]byte, len(s)); - for i := 0; i < len(s); i++ { - b[i] = s[i]; - } - return b; -} - -// WriteString writes the contents of the string s to w, which accepts an array of bytes. -func WriteString(w Writer, s string) (n int, err os.Error) { - return w.Write(StringBytes(s)) -} - -// ReadAtLeast reads r into buf until at least min bytes have been read, -// or until EOF or error. -func ReadAtLeast(r Reader, buf []byte, min int) (n int, err os.Error) { - n = 0; - for n < min { - nn, e := r.Read(buf[n:len(buf)]); - if nn > 0 { - n += nn - } - if e != nil { - return n, e - } - if nn <= 0 { - return n, ErrEOF // no error but insufficient data - } - } - return n, nil -} - -// FullRead reads r until the buffer buf is full, or until EOF or error. -func FullRead(r Reader, buf []byte) (n int, err os.Error) { - // TODO(rsc): 6g bug prevents obvious return - n, err = ReadAtLeast(r, buf, len(buf)); - return; -} - -// Convert something that implements Read into something -// whose Reads are always FullReads -type fullRead struct { - r Reader; -} - -func (fr *fullRead) Read(p []byte) (n int, err os.Error) { - n, err = FullRead(fr.r, p); - return n, err -} - -// MakeFullReader takes r, an implementation of Read, and returns an object -// that still implements Read but always calls FullRead underneath. -func MakeFullReader(r Reader) Reader { - if fr, ok := r.(*fullRead); ok { - // already a fullRead - return r - } - return &fullRead{r} -} - -// Copy n copies n bytes (or until EOF is reached) from src to dst. -// It returns the number of bytes copied and the error, if any. -func Copyn(src Reader, dst Writer, n int64) (written int64, err os.Error) { - 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 = os.EIO; - break; - } - } - if er != nil { - err = er; - break; - } - if nr == 0 { - err = ErrEOF; - break; - } - } - return written, err -} - -// Copy copies from src to dst until EOF is reached. -// It returns the number of bytes copied and the error, if any. -func Copy(src Reader, dst Writer) (written int64, err os.Error) { - 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 = os.EIO; - break; - } - } - if er != nil { - err = er; - break; - } - if nr == 0 { - break; - } - } - return written, err -} - -// A ByteReader satisfies Reads by consuming data from a slice of bytes. -// Clients can call NewByteReader to create one or wrap pointers -// to their own slices: r := ByteReader{&data}. -type ByteReader struct { - Data *[]byte -} - -func (r ByteReader) Read(p []byte) (int, os.Error) { - n := len(p); - b := r.Data; - if n > len(b) { - n = len(b); - } - bytes.Copy(p, b[0:n]); - *b = b[n:len(b)]; - return n, nil; -} - -// NewByteReader returns a new ByteReader reading from data. -func NewByteReader(data []byte) ByteReader { - return ByteReader{ &data }; -} - diff --git a/src/lib/io/pipe.go b/src/lib/io/pipe.go deleted file mode 100644 index 1a443ddce..000000000 --- a/src/lib/io/pipe.go +++ /dev/null @@ -1,226 +0,0 @@ -// Copyright 2009 The Go 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.Read -// with code expecting an io.Write. - -package io - -import ( - "io"; - "os"; - "sync"; -) - -type pipeReturn struct { - n int; - err os.Error; -} - -// Shared pipe structure. -type pipe struct { - rclosed bool; // Read end closed? - rerr os.Error; // Error supplied to CloseReader - wclosed bool; // Write end closed? - werr os.Error; // Error supplied to CloseWriter - wpend []byte; // Written data waiting to be read. - wtot int; // Bytes consumed so far in current write. - cr chan []byte; // Write sends data here... - cw chan pipeReturn; // ... and reads the n, err back from here. -} - -func (p *pipe) Read(data []byte) (n int, err os.Error) { - if p == nil || p.rclosed { - return 0, os.EINVAL; - } - - // Wait for next write block if necessary. - if p.wpend == nil { - if !p.wclosed { - p.wpend = <-p.cr; - } - if p.wpend == nil { - return 0, p.werr; - } - p.wtot = 0; - } - - // Read from current write block. - n = len(data); - if n > len(p.wpend) { - n = len(p.wpend); - } - for i := 0; i < n; i++ { - data[i] = p.wpend[i]; - } - p.wtot += n; - p.wpend = p.wpend[n:len(p.wpend)]; - - // If write block is done, finish the write. - if len(p.wpend) == 0 { - p.wpend = nil; - p.cw <- pipeReturn{p.wtot, nil}; - p.wtot = 0; - } - - return n, nil; -} - -func (p *pipe) Write(data []byte) (n int, err os.Error) { - if p == nil || p.wclosed { - return 0, os.EINVAL; - } - if p.rclosed { - return 0, p.rerr; - } - - // Send data to reader. - p.cr <- data; - - // Wait for reader to finish copying it. - res := <-p.cw; - return res.n, res.err; -} - -func (p *pipe) CloseReader(rerr os.Error) os.Error { - if p == nil || p.rclosed { - return os.EINVAL; - } - - // Stop any future writes. - p.rclosed = true; - if rerr == nil { - rerr = os.EPIPE; - } - p.rerr = rerr; - - // Stop the current write. - if !p.wclosed { - p.cw <- pipeReturn{p.wtot, rerr}; - } - - return nil; -} - -func (p *pipe) CloseWriter(werr os.Error) os.Error { - if p == nil || p.wclosed { - return os.EINVAL; - } - - // Stop any future reads. - p.wclosed = true; - p.werr = werr; - - // Stop the current read. - if !p.rclosed { - p.cr <- nil; - } - - return nil; -} - -// Read/write halves of the pipe. -// They are separate structures for two reasons: -// 1. If one end becomes garbage without being Closed, -// its finisher can Close so that the other end -// does not hang indefinitely. -// 2. Clients cannot use interface conversions on the -// read end to find the Write method, and vice versa. - -// A PipeReader is the read half of a pipe. -type PipeReader struct { - lock sync.Mutex; - 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 nil. -func (r *PipeReader) Read(data []byte) (n int, err os.Error) { - r.lock.Lock(); - defer r.lock.Unlock(); - - 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 { - r.lock.Lock(); - defer r.lock.Unlock(); - - return r.p.CloseReader(nil); -} - -// CloseWithError closes the reader; subsequent writes -// to the write half of the pipe will return the error rerr. -func (r *PipeReader) CloseWithError(rerr os.Error) os.Error { - r.lock.Lock(); - defer r.lock.Unlock(); - - return r.p.CloseReader(rerr); -} - -func (r *PipeReader) finish() { - r.Close(); -} - -// Write half of pipe. -type PipeWriter struct { - lock sync.Mutex; - 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) { - w.lock.Lock(); - defer w.lock.Unlock(); - - return w.p.Write(data); -} - -// Close closes the writer; subsequent reads from the -// read half of the pipe will return no bytes and a nil error. -func (w *PipeWriter) Close() os.Error { - w.lock.Lock(); - defer w.lock.Unlock(); - - return w.p.CloseWriter(nil); -} - -// CloseWithError closes the writer; subsequent reads from the -// read half of the pipe will return no bytes and the error werr. -func (w *PipeWriter) CloseWithError(werr os.Error) os.Error { - w.lock.Lock(); - defer w.lock.Unlock(); - - return w.p.CloseWriter(werr); -} - -func (w *PipeWriter) finish() { - w.Close(); -} - -// 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.cr = make(chan []byte, 1); - p.cw = make(chan pipeReturn, 1); - r := new(PipeReader); - r.p = p; - w := new(PipeWriter); - w.p = p; - return r, w; -} - diff --git a/src/lib/io/pipe_test.go b/src/lib/io/pipe_test.go deleted file mode 100644 index 277f44525..000000000 --- a/src/lib/io/pipe_test.go +++ /dev/null @@ -1,225 +0,0 @@ -// Copyright 2009 The Go Authors. 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 ( - "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, StringBytes("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 != nil { - t.Errorf("read: %v", err); - } - c <- n; - if n == 0 { - break; - } - } -} - -// 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); - } -} - -// 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 { - 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 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 { - pipeTest{ true, nil, false }, - pipeTest{ true, nil, true }, - pipeTest{ true, io.ErrShortWrite, true }, - pipeTest{ false, nil, false }, - pipeTest{ false, nil, true }, - pipeTest{ false, io.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; - if err != tt.err { - t.Errorf("read from closed pipe: %v want %v", err, tt.err); - } - 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 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); - } - } -} diff --git a/src/lib/io/utils.go b/src/lib/io/utils.go deleted file mode 100644 index a4cbb2d9a..000000000 --- a/src/lib/io/utils.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Utility functions. - -package io - -import ( - "io"; - "os"; -) - -// ReadAll reads from r until an error or EOF and returns the data it read. -func ReadAll(r Reader) ([]byte, os.Error) { - var buf ByteBuffer; - n, err := io.Copy(r, &buf); - return buf.Data(), err; -} - -// ReadFile reads the file named by filename and returns the contents. -func ReadFile(filename string) ([]byte, os.Error) { - f, err := os.Open(filename, os.O_RDONLY, 0); - if err != nil { - return nil, err; - } - defer f.Close(); - return ReadAll(f); -} diff --git a/src/lib/io/utils_test.go b/src/lib/io/utils_test.go deleted file mode 100644 index f35dad60c..000000000 --- a/src/lib/io/utils_test.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package io - -import ( - "io"; - "os"; - "testing"; -) - -func checkSize(t *testing.T, path string, size uint64) { - 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 = "utils_test.go"; - contents, err = ReadFile(filename); - if err != nil { - t.Fatalf("ReadFile %s: %v", filename, err); - } - - checkSize(t, filename, uint64(len(contents))); -} diff --git a/src/lib/json/Makefile b/src/lib/json/Makefile deleted file mode 100644 index 2d70c2cf8..000000000 --- a/src/lib/json/Makefile +++ /dev/null @@ -1,69 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m >Makefile - -D= - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - parse.$O\ - -O2=\ - generic.$O\ - struct.$O\ - - -phases: a1 a2 -_obj$D/json.a: phases - -a1: $(O1) - $(AR) grc _obj$D/json.a parse.$O - rm -f $(O1) - -a2: $(O2) - $(AR) grc _obj$D/json.a generic.$O struct.$O - rm -f $(O2) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/json.a - -$(O1): newpkg -$(O2): a1 -$(O3): a2 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/json.a - -packages: _obj$D/json.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/json.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/json.a diff --git a/src/lib/json/generic.go b/src/lib/json/generic.go deleted file mode 100644 index e3194eb17..000000000 --- a/src/lib/json/generic.go +++ /dev/null @@ -1,331 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Generic representation of JSON objects. - -package json - -import ( - "container/vector"; - "fmt"; - "json"; - "math"; - "strconv"; - "strings"; -) - -// Integers identifying the data type in the Json interface. -const ( - StringKind = iota; - NumberKind; - MapKind; // JSON term is "Object", but in Go, it's a map - ArrayKind; - BoolKind; - NullKind; -) - -// The Json interface is implemented by all JSON objects. -type Json interface { - Kind() int; // StringKind, NumberKind, etc. - String() string; // a string form (any kind) - Number() float64; // numeric form (NumberKind) - Bool() bool; // boolean (BoolKind) - Get(s string) Json; // field lookup (MapKind) - Elem(i int) Json; // element lookup (ArrayKind) - Len() int; // length (ArrayKind, MapKind) -} - -// JsonToString returns the textual JSON syntax representation -// for the JSON object j. -// -// JsonToString differs from j.String() in the handling -// of string objects. If j represents the string abc, -// j.String() == `abc`, but JsonToString(j) == `"abc"`. -func JsonToString(j Json) string { - if j == nil { - return "null" - } - if j.Kind() == StringKind { - return Quote(j.String()) - } - return j.String() -} - -type _Null struct { } - -// Null is the JSON object representing the null data object. -var Null Json = &_Null{} - -func (*_Null) Kind() int { return NullKind } -func (*_Null) String() string { return "null" } -func (*_Null) Number() float64 { return 0 } -func (*_Null) Bool() bool { return false } -func (*_Null) Get(s string) Json { return Null } -func (*_Null) Elem(int) Json { return Null } -func (*_Null) Len() int { return 0 } - -type _String struct { s string; _Null } -func (j *_String) Kind() int { return StringKind } -func (j *_String) String() string { return j.s } - -type _Number struct { f float64; _Null } -func (j *_Number) Kind() int { return NumberKind } -func (j *_Number) Number() float64 { return j.f } -func (j *_Number) String() string { - if math.Floor(j.f) == j.f { - return fmt.Sprintf("%.0f", j.f); - } - return fmt.Sprintf("%g", j.f); -} - -type _Array struct { a *vector.Vector; _Null } -func (j *_Array) Kind() int { return ArrayKind } -func (j *_Array) Len() int { return j.a.Len() } -func (j *_Array) Elem(i int) Json { - if i < 0 || i >= j.a.Len() { - return Null - } - return j.a.At(i).(Json) -} -func (j *_Array) String() string { - s := "["; - for i := 0; i < j.a.Len(); i++ { - if i > 0 { - s += ","; - } - s += JsonToString(j.a.At(i).(Json)); - } - s += "]"; - return s; -} - -type _Bool struct { b bool; _Null } -func (j *_Bool) Kind() int { return BoolKind } -func (j *_Bool) Bool() bool { return j.b } -func (j *_Bool) String() string { - if j.b { - return "true" - } - return "false" -} - -type _Map struct { m map[string]Json; _Null } -func (j *_Map) Kind() int { return MapKind } -func (j *_Map) Len() int { return len(j.m) } -func (j *_Map) Get(s string) Json { - if j.m == nil { - return Null - } - v, ok := j.m[s]; - if !ok { - return Null - } - return v; -} -func (j *_Map) String() string { - s := "{"; - first := true; - for k,v := range j.m { - if first { - first = false; - } else { - s += ","; - } - s += Quote(k); - s += ":"; - s += JsonToString(v); - } - s += "}"; - return s; -} - -// Walk evaluates path relative to the JSON object j. -// Path is taken as a sequence of slash-separated field names -// or numbers that can be used to index into JSON map and -// array objects. -// -// For example, if j is the JSON object for -// {"abc": [true, false]}, then Walk(j, "abc/1") returns the -// JSON object for true. -func Walk(j Json, path string) Json { - for len(path) > 0 { - var elem string; - if i := strings.Index(path, "/"); i >= 0 { - elem = path[0:i]; - path = path[i+1:len(path)]; - } else { - elem = path; - path = ""; - } - switch j.Kind() { - case ArrayKind: - indx, err := strconv.Atoi(elem); - if err != nil { - return Null - } - j = j.Elem(indx); - case MapKind: - j = j.Get(elem); - default: - return Null - } - } - return j -} - -// Equal returns whether a and b are indistinguishable JSON objects. -func Equal(a, b Json) bool { - switch { - case a == nil && b == nil: - return true; - case a == nil || b == nil: - return false; - case a.Kind() != b.Kind(): - return false; - } - - switch a.Kind() { - case NullKind: - return true; - case StringKind: - return a.String() == b.String(); - case NumberKind: - return a.Number() == b.Number(); - case BoolKind: - return a.Bool() == b.Bool(); - case ArrayKind: - if a.Len() != b.Len() { - return false; - } - for i := 0; i < a.Len(); i++ { - if !Equal(a.Elem(i), b.Elem(i)) { - return false; - } - } - return true; - case MapKind: - m := a.(*_Map).m; - if len(m) != len(b.(*_Map).m) { - return false; - } - for k,v := range m { - if !Equal(v, b.Get(k)) { - return false; - } - } - return true; - } - - // invalid kind - return false; -} - - -// Parse builder for JSON objects. - -type _JsonBuilder struct { - // either writing to *ptr - ptr *Json; - - // or to a[i] (can't set ptr = &a[i]) - a *vector.Vector; - i int; - - // or to m[k] (can't set ptr = &m[k]) - m map[string] Json; - k string; -} - -func (b *_JsonBuilder) Put(j Json) { - switch { - case b.ptr != nil: - *b.ptr = j; - case b.a != nil: - b.a.Set(b.i, j); - case b.m != nil: - b.m[b.k] = j; - } -} - -func (b *_JsonBuilder) Get() Json { - switch { - case b.ptr != nil: - return *b.ptr; - case b.a != nil: - return b.a.At(b.i).(Json); - case b.m != nil: - return b.m[b.k]; - } - return nil -} - -func (b *_JsonBuilder) Float64(f float64) { - b.Put(&_Number{f, _Null{}}) -} - -func (b *_JsonBuilder) Int64(i int64) { - b.Float64(float64(i)) -} - -func (b *_JsonBuilder) Uint64(i uint64) { - b.Float64(float64(i)) -} - -func (b *_JsonBuilder) Bool(tf bool) { - b.Put(&_Bool{tf, _Null{}}) -} - -func (b *_JsonBuilder) Null() { - b.Put(Null) -} - -func (b *_JsonBuilder) String(s string) { - b.Put(&_String{s, _Null{}}) -} - - -func (b *_JsonBuilder) Array() { - b.Put(&_Array{vector.New(0), _Null{}}) -} - -func (b *_JsonBuilder) Map() { - b.Put(&_Map{make(map[string]Json), _Null{}}) -} - -func (b *_JsonBuilder) Elem(i int) Builder { - bb := new(_JsonBuilder); - bb.a = b.Get().(*_Array).a; - bb.i = i; - for i >= bb.a.Len() { - bb.a.Push(Null) - } - return bb -} - -func (b *_JsonBuilder) Key(k string) Builder { - bb := new(_JsonBuilder); - bb.m = b.Get().(*_Map).m; - bb.k = k; - bb.m[k] = Null; - return bb -} - -// StringToJson parses the string s as a JSON-syntax string -// and returns the generic JSON object representation. -// On success, StringToJson returns with ok set to true and errtok empty. -// If StringToJson encounters a syntax error, it returns with -// ok set to false and errtok set to a fragment of the offending syntax. -func StringToJson(s string) (json Json, ok bool, errtok string) { - var errindx int; - var j Json; - b := new(_JsonBuilder); - b.ptr = &j; - ok, errindx, errtok = Parse(s, b); - if !ok { - return nil, false, errtok - } - return j, true, "" -} - -// BUG(rsc): StringToJson should return an os.Error instead of a bool. diff --git a/src/lib/json/generic_test.go b/src/lib/json/generic_test.go deleted file mode 100644 index 68868d7a5..000000000 --- a/src/lib/json/generic_test.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2009 The Go Authors. 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 ( - "json"; - "testing"; -) - -var jsontests = []string { - `null`, - `true`, - `false`, - `"abc"`, - `123`, - `0.1`, - `1e-10`, - `[]`, - `[1,2,3,4]`, - `[1,2,"abc",null,true,false]`, - `{}`, - `{"a":1}`, -} - -func TestJson(t *testing.T) { - for i := 0; i < len(jsontests); i++ { - val, ok, errtok := StringToJson(jsontests[i]); - if !ok { - t.Errorf("StringToJson(%#q) => error near %v", jsontests[i], errtok); - continue; - } - str := JsonToString(val); - if str != jsontests[i] { - t.Errorf("JsonToString(StringToJson(%#q)) = %#q", jsontests[i], str); - continue; - } - } -} - -func TestJsonMap(t *testing.T) { - values := make(map[string]Json); - mapstr := "{"; - for i := 0; i < len(jsontests); i++ { - val, ok, errtok := StringToJson(jsontests[i]); - if !ok { - t.Errorf("StringToJson(%#q) => error near %v", jsontests[i], errtok); - } - if i > 0 { - mapstr += ","; - } - values[jsontests[i]] = val; - mapstr += Quote(jsontests[i]); - mapstr += ":"; - mapstr += JsonToString(val); - } - mapstr += "}"; - - mapv, ok, errtok := StringToJson(mapstr); - if !ok { - t.Fatalf("StringToJson(%#q) => error near %v", mapstr, errtok); - } - if mapv == nil { - t.Fatalf("StringToJson(%#q) => nil, %v, %v", mapstr, ok, errtok); - } - if cnt := mapv.Len(); cnt != len(jsontests) { - t.Errorf("StringToJson(%#q).Len() => %v, want %v", mapstr, cnt, - len(jsontests)); - } - for k,v := range values { - if v1 := mapv.Get(k); !Equal(v1, v) { - t.Errorf("MapTest: Walk(%#q) => %v, want %v", k, v1, v); - } - } -} diff --git a/src/lib/json/parse.go b/src/lib/json/parse.go deleted file mode 100644 index e33b9dbc1..000000000 --- a/src/lib/json/parse.go +++ /dev/null @@ -1,419 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// JSON (JavaScript Object Notation) parser. -// See http://www.json.org/ - -// The json package implements a simple parser and -// representation for JSON (JavaScript Object Notation), -// as defined at http://www.json.org/. -package json - -import ( - "fmt"; - "io"; - "math"; - "strconv"; - "strings"; - "utf8"; -) - -// Strings -// -// Double quoted with escapes: \" \\ \/ \b \f \n \r \t \uXXXX. -// No literal control characters, supposedly. -// Have also seen \' and embedded newlines. - -func _UnHex(p string, r, l int) (v int, ok bool) { - v = 0; - for i := r; i < l; i++ { - if i >= len(p) { - return 0, false - } - v *= 16; - switch { - case '0' <= p[i] && p[i] <= '9': - v += int(p[i] - '0'); - case 'a' <= p[i] && p[i] <= 'f': - v += int(p[i] - 'a' + 10); - case 'A' <= p[i] && p[i] <= 'F': - v += int(p[i] - 'A' + 10); - default: - return 0, false; - } - } - return v, true; -} - -// Unquote unquotes the JSON-quoted string s, -// returning a raw string t. If s is not a valid -// JSON-quoted string, Unquote returns with ok set to false. -func Unquote(s string) (t string, ok bool) { - if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' { - return - } - b := make([]byte, len(s)); - w := 0; - for r := 1; r < len(s)-1; { - switch { - case s[r] == '\\': - r++; - if r >= len(s)-1 { - return - } - switch s[r] { - default: - return; - case '"', '\\', '/', '\'': - b[w] = s[r]; - r++; - w++; - case 'b': - b[w] = '\b'; - r++; - w++; - case 'f': - b[w] = '\f'; - r++; - w++; - case 'n': - b[w] = '\n'; - r++; - w++; - case 'r': - b[w] = '\r'; - r++; - w++; - case 't': - b[w] = '\t'; - r++; - w++; - case 'u': - r++; - rune, ok := _UnHex(s, r, 4); - if !ok { - return - } - r += 4; - w += utf8.EncodeRune(rune, b[w:len(b)]); - } - // Control characters are invalid, but we've seen raw \n. - case s[r] < ' ' && s[r] != '\n': - if s[r] == '\n' { - b[w] = '\n'; - r++; - w++; - break; - } - return; - // ASCII - case s[r] < utf8.RuneSelf: - b[w] = s[r]; - r++; - w++; - // Coerce to well-formed UTF-8. - default: - rune, size := utf8.DecodeRuneInString(s[r:len(s)]); - r += size; - w += utf8.EncodeRune(rune, b[w:len(b)]); - } - } - return string(b[0:w]), true -} - -// Quote quotes the raw string s using JSON syntax, -// so that Unquote(Quote(s)) = s, true. -func Quote(s string) string { - chr := make([]byte, utf8.UTFMax); - chr0 := chr[0:1]; - b := new(io.ByteBuffer); - chr[0] = '"'; - b.Write(chr0); - for i := 0; i < len(s); i++ { - switch { - case s[i]=='"' || s[i]=='\\': - chr[0] = '\\'; - chr[1] = s[i]; - b.Write(chr[0:2]); - - case s[i] == '\b': - chr[0] = '\\'; - chr[1] = 'b'; - b.Write(chr[0:2]); - - case s[i] == '\f': - chr[0] = '\\'; - chr[1] = 'f'; - b.Write(chr[0:2]); - - case s[i] == '\n': - chr[0] = '\\'; - chr[1] = 'n'; - b.Write(chr[0:2]); - - case s[i] == '\r': - chr[0] = '\\'; - chr[1] = 'r'; - b.Write(chr[0:2]); - - case s[i] == '\t': - chr[0] = '\\'; - chr[1] = 't'; - b.Write(chr[0:2]); - - case 0x20 <= s[i] && s[i] < utf8.RuneSelf: - chr[0] = s[i]; - b.Write(chr0); - } - } - chr[0] = '"'; - b.Write(chr0); - return string(b.Data()); -} - - -// _Lexer - -type _Lexer struct { - s string; - i int; - kind int; - token string; -} - -func punct(c byte) bool { - return c=='"' || c=='[' || c==']' || c==':' || c=='{' || c=='}' || c==',' -} - -func white(c byte) bool { - return c==' ' || c=='\t' || c=='\n' || c=='\v' -} - -func skipwhite(p string, i int) int { - for i < len(p) && white(p[i]) { - i++ - } - return i -} - -func skiptoken(p string, i int) int { - for i < len(p) && !punct(p[i]) && !white(p[i]) { - i++ - } - return i -} - -func skipstring(p string, i int) int { - for i++; i < len(p) && p[i] != '"'; i++ { - if p[i] == '\\' { - i++ - } - } - if i >= len(p) { - return i - } - return i+1 -} - -func (t *_Lexer) Next() { - i, s := t.i, t.s; - i = skipwhite(s, i); - if i >= len(s) { - t.kind = 0; - t.token = ""; - t.i = len(s); - return; - } - - c := s[i]; - switch { - case c == '-' || '0' <= c && c <= '9': - j := skiptoken(s, i); - t.kind = '1'; - t.token = s[i:j]; - i = j; - - case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z': - j := skiptoken(s, i); - t.kind = 'a'; - t.token = s[i:j]; - i = j; - - case c == '"': - j := skipstring(s, i); - t.kind = '"'; - t.token = s[i:j]; - i = j; - - case c == '[', c == ']', c == ':', c == '{', c == '}', c == ',': - t.kind = int(c); - t.token = s[i:i+1]; - i++; - - default: - t.kind = '?'; - t.token = s[i:i+1]; - } - - t.i = i; -} - - -// Parser -// -// Implements parsing but not the actions. Those are -// carried out by the implementation of the Builder interface. -// A Builder represents the object being created. -// Calling a method like Int64(i) sets that object to i. -// Calling a method like Elem(i) or Key(s) creates a -// new builder for a subpiece of the object (logically, -// an array element or a map key). -// -// There are two Builders, in other files. -// The JsonBuilder builds a generic Json structure -// in which maps are maps. -// The StructBuilder copies data into a possibly -// nested data structure, using the "map keys" -// as struct field names. - -type _Value interface {} - -// BUG(rsc): The json Builder interface needs to be -// reconciled with the xml Builder interface. - -// A Builder is an interface implemented by clients and passed -// to the JSON parser. It gives clients full control over the -// eventual representation returned by the parser. -type Builder interface { - // Set value - Int64(i int64); - Uint64(i uint64); - Float64(f float64); - String(s string); - Bool(b bool); - Null(); - Array(); - Map(); - - // Create sub-Builders - Elem(i int) Builder; - Key(s string) Builder; -} - -func parse(lex *_Lexer, build Builder) bool { - ok := false; -Switch: - switch lex.kind { - case 0: - break; - case '1': - // If the number is exactly an integer, use that. - if i, err := strconv.Atoi64(lex.token); err == nil { - build.Int64(i); - ok = true; - } - else if i, err := strconv.Atoui64(lex.token); err == nil { - build.Uint64(i); - ok = true; - } - // Fall back to floating point. - else if f, err := strconv.Atof64(lex.token); err == nil { - build.Float64(f); - ok = true; - } - - case 'a': - switch lex.token { - case "true": - build.Bool(true); - ok = true; - case "false": - build.Bool(false); - ok = true; - case "null": - build.Null(); - ok = true; - } - - case '"': - if str, ok1 := Unquote(lex.token); ok1 { - build.String(str); - ok = true; - } - - case '[': - // array - build.Array(); - lex.Next(); - n := 0; - for lex.kind != ']' { - if n > 0 { - if lex.kind != ',' { - break Switch; - } - lex.Next(); - } - if !parse(lex, build.Elem(n)) { - break Switch; - } - n++; - } - ok = true; - - case '{': - // map - lex.Next(); - build.Map(); - n := 0; - for lex.kind != '}' { - if n > 0 { - if lex.kind != ',' { - break Switch; - } - lex.Next(); - } - if lex.kind != '"' { - break Switch; - } - key, ok := Unquote(lex.token); - if !ok { - break Switch; - } - lex.Next(); - if lex.kind != ':' { - break Switch; - } - lex.Next(); - if !parse(lex, build.Key(key)) { - break Switch; - } - n++; - } - ok = true; - } - - if ok { - lex.Next(); - } - return ok; -} - -// Parse parses the JSON syntax string s and makes calls to -// the builder to construct a parsed representation. -// On success, it returns with ok set to true. -// On error, it returns with ok set to false, errindx set -// to the byte index in s where a syntax error occurred, -// and errtok set to the offending token. -func Parse(s string, builder Builder) (ok bool, errindx int, errtok string) { - lex := new(_Lexer); - lex.s = s; - lex.Next(); - if parse(lex, builder) { - if lex.kind == 0 { // EOF - return true, 0, "" - } - } - return false, lex.i, lex.token -} - diff --git a/src/lib/json/struct.go b/src/lib/json/struct.go deleted file mode 100644 index ac2689557..000000000 --- a/src/lib/json/struct.go +++ /dev/null @@ -1,269 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Marshalling and unmarshalling of -// JSON data into Go structs using reflection. - -package json - -import ( - "json"; - "reflect"; -) - -type _StructBuilder struct { - val reflect.Value -} - -var nobuilder *_StructBuilder - -func setfloat(v reflect.Value, f float64) { - switch v.Kind() { - case reflect.FloatKind: - v.(reflect.FloatValue).Set(float(f)); - case reflect.Float32Kind: - v.(reflect.Float32Value).Set(float32(f)); - case reflect.Float64Kind: - v.(reflect.Float64Value).Set(float64(f)); - } -} - -func setint(v reflect.Value, i int64) { - switch v.Kind() { - case reflect.IntKind: - v.(reflect.IntValue).Set(int(i)); - case reflect.Int8Kind: - v.(reflect.Int8Value).Set(int8(i)); - case reflect.Int16Kind: - v.(reflect.Int16Value).Set(int16(i)); - case reflect.Int32Kind: - v.(reflect.Int32Value).Set(int32(i)); - case reflect.Int64Kind: - v.(reflect.Int64Value).Set(int64(i)); - case reflect.UintKind: - v.(reflect.UintValue).Set(uint(i)); - case reflect.Uint8Kind: - v.(reflect.Uint8Value).Set(uint8(i)); - case reflect.Uint16Kind: - v.(reflect.Uint16Value).Set(uint16(i)); - case reflect.Uint32Kind: - v.(reflect.Uint32Value).Set(uint32(i)); - case reflect.Uint64Kind: - v.(reflect.Uint64Value).Set(uint64(i)); - } -} - -func (b *_StructBuilder) Int64(i int64) { - if b == nil { - return - } - v := b.val; - switch v.Kind() { - case reflect.FloatKind, reflect.Float32Kind, reflect.Float64Kind: - setfloat(v, float64(i)); - default: - setint(v, i); - } -} - -func (b *_StructBuilder) Uint64(i uint64) { - if b == nil { - return - } - v := b.val; - switch v.Kind() { - case reflect.FloatKind, reflect.Float32Kind, reflect.Float64Kind: - setfloat(v, float64(i)); - default: - setint(v, int64(i)); - } -} - -func (b *_StructBuilder) Float64(f float64) { - if b == nil { - return - } - v := b.val; - switch v.Kind() { - case reflect.FloatKind, reflect.Float32Kind, reflect.Float64Kind: - setfloat(v, f); - default: - setint(v, int64(f)); - } -} - -func (b *_StructBuilder) Null() { -} - -func (b *_StructBuilder) String(s string) { - if b == nil { - return - } - if v := b.val; v.Kind() == reflect.StringKind { - v.(reflect.StringValue).Set(s); - } -} - -func (b *_StructBuilder) Bool(tf bool) { - if b == nil { - return - } - if v := b.val; v.Kind() == reflect.BoolKind { - v.(reflect.BoolValue).Set(tf); - } -} - -func (b *_StructBuilder) Array() { - if b == nil { - return - } - if v := b.val; v.Kind() == reflect.PtrKind { - pv := v.(reflect.PtrValue); - psubtype := pv.Type().(reflect.PtrType).Sub(); - if pv.Get() == nil && psubtype.Kind() == reflect.ArrayKind { - av := reflect.NewSliceValue(psubtype.(reflect.ArrayType), 0, 8); - pv.SetSub(av); - } - } -} - -func (b *_StructBuilder) Elem(i int) Builder { - if b == nil || i < 0 { - return nobuilder - } - v := b.val; - if v.Kind() == reflect.PtrKind { - // If we have a pointer to an array, allocate or grow - // the array as necessary. Then set v to the array itself. - pv := v.(reflect.PtrValue); - psub := pv.Sub(); - if psub.Kind() == reflect.ArrayKind { - av := psub.(reflect.ArrayValue); - if i > av.Cap() { - n := av.Cap(); - if n < 8 { - n = 8 - } - for n <= i { - n *= 2 - } - av1 := reflect.NewSliceValue(av.Type().(reflect.ArrayType), av.Len(), n); - av1.CopyFrom(av, av.Len()); - pv.SetSub(av1); - av = av1; - } - } - v = psub; - } - if v.Kind() == reflect.ArrayKind { - // Array was grown above, or is fixed size. - av := v.(reflect.ArrayValue); - if av.Len() <= i && i < av.Cap() { - av.SetLen(i+1); - } - if i < av.Len() { - return &_StructBuilder{ av.Elem(i) } - } - } - return nobuilder -} - -func (b *_StructBuilder) Map() { - if b == nil { - return - } - if v := b.val; v.Kind() == reflect.PtrKind { - pv := v.(reflect.PtrValue); - if pv.Get() == nil { - pv.SetSub(reflect.NewZeroValue(pv.Type().(reflect.PtrType).Sub())) - } - } -} - -func (b *_StructBuilder) Key(k string) Builder { - if b == nil { - return nobuilder - } - v := b.val; - if v.Kind() == reflect.PtrKind { - v = v.(reflect.PtrValue).Sub(); - } - if v.Kind() == reflect.StructKind { - sv := v.(reflect.StructValue); - t := v.Type().(reflect.StructType); - for i := 0; i < t.Len(); i++ { - name, typ, tag, off := t.Field(i); - if k == name { - return &_StructBuilder{ sv.Field(i) } - } - } - } - return nobuilder -} - -// Unmarshal parses the JSON syntax string s and fills in -// an arbitrary struct or array pointed at by val. -// It uses the reflection library to assign to fields -// and arrays embedded in val. Well-formed data that does not fit -// into the struct is discarded. -// -// For example, given the following definitions: -// -// type Email struct { -// where string; -// addr string; -// } -// -// type Result struct { -// name string; -// phone string; -// emails []Email -// } -// -// var r = Result{ "name", "phone", nil } -// -// unmarshalling the JSON syntax string -// -// { -// "email": [ -// { -// "where": "home", -// "addr": "gre@example.com" -// }, -// { -// "where": "work", -// "addr": "gre@work.com" -// } -// ], -// "name": "Grace R. Emlin", -// "address": "123 Main Street" -// } -// -// via Unmarshal(s, &r) is equivalent to assigning -// -// r = Result{ -// "Grace R. Emlin", // name -// "phone", // no phone given -// []Email{ -// Email{ "home", "gre@example.com" }, -// Email{ "work", "gre@work.com" } -// } -// } -// -// Note that the field r.phone has not been modified and -// that the JSON field "address" was discarded. -// -// On success, Unmarshal returns with ok set to true. -// On a syntax error, it returns with ok set to false and errtok -// set to the offending token. -func Unmarshal(s string, val interface{}) (ok bool, errtok string) { - var errindx int; - var val1 interface{}; - b := &_StructBuilder{ reflect.NewValue(val) }; - ok, errindx, errtok = Parse(s, b); - if !ok { - return false, errtok - } - return true, "" -} diff --git a/src/lib/json/struct_test.go b/src/lib/json/struct_test.go deleted file mode 100644 index 88d9e9ec4..000000000 --- a/src/lib/json/struct_test.go +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2009 The Go Authors. 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 ( - "json"; - "testing"; -) - -type _MyStruct struct { - t bool; - f bool; - s string; - i8 int8; - i16 int16; - i32 int32; - i64 int64; - u8 uint8; - u16 uint16; - u32 uint32; - u64 uint64; - i int; - u uint; - fl float; - fl32 float32; - fl64 float64; - a *[]string; // TODO(rsc): Should be able to use []string. - my *_MyStruct; -}; - -const _Encoded = - `{"t":true,"f":false,"s":"abc","i8":1,"i16":2,"i32":3,"i64":4,` - ` "u8":5,"u16":6,"u32":7,"u64":8,` - ` "i":-9,"u":10,"bogusfield":"should be ignored",` - ` "fl":11.5,"fl32":12.25,"fl64":13.75,` - ` "a":["x","y","z"],"my":{"s":"subguy"}}`; - - -func _Check(t *testing.T, ok bool, name string, v interface{}) { - if !ok { - t.Errorf("%s = %v (BAD)", name, v); - } else { - t.Logf("%s = %v (good)", name, v); - } -} - -func TestUnmarshal(t *testing.T) { - var m _MyStruct; - m.f = true; - ok, errtok := Unmarshal(_Encoded, &m); - if !ok { - t.Fatalf("Unmarshal failed near %s", errtok); - } - _Check(t, m.t==true, "t", m.t); - _Check(t, m.f==false, "f", m.f); - _Check(t, m.s=="abc", "s", m.s); - _Check(t, m.i8==1, "i8", m.i8); - _Check(t, m.i16==2, "i16", m.i16); - _Check(t, m.i32==3, "i32", m.i32); - _Check(t, m.i64==4, "i64", m.i64); - _Check(t, m.u8==5, "u8", m.u8); - _Check(t, m.u16==6, "u16", m.u16); - _Check(t, m.u32==7, "u32", m.u32); - _Check(t, m.u64==8, "u64", m.u64); - _Check(t, m.i==-9, "i", m.i); - _Check(t, m.u==10, "u", m.u); - _Check(t, m.fl==11.5, "fl", m.fl); - _Check(t, m.fl32==12.25, "fl32", m.fl32); - _Check(t, m.fl64==13.75, "fl64", m.fl64); - _Check(t, m.a!=nil, "a", m.a); - if m.a != nil { - _Check(t, m.a[0]=="x", "a[0]", m.a[0]); - _Check(t, m.a[1]=="y", "a[1]", m.a[1]); - _Check(t, m.a[2]=="z", "a[2]", m.a[2]); - } - _Check(t, m.my!=nil, "my", m.my); - if m.my != nil { - _Check(t, m.my.s=="subguy", "my.s", m.my.s); - } -} diff --git a/src/lib/log/Makefile b/src/lib/log/Makefile deleted file mode 100644 index 4b1c4b5a2..000000000 --- a/src/lib/log/Makefile +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m >Makefile - -D= - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - log.$O\ - - -phases: a1 -_obj$D/log.a: phases - -a1: $(O1) - $(AR) grc _obj$D/log.a log.$O - rm -f $(O1) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/log.a - -$(O1): newpkg -$(O2): a1 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/log.a - -packages: _obj$D/log.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/log.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/log.a diff --git a/src/lib/log/log.go b/src/lib/log/log.go deleted file mode 100644 index 8fcd73190..000000000 --- a/src/lib/log/log.go +++ /dev/null @@ -1,195 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Rudimentary logging package. Defines a type, Logger, with simple -// methods for formatting output to one or two destinations. Also has -// predefined Loggers accessible through helper functions Stdout[f], -// Stderr[f], Exit[f], and Crash[f], which are easier to use than creating -// a Logger manually. -// Exit exits when written to. -// Crash causes a crash when written to. -package log - -import ( - "fmt"; - "io"; - "runtime"; - "os"; - "time"; -) - -// These flags define the properties of the Logger and the output they produce. -const ( - // Flags - Lok = iota; - Lexit; // terminate execution when written - Lcrash; // crash (panic) when written - // Bits or'ed together to control what's printed. There is no control over the - // order they appear (the order listed here) or the format they present (as - // described in the comments). A colon appears after these items: - // 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 - lAllBits = Ldate | Ltime | Lmicroseconds | Llongfile | Lshortfile; -) - -// Logger represents an active logging object. -type Logger struct { - out0 io.Writer; // first destination for output - out1 io.Writer; // second destination for output; may be nil - prefix string; // prefix to write at beginning of each line - flag int; // properties -} - -// New creates a new Logger. The out0 and out1 variables set the -// destinations to which log data will be written; out1 may be nil. -// The prefix appears at the beginning of each generated log line. -// The flag argument defines the logging properties. -func New(out0, out1 io.Writer, prefix string, flag int) *Logger { - return &Logger{out0, out1, prefix, flag} -} - -var ( - stdout = New(os.Stdout, nil, "", Lok|Ldate|Ltime); - stderr = New(os.Stderr, nil, "", Lok|Ldate|Ltime); - exit = New(os.Stderr, nil, "", Lexit|Ldate|Ltime); - crash = New(os.Stderr, nil, "", Lcrash|Ldate|Ltime); -) - -var shortnames = make(map[string] string) // cache of short names to avoid allocation. - -// Cheap integer to fixed-width decimal ASCII. Use a negative width to avoid zero-padding -func itoa(i int, wid int) string { - var u uint = uint(i); - if u == 0 && wid <= 1 { - return "0" - } - - // 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'; - } - - return string(b[bp:len(b)]) -} - -func (l *Logger) formatHeader(ns int64, calldepth int) string { - h := l.prefix; - if l.flag & (Ldate | Ltime | Lmicroseconds) != 0 { - t := time.SecondsToLocalTime(ns/1e9); - if l.flag & (Ldate) != 0 { - h += itoa(int(t.Year), 4) + "/" + itoa(t.Month, 2) + itoa(t.Day, 2) + " " - } - if l.flag & (Ltime | Lmicroseconds) != 0 { - h += itoa(t.Hour, 2) + ":" + itoa(t.Minute, 2) + ":" + itoa(t.Second, 2); - if l.flag & Lmicroseconds != 0 { - h += "." + itoa(int(ns % 1e9)/1e3, 6); - } - h += " "; - } - } - if l.flag & (Lshortfile | Llongfile) != 0 { - pc, file, line, ok := runtime.Caller(calldepth); - if ok { - if l.flag & Lshortfile != 0 { - short, ok := shortnames[file]; - if !ok { - short = file; - for i := len(file) - 1; i > 0; i-- { - if file[i] == '/' { - short = file[i+1:len(file)]; - break; - } - } - shortnames[file] = short; - } - file = short; - } - } else { - file = "???"; - line = 0; - } - h += file + ":" + itoa(line, -1) + ": "; - } - return h; -} - -// Output writes the output for a logging event. The string s contains the text to print after -// the time stamp; calldepth is used to recover the PC. It is provided for generality, although -// at the moment on all pre-defined paths it will be 2. -func (l *Logger) Output(calldepth int, s string) { - now := time.Nanoseconds(); // get this early. - newline := "\n"; - if len(s) > 0 && s[len(s)-1] == '\n' { - newline = "" - } - s = l.formatHeader(now, calldepth+1) + s + newline; - io.WriteString(l.out0, s); - if l.out1 != nil { - io.WriteString(l.out1, s); - } - switch l.flag & ^lAllBits { - case Lcrash: - panic("log: fatal error"); - case Lexit: - os.Exit(1); - } -} - -// Logf is analogous to Printf() for a Logger. -func (l *Logger) Logf(format string, v ...) { - l.Output(2, fmt.Sprintf(format, v)) -} - -// Log is analogouts to Print() for a Logger. -func (l *Logger) Log(v ...) { - l.Output(2, fmt.Sprintln(v)) -} - -// Stdout is a helper function for easy logging to stdout. It is analogous to Print(). -func Stdout(v ...) { - stdout.Output(2, fmt.Sprint(v)) -} - -// Stderr is a helper function for easy logging to stderr. It is analogous to Fprint(os.Stderr). -func Stderr(v ...) { - stderr.Output(2, fmt.Sprintln(v)) -} - -// Stdoutf is a helper functions for easy formatted logging to stdout. It is analogous to Printf(). -func Stdoutf(format string, v ...) { - stdout.Output(2, fmt.Sprintf(format, v)) -} - -// Stderrf is a helper function for easy formatted logging to stderr. It is analogous to Fprintf(os.Stderr). -func Stderrf(format string, v ...) { - stderr.Output(2, fmt.Sprintf(format, v)) -} - -// Exit is equivalent to Stderr() followed by a call to os.Exit(1). -func Exit(v ...) { - exit.Output(2, fmt.Sprintln(v)) -} - -// Exitf is equivalent to Stderrf() followed by a call to os.Exit(1). -func Exitf(format string, v ...) { - exit.Output(2, fmt.Sprintf(format, v)) -} - -// Crash is equivalent to Stderrf() followed by a call to panic(). -func Crash(v ...) { - crash.Output(2, fmt.Sprintln(v)) -} - -// Crashf is equivalent to Stderrf() followed by a call to panic(). -func Crashf(format string, v ...) { - crash.Output(2, fmt.Sprintf(format, v)) -} diff --git a/src/lib/log/log_test.go b/src/lib/log/log_test.go deleted file mode 100644 index 0cfb2e36f..000000000 --- a/src/lib/log/log_test.go +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2009 The Go Authors. 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 ( - "bufio"; - "log"; - "os"; - "regexp"; - "testing"; -) - -const ( - Rdate = `[0-9][0-9][0-9][0-9]/[0-9][0-9][0-9][0-9]`; - Rtime = `[0-9][0-9]:[0-9][0-9]:[0-9][0-9]`; - Rmicroseconds = `\.[0-9][0-9][0-9][0-9][0-9][0-9]`; - Rline = `[0-9]+:`; - 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: - tester{ 0, "", "" }, - tester{ 0, "XXX", "XXX" }, - tester{ Lok|Ldate, "", Rdate+" " }, - tester{ Lok|Ltime, "", Rtime+" " }, - tester{ Lok|Ltime|Lmicroseconds, "", Rtime+Rmicroseconds+" " }, - tester{ Lok|Lmicroseconds, "", Rtime+Rmicroseconds+" " }, // microsec implies time - tester{ Lok|Llongfile, "", Rlongfile+" " }, - tester{ Lok|Lshortfile, "", Rshortfile+" " }, - tester{ Lok|Llongfile|Lshortfile, "", Rshortfile+" " }, // shortfile overrides longfile - // everything at once: - tester{ Lok|Ldate|Ltime|Lmicroseconds|Llongfile, "XXX", "XXX"+Rdate+" "+Rtime+Rmicroseconds+" "+Rlongfile+" " }, - tester{ Lok|Ldate|Ltime|Lmicroseconds|Lshortfile, "XXX", "XXX"+Rdate+" "+Rtime+Rmicroseconds+" "+Rshortfile+" " }, -} - -// Test using Log("hello", 23, "world") or using Logf("hello %d world", 23) -func testLog(t *testing.T, flag int, prefix string, pattern string, useLogf bool) { - r, w, err1 := os.Pipe(); - if err1 != nil { - t.Fatal("pipe", err1); - } - defer r.Close(); - defer w.Close(); - buf := bufio.NewReader(r); - l := New(w, nil, prefix, flag); - if useLogf { - l.Logf("hello %d world", 23); - } else { - l.Log("hello", 23, "world"); - } - line, err3 := buf.ReadLineString('\n', false); - if err3 != nil { - t.Fatal("log error", err3); - } - pattern = "^"+pattern+"hello 23 world$"; - matched, err4 := regexp.Match(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); - } -} - -func TestAllLog(t *testing.T) { - for i, testcase := range(tests) { - testLog(t, testcase.flag, testcase.prefix, testcase.pattern, false); - testLog(t, testcase.flag, testcase.prefix, testcase.pattern, true); - } -} diff --git a/src/lib/malloc/Makefile b/src/lib/malloc/Makefile deleted file mode 100644 index 61894f71f..000000000 --- a/src/lib/malloc/Makefile +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m >Makefile - -D= - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - malloc.$O\ - - -phases: a1 -_obj$D/malloc.a: phases - -a1: $(O1) - $(AR) grc _obj$D/malloc.a malloc.$O - rm -f $(O1) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/malloc.a - -$(O1): newpkg -$(O2): a1 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/malloc.a - -packages: _obj$D/malloc.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/malloc.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/malloc.a diff --git a/src/lib/malloc/malloc.go b/src/lib/malloc/malloc.go deleted file mode 100644 index fec53f08f..000000000 --- a/src/lib/malloc/malloc.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Go declarations for malloc. -// The actual functions are written in C -// and part of the runtime library. - -package malloc - -type Stats struct { - Alloc uint64; - Sys uint64; - Stacks uint64; - InusePages uint64; - NextGC uint64; - EnableGC bool; -} - -func Alloc(uintptr) *byte -func Free(*byte) -func GetStats() *Stats -func Lookup(*byte) (*byte, uintptr) -func GC() diff --git a/src/lib/math/Makefile b/src/lib/math/Makefile deleted file mode 100644 index 058049072..000000000 --- a/src/lib/math/Makefile +++ /dev/null @@ -1,98 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m >Makefile - -D= - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - const.$O\ - fabs.$O\ - hypot.$O\ - pow10.$O\ - runtime.$O\ - -O2=\ - atan.$O\ - exp.$O\ - floor.$O\ - fmod.$O\ - log.$O\ - sin.$O\ - sqrt.$O\ - tan.$O\ - -O3=\ - asin.$O\ - atan2.$O\ - pow.$O\ - sinh.$O\ - -O4=\ - tanh.$O\ - - -phases: a1 a2 a3 a4 -_obj$D/math.a: phases - -a1: $(O1) - $(AR) grc _obj$D/math.a const.$O fabs.$O hypot.$O pow10.$O runtime.$O - rm -f $(O1) - -a2: $(O2) - $(AR) grc _obj$D/math.a atan.$O exp.$O floor.$O fmod.$O log.$O sin.$O sqrt.$O tan.$O - rm -f $(O2) - -a3: $(O3) - $(AR) grc _obj$D/math.a asin.$O atan2.$O pow.$O sinh.$O - rm -f $(O3) - -a4: $(O4) - $(AR) grc _obj$D/math.a tanh.$O - rm -f $(O4) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/math.a - -$(O1): newpkg -$(O2): a1 -$(O3): a2 -$(O4): a3 -$(O5): a4 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/math.a - -packages: _obj$D/math.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/math.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/math.a diff --git a/src/lib/math/all_test.go b/src/lib/math/all_test.go deleted file mode 100644 index c5d5c01c4..000000000 --- a/src/lib/math/all_test.go +++ /dev/null @@ -1,278 +0,0 @@ -// Copyright 2009 The Go Authors. 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 ( - "math"; - "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, -} -var asin = []float64 { - 5.2117697218417440e-01, - 8.8495619865825236e-01, - -2.7691544662819413e-02, - -5.2482360935268932e-01, - 1.3002662421166553e+00, - 2.9698415875871901e-01, - 5.5025938468083364e-01, - 2.7629597861677200e-01, - 1.8355989225745148e-01, - -1.0523547536021498e+00, -} -var atan = []float64 { - 1.3725902621296217e+00, - 1.4422906096452980e+00, - -2.7011324359471755e-01, - -1.3738077684543379e+00, - 1.4673921193587666e+00, - 1.2415173565870167e+00, - 1.3818396865615167e+00, - 1.2194305844639670e+00, - 1.0696031952318783e+00, - -1.4561721938838085e+00, -} -var exp = []float64 { - 1.4533071302642137e+02, - 2.2958822575694450e+03, - 7.5814542574851666e-01, - 6.6668778421791010e-03, - 1.5310493273896035e+04, - 1.8659907517999329e+01, - 1.8662167355098713e+02, - 1.5301332413189379e+01, - 6.2047063430646876e+00, - 1.6894712385826522e-04, -} -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 log = []float64 { - 1.6052314626930630e+00, - 2.0462560018708768e+00, - -1.2841708730962657e+00, - 1.6115563905281544e+00, - 2.2655365644872018e+00, - 1.0737652208918380e+00, - 1.6542360106073545e+00, - 1.0035467127723465e+00, - 6.0174879014578053e-01, - 2.1617038728473527e+00, -} -var pow = []float64 { - 9.5282232631648415e+04, - 5.4811599352999900e+07, - 5.2859121715894400e-01, - 9.7587991957286472e-06, - 4.3280643293460450e+09, - 8.4406761805034551e+02, - 1.6946633276191194e+05, - 5.3449040147551940e+02, - 6.6881821384514159e+01, - 2.0609869004248744e-09, -} -var sin = []float64 { - -9.6466616586009283e-01, - 9.9338225271646543e-01, - -2.7335587039794395e-01, - 9.5586257685042800e-01, - -2.0994210667799692e-01, - 2.1355787807998605e-01, - -8.6945689711673619e-01, - 4.0195666811555783e-01, - 9.6778633541688000e-01, - -6.7344058690503452e-01, -} -var sinh = []float64 { - 7.2661916084208533e+01, - 1.1479409110035194e+03, - -2.8043136512812520e-01, - -7.4994290911815868e+01, - 7.6552466042906761e+03, - 9.3031583421672010e+00, - 9.3308157558281088e+01, - 7.6179893137269143e+00, - 3.0217691805496156e+00, - -2.9595057572444951e+03, -} -var sqrt = []float64 { - 2.2313699659365484e+00, - 2.7818829009464263e+00, - 5.2619393496314792e-01, - 2.2384377628763938e+00, - 3.1042380236055380e+00, - 1.7106657298385224e+00, - 2.2867189227054791e+00, - 1.6516476350711160e+00, - 1.3510396336454586e+00, - 2.9471892997524950e+00, -} -var tan = []float64 { - -3.6613165650402277e+00, - 8.6490023264859754e+00, - -2.8417941955033615e-01, - 3.2532901859747287e+00, - 2.1472756403802937e-01, - -2.1860091071106700e-01, - -1.7600028178723679e+00, - -4.3898089147528178e-01, - -3.8438855602011305e+00, - 9.1098879337768517e-01, -} -var tanh = []float64 { - 9.9990531206936328e-01, - 9.9999962057085307e-01, - -2.7001505097318680e-01, - -9.9991110943061700e-01, - 9.9999999146798441e-01, - 9.9427249436125233e-01, - 9.9994257600983156e-01, - 9.9149409509772863e-01, - 9.4936501296239700e-01, - -9.9999994291374019e-01, -} - -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 close(a,b float64) bool { - return tolerance(a, b, 1e-14); -} -func veryclose(a,b float64) bool { - return tolerance(a, b, 4e-16); -} - -func TestAsin(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f := math.Asin(vf[i]/10); !veryclose(asin[i], f) { - t.Errorf("math.Asin(%g) = %g, want %g\n", vf[i]/10, f, asin[i]); - } - } -} - -func TestAtan(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f := math.Atan(vf[i]); !veryclose(atan[i], f) { - t.Errorf("math.Atan(%g) = %g, want %g\n", vf[i], f, atan[i]); - } - } -} - -func TestExp(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f := math.Exp(vf[i]); !veryclose(exp[i], f) { - t.Errorf("math.Exp(%g) = %g, want %g\n", vf[i], f, exp[i]); - } - } -} - -func TestFloor(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f := math.Floor(vf[i]); floor[i] != f { - t.Errorf("math.Floor(%g) = %g, want %g\n", vf[i], f, floor[i]); - } - } -} - -func TestLog(t *testing.T) { - for i := 0; i < len(vf); i++ { - a := math.Fabs(vf[i]); - if f := math.Log(a); log[i] != f { - t.Errorf("math.Log(%g) = %g, want %g\n", a, f, log[i]); - } - } - if f := math.Log(10); f != math.Ln10 { - t.Errorf("math.Log(%g) = %g, want %g\n", 10, f, math.Ln10); - } -} - -func TestPow(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f := math.Pow(10, vf[i]); !close(pow[i], f) { - t.Errorf("math.Pow(10, %.17g) = %.17g, want %.17g\n", vf[i], f, pow[i]); - } - } -} - -func TestSin(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f := math.Sin(vf[i]); !close(sin[i], f) { - t.Errorf("math.Sin(%g) = %g, want %g\n", vf[i], f, sin[i]); - } - } -} - -func TestSinh(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f := math.Sinh(vf[i]); !veryclose(sinh[i], f) { - t.Errorf("math.Sinh(%g) = %g, want %g\n", vf[i], f, sinh[i]); - } - } -} - -func TestSqrt(t *testing.T) { - for i := 0; i < len(vf); i++ { - a := math.Fabs(vf[i]); - if f := math.Sqrt(a); !veryclose(sqrt[i], f) { - t.Errorf("math.Sqrt(%g) = %g, want %g\n", a, f, floor[i]); - } - } -} - -func TestTan(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f := math.Tan(vf[i]); !close(tan[i], f) { - t.Errorf("math.Tan(%g) = %g, want %g\n", vf[i], f, tan[i]); - } - } -} - -func TestTanh(t *testing.T) { - for i := 0; i < len(vf); i++ { - if f := math.Tanh(vf[i]); !veryclose(tanh[i], f) { - t.Errorf("math.Tanh(%g) = %g, want %g\n", vf[i], f, tanh[i]); - } - } -} - -func TestHypot(t *testing.T) { - for i := 0; i < len(vf); i++ { - a := math.Fabs(tanh[i]*math.Sqrt(2)); - if f := math.Hypot(tanh[i], tanh[i]); !veryclose(a, f) { - t.Errorf("math.Hypot(%g, %g) = %g, want %g\n", tanh[i], tanh[i], f, a); - } - } -} diff --git a/src/lib/math/asin.go b/src/lib/math/asin.go deleted file mode 100644 index 23c9a1069..000000000 --- a/src/lib/math/asin.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package math - -import "math" - -/* - * asin(arg) and acos(arg) return the arcsin, arccos, - * respectively of their arguments. - * - * Arctan is called after appropriate range reduction. - */ - -// Asin returns the arc sine of x. -func Asin(x float64) float64 { - sign := false; - if x < 0 { - x = -x; - sign = true; - } - if x > 1 { - return NaN(); - } - - temp := Sqrt(1 - x*x); - if x > 0.7 { - temp = Pi/2 - Atan(temp/x); - } else { - temp = Atan(x/temp); - } - - if sign { - temp = -temp; - } - return temp; -} - -// Acos returns the arc cosine of x. -func Acos(x float64) float64 { - if x > 1 || x < -1 { - return NaN(); - } - return Pi/2 - Asin(x); -} diff --git a/src/lib/math/atan.go b/src/lib/math/atan.go deleted file mode 100644 index 4b18f76aa..000000000 --- a/src/lib/math/atan.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package math - -import "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 makes its argument positive and - * calls the inner routine satan. - */ - -// Atan returns the arc tangent of x. -func Atan(x float64) float64 { - if x > 0 { - return satan(x); - } - return -satan(-x); -} diff --git a/src/lib/math/atan2.go b/src/lib/math/atan2.go deleted file mode 100644 index 72f2117b3..000000000 --- a/src/lib/math/atan2.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2009 The Go Authors. 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 "math" - -// Atan returns the arc tangent of y/x, using -// the signs of the two to determine the quadrant -// of the return value. -func Atan2(x, y float64) float64 { - // Determine the quadrant and call atan. - if x+y == x { - if x >= 0 { - return Pi/2; - } - return -Pi/2; - } - q := Atan(x/y); - if y < 0 { - if q <= 0 { - return q + Pi; - } - return q - Pi; - } - return q; -} diff --git a/src/lib/math/const.go b/src/lib/math/const.go deleted file mode 100644 index 259660fea..000000000 --- a/src/lib/math/const.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// The math package provides basic constants and mathematical functions. -package math - -// Mathematical constants. -// Reference: http://www.research.att.com/~njas/sequences/Axxxxxx -const ( - E = 2.71828182845904523536028747135266249775724709369995957496696763; // A001113 - Pi = 3.14159265358979323846264338327950288419716939937510582097494459; // A000796 - Phi = 1.61803398874989484820458683436563811772030917980576286213544862; // A001622 - - Sqrt2 = 1.41421356237309504880168872420969807856967187537694807317667974; // A002193 - SqrtE = 1.64872127070012814684865078781416357165377610071014801157507931; // A019774 - SqrtPi = 1.77245385090551602729816748334114518279754945612238712821380779; // A002161 - SqrtPhi = 1.27201964951406896425242246173749149171560804184009624861664038; // A139339 - - Ln2 = 0.693147180559945309417232121458176568075500134360255254120680009; // A002162 - Log2E = 1/Ln2; - Ln10 = 2.30258509299404568401799145468436420760110148862877297603332790; // A002392 - Log10E = 1/Ln10; -) - -// BUG(rsc): The manual should define the special cases for all of these functions. diff --git a/src/lib/math/exp.go b/src/lib/math/exp.go deleted file mode 100644 index a32c7e1d5..000000000 --- a/src/lib/math/exp.go +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2009 The Go Authors. 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 "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 -Inf or +Inf. -// Very small values underflow to 1. -func Exp(x float64) float64 { - const ( - Ln2Hi = 6.93147180369123816490e-01; - Ln2Lo = 1.90821492927058770002e-10; - Log2e = 1.44269504088896338700e+00; - - P1 = 1.66666666666666019037e-01; /* 0x3FC55555; 0x5555553E */ - P2 = -2.77777777770155933842e-03; /* 0xBF66C16C; 0x16BEBD93 */ - P3 = 6.61375632143793436117e-05; /* 0x3F11566A; 0xAF25DE2C */ - P4 = -1.65339022054652515390e-06; /* 0xBEBBBD41; 0xC5D26BF1 */ - P5 = 4.13813679705723846039e-08; /* 0x3E663769; 0x72BEA4D0 */ - - Overflow = 7.09782712893383973096e+02; - Underflow = -7.45133219101941108420e+02; - NearZero = 1.0/(1<<28); // 2^-28 - ) - - // special cases - switch { - case IsNaN(x) || IsInf(x, 1): - return x; - case IsInf(x, -1): - return 0; - case x > Overflow: - return Inf(1); - case x < Underflow: - return 0; - case -NearZero < x && x < NearZero: - return 1; - } - - // reduce; computed as r = hi - lo for extra precision. - var k int; - switch { - case x < 0: - k = int(Log2e*x - 0.5); - case x > 0: - k = int(Log2e*x + 0.5); - } - hi := x - float64(k)*Ln2Hi; - lo := float64(k)*Ln2Lo; - r := hi - lo; - - // compute - t := r * r; - c := r - t*(P1+t*(P2+t*(P3+t*(P4+t*P5)))); - y := 1 - ((lo - (r*c)/(2-c)) - hi); - // TODO(rsc): make sure Ldexp can handle boundary k - return Ldexp(y, k); -} diff --git a/src/lib/math/fabs.go b/src/lib/math/fabs.go deleted file mode 100644 index 9427c5726..000000000 --- a/src/lib/math/fabs.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package math - -// Fabs returns the absolute value of x. -func Fabs(x float64) float64 { - if x < 0 { - return -x; - } - return x; -} - diff --git a/src/lib/math/floor.go b/src/lib/math/floor.go deleted file mode 100644 index 48a1003f0..000000000 --- a/src/lib/math/floor.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package math - -import "math" - -// Floor returns the greatest integer value less than or equal to x. -func Floor(x float64) float64 { - if x < 0 { - d, fract := Modf(-x); - if fract != 0.0 { - d = d+1; - } - return -d; - } - d, fract := Modf(x); - return d; -} - -// Ceil returns the least integer value greater than or equal to x. -func Ceil(x float64) float64 { - return -Floor(-x); -} diff --git a/src/lib/math/fmod.go b/src/lib/math/fmod.go deleted file mode 100644 index 617f5408b..000000000 --- a/src/lib/math/fmod.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package math - -import "math" - -/* - * floating-point mod func without infinity or NaN checking - */ - -// Fmod returns the floating-point remainder of x/y. -func Fmod(x, y float64) float64 { - if y == 0 { - return x; - } - 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/lib/math/hypot.go b/src/lib/math/hypot.go deleted file mode 100644 index 411f74e4f..000000000 --- a/src/lib/math/hypot.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2009 The Go Authors. 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. -func Hypot(p, q float64) float64 { - 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/lib/math/log.go b/src/lib/math/log.go deleted file mode 100644 index b24175b63..000000000 --- a/src/lib/math/log.go +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2009 The Go Authors. 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 "math" - -// The original C code, the long comment, and the constants -// below are from FreeBSD's /usr/src/lib/msun/src/e_log.c -// and came with this notice. The go code is a simpler -// version of the original C. -// -// ==================================================== -// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. -// -// Developed at SunPro, a Sun Microsystems, Inc. business. -// Permission to use, copy, modify, and distribute this -// software is freely granted, provided that this notice -// is preserved. -// ==================================================== -// -// __ieee754_log(x) -// Return the logrithm of x -// -// Method : -// 1. Argument Reduction: find k and f such that -// x = 2^k * (1+f), -// where sqrt(2)/2 < 1+f < sqrt(2) . -// -// 2. Approximation of log(1+f). -// Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s) -// = 2s + 2/3 s**3 + 2/5 s**5 + ....., -// = 2s + s*R -// We use a special Reme algorithm on [0,0.1716] to generate -// a polynomial of degree 14 to approximate R The maximum error -// of this polynomial approximation is bounded by 2**-58.45. In -// other words, -// 2 4 6 8 10 12 14 -// R(z) ~ L1*s +L2*s +L3*s +L4*s +L5*s +L6*s +L7*s -// (the values of L1 to L7 are listed in the program) -// and -// | 2 14 | -58.45 -// | L1*s +...+L7*s - R(z) | <= 2 -// | | -// Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2. -// In order to guarantee error in log below 1ulp, we compute log -// by -// log(1+f) = f - s*(f - R) (if f is not too large) -// log(1+f) = f - (hfsq - s*(hfsq+R)). (better accuracy) -// -// 3. Finally, log(x) = k*Ln2 + log(1+f). -// = k*Ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*Ln2_lo))) -// Here Ln2 is split into two floating point number: -// Ln2_hi + Ln2_lo, -// where n*Ln2_hi is always exact for |n| < 2000. -// -// Special cases: -// log(x) is NaN with signal if x < 0 (including -INF) ; -// log(+INF) is +INF; log(0) is -INF with signal; -// log(NaN) is that NaN with no signal. -// -// Accuracy: -// according to an error analysis, the error is always less than -// 1 ulp (unit in the last place). -// -// Constants: -// The hexadecimal values are the intended ones for the following -// constants. The decimal values may be used, provided that the -// compiler will convert from decimal to binary accurately enough -// to produce the hexadecimal values shown. - -// Log returns the natural logarithm of x. -// -// Special cases are: -// Log(+Inf) = +Inf -// Log(0) = -Inf -// Log(x < 0) = NaN -// Log(NaN) = NaN -func Log(x float64) float64 { - const ( - Ln2Hi = 6.93147180369123816490e-01; /* 3fe62e42 fee00000 */ - Ln2Lo = 1.90821492927058770002e-10; /* 3dea39ef 35793c76 */ - L1 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ - L2 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ - L3 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ - L4 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ - L5 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ - L6 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ - L7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ - ) - - // special cases - switch { - case 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); -} - -// Log10 returns the decimal logarthm of x. -// The special cases are the same as for Log. -func Log10(x float64) float64 { - if x <= 0 { - return NaN(); - } - return Log(x) * (1/Ln10); -} - diff --git a/src/lib/math/pow.go b/src/lib/math/pow.go deleted file mode 100644 index 920d210b5..000000000 --- a/src/lib/math/pow.go +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2009 The Go Authors. 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 "math" - -// Pow returns x**y, the base-x exponential of y. -func Pow(x, y float64) float64 { - // TODO: x or y NaN, ±Inf, maybe ±0. - switch { - case y == 0: - return 1; - case y == 1: - return x; - case x == 0 && y > 0: - return 0; - case x == 0 && y < 0: - return Inf(1); - case y == 0.5: - return Sqrt(x); - case y == -0.5: - return 1 / Sqrt(x); - } - - 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 := float64(1); - 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/lib/math/pow10.go b/src/lib/math/pow10.go deleted file mode 100644 index fcdd6e0a1..000000000 --- a/src/lib/math/pow10.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package math - -/* - * 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 GO converts fp numbers better - * than multipication of lower powers of 10. - */ - -var pow10tab [70]float64; - -// Pow10 returns 10**x, the base-10 exponential of x. -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; iexp, -// with the absolute value of frac in the interval [½, 1). -func Frexp(f float64) (frac float64, exp int) - -// Inf returns positive infinity if sign >= 0, negative infinity if sign < 0. -func Inf(sign int32) (f float64) - -// 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) (is bool) - -// IsNaN returns whether f is an IEEE 754 ``not-a-number'' value. -func IsNaN(f float64) (is bool) - -// Ldexp is the inverse of Frexp. -// It returns frac × 2exp. -func Ldexp(frac float64, exp int) (f float64) - -// Modf returns integer and fractional floating-point numbers -// that sum to f. -// Integer and frac have the same sign as f. -func Modf(f float64) (integer float64, frac float64) - -// NaN returns an IEEE 754 ``not-a-number'' value. -func NaN() (f float64) diff --git a/src/lib/math/sin.go b/src/lib/math/sin.go deleted file mode 100644 index 9fc69606c..000000000 --- a/src/lib/math/sin.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2009 The Go Authors. 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 "math" - -func sinus(x float64, quad int) float64 { - // Coefficients are #3370 from Hart & Cheney (18.80D). - 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); - temp1, 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/lib/math/sinh.go b/src/lib/math/sinh.go deleted file mode 100644 index ef70989fb..000000000 --- a/src/lib/math/sinh.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package math - -import "math" - -/* - * Sinh(x) returns the hyperbolic sine of x - * - * 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/lib/math/sqrt.go b/src/lib/math/sqrt.go deleted file mode 100644 index 79384f648..000000000 --- a/src/lib/math/sqrt.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package math - -import "math" - -/* - * sqrt returns the square root of its floating - * point argument. Newton's method. - * - * calls frexp - */ - -// Sqrt returns the square root of x. -// -// Special cases are: -// Sqrt(+Inf) = +Inf -// Sqrt(0) = 0 -// Sqrt(x < 0) = NaN -func Sqrt(x float64) float64 { - if IsInf(x, 1) { - return x; - } - - if x <= 0 { - if x < 0 { - return NaN(); - } - return 0; - } - - y, exp := Frexp(x); - for y < 0.5 { - y = y*2; - exp = exp-1; - } - - if exp&1 != 0 { - y = y*2; - exp = exp-1; - } - temp := 0.5 * (1+y); - - for exp > 60 { - temp = temp * float64(1<<30); - exp = exp - 60; - } - for exp < -60 { - temp = temp / float64(1<<30); - exp = exp + 60; - } - if exp >= 0 { - exp = 1 << uint(exp/2); - temp = temp * float64(exp); - } else { - exp = 1 << uint(-exp/2); - temp = temp / float64(exp); - } - - for i:=0; i<=4; i++ { - temp = 0.5*(temp + x/temp); - } - return temp; -} diff --git a/src/lib/math/tan.go b/src/lib/math/tan.go deleted file mode 100644 index 2d4a044b8..000000000 --- a/src/lib/math/tan.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package math - -import "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) { - panic(NaN()); - } - temp = 1/temp; - } - if sign { - temp = -temp; - } - return temp; -} diff --git a/src/lib/math/tanh.go b/src/lib/math/tanh.go deleted file mode 100644 index 18d38ae8f..000000000 --- a/src/lib/math/tanh.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package math - -import "math" - -/* - * tanh(x) computes the hyperbolic tangent of its floating - * point argument. - * - * 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/lib/net/Makefile b/src/lib/net/Makefile deleted file mode 100644 index 61c872089..000000000 --- a/src/lib/net/Makefile +++ /dev/null @@ -1,96 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m dnsclient.go dnsconfig.go dnsmsg.go fd.go fd_${GOOS}.go ip.go net.go parse.go port.go >Makefile - -D= - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - dnsmsg.$O\ - parse.$O\ - -O2=\ - fd_$(GOOS).$O\ - ip.$O\ - port.$O\ - -O3=\ - dnsconfig.$O\ - fd.$O\ - -O4=\ - net.$O\ - -O5=\ - dnsclient.$O\ - - -phases: a1 a2 a3 a4 a5 -_obj$D/net.a: phases - -a1: $(O1) - $(AR) grc _obj$D/net.a dnsmsg.$O parse.$O - rm -f $(O1) - -a2: $(O2) - $(AR) grc _obj$D/net.a fd_$(GOOS).$O ip.$O port.$O - rm -f $(O2) - -a3: $(O3) - $(AR) grc _obj$D/net.a dnsconfig.$O fd.$O - rm -f $(O3) - -a4: $(O4) - $(AR) grc _obj$D/net.a net.$O - rm -f $(O4) - -a5: $(O5) - $(AR) grc _obj$D/net.a dnsclient.$O - rm -f $(O5) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/net.a - -$(O1): newpkg -$(O2): a1 -$(O3): a2 -$(O4): a3 -$(O5): a4 -$(O6): a5 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/net.a - -packages: _obj$D/net.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/net.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/net.a diff --git a/src/lib/net/dialgoogle_test.go b/src/lib/net/dialgoogle_test.go deleted file mode 100644 index 1e0c0aaf0..000000000 --- a/src/lib/net/dialgoogle_test.go +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package net - -import ( - "flag"; - "fmt"; - "io"; - "net"; - "os"; - "syscall"; - "testing"; -) - -// If an IPv6 tunnel is running (see go/stubl), 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 net.Conn, network, addr string) { - req := io.StringBytes("GET /intl/en/privacy.html HTTP/1.0\r\nHost: www.google.com\r\n\r\n"); - n, err := fd.Write(req); - - buf := make([]byte, 1000); - n, err = io.FullRead(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 := net.Dial(network, "", addr); - if err != nil { - t.Errorf("net.Dial(%q, %q, %q) = _, %v", network, "", addr, err); - return - } - fetchGoogle(t, fd, network, addr); - fd.Close() -} - -func doDialTCP(t *testing.T, network, addr string) { - fd, err := net.DialTCP(network, "", addr); - if err != nil { - t.Errorf("net.DialTCP(%q, %q, %q) = _, %v", network, "", addr, err); - } else { - fetchGoogle(t, fd, network, addr); - } - fd.Close() -} - -var googleaddrs = []string { - "74.125.19.99:80", - "www.google.com:80", - "74.125.19.99:http", - "www.google.com:http", - "074.125.019.099:0080", - "[::ffff:74.125.19.99]:80", - "[::ffff:4a7d:1363]:80", - "[0:0:0:0:0000:ffff:74.125.19.99]:80", - "[0:0:0:0:000000:ffff:74.125.19.99]:80", - "[0:0:0:0:0:ffff::74.125.19.99]:80", - "[2001:4860:0:2001::68]:80" // ipv6.google.com; removed if ipv6 flag not set -} - -func TestDialGoogle(t *testing.T) { - // If no ipv6 tunnel, don't try the last address. - if !*ipv6 { - googleaddrs[len(googleaddrs)-1] = "" - } - - for i := 0; i < len(googleaddrs); i++ { - addr := googleaddrs[i]; - if addr == "" { - continue - } - t.Logf("-- %s --", addr); - doDial(t, "tcp", addr); - doDialTCP(t, "tcp", addr); - if addr[0] != '[' { - doDial(t, "tcp4", addr); - doDialTCP(t, "tcp4", addr); - - if !preferIPv4 { - // make sure preferIPv4 flag works. - preferIPv4 = true; - syscall.SocketDisableIPv6 = true; - doDial(t, "tcp4", addr); - doDialTCP(t, "tcp4", addr); - syscall.SocketDisableIPv6 = false; - preferIPv4 = false; - } - } - doDial(t, "tcp6", addr); - doDialTCP(t, "tcp6", addr) - } -} diff --git a/src/lib/net/dnsclient.go b/src/lib/net/dnsclient.go deleted file mode 100644 index cfd67eabe..000000000 --- a/src/lib/net/dnsclient.go +++ /dev/null @@ -1,227 +0,0 @@ -// Copyright 2009 The Go 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. -// 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. -// More substantial error reporting. -// Remove use of fmt? - -package net - -import ( - "fmt"; - "io"; - "net"; - "once"; - "os"; - "strings"; -) - -// DNS errors returned by LookupHost. -type DNSError struct { - os.ErrorString -} -var ( - DNS_InternalError os.Error = &DNSError{"internal dns error"}; - DNS_MissingConfig os.Error = &DNSError{"no dns configuration"}; - DNS_No_Answer os.Error = &DNSError{"dns got no answer"}; - DNS_BadRequest os.Error = &DNSError{"malformed dns request"}; - DNS_BadReply os.Error = &DNSError{"malformed dns reply"}; - DNS_ServerFailure os.Error = &DNSError{"dns server failure"}; - DNS_NoServers os.Error = &DNSError{"no dns servers"}; - DNS_NameTooLong os.Error = &DNSError{"dns name too long"}; - DNS_RedirectLoop os.Error = &DNSError{"dns redirect loop"}; - DNS_NameNotFound os.Error = &DNSError{"dns name not found"}; -) - -// Send a request on the connection and hope for a reply. -// Up to cfg.attempts attempts. -func _Exchange(cfg *_DNS_Config, c Conn, name string) (m *_DNS_Msg, err os.Error) { - if len(name) >= 256 { - return nil, DNS_NameTooLong - } - out := new(_DNS_Msg); - out.id = 0x1234; - out.question = []_DNS_Question{ - _DNS_Question{ name, _DNS_TypeA, _DNS_ClassINET } - }; - out.recursion_desired = true; - msg, ok := out.Pack(); - if !ok { - return nil, DNS_InternalError - } - - for attempt := 0; attempt < cfg.attempts; attempt++ { - n, err := c.Write(msg); - if err != nil { - return nil, err - } - - c.SetReadTimeout(1e9); // nanoseconds - - buf := make([]byte, 2000); // More than enough. - n, err = c.Read(buf); - if err == os.EAGAIN { - continue; - } - if err != nil { - return nil, err; - } - buf = buf[0:n]; - in := new(_DNS_Msg); - if !in.Unpack(buf) || in.id != out.id { - continue - } - return in, nil - } - return nil, DNS_No_Answer -} - - -// Find answer for name in dns message. -// On return, if err == nil, addrs != nil. -// TODO(rsc): Maybe return []IP instead? -func answer(name string, dns *_DNS_Msg) (addrs []string, err os.Error) { - addrs = make([]string, 0, len(dns.answer)); - - if dns.rcode == _DNS_RcodeNameError && dns.authoritative { - return nil, DNS_NameNotFound // authoritative "no such host" - } - if dns.rcode != _DNS_RcodeSuccess { - // 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, DNS_ServerFailure - } - - // Look for the name. - // Presotto says it's okay to assume that servers listed in - // /etc/resolv.conf are recursive resolvers. - // We asked for recursion, so it should have included - // all the answers we need in this one packet. -Cname: - for cnameloop := 0; cnameloop < 10; cnameloop++ { - addrs = addrs[0:0]; - for i := 0; i < len(dns.answer); i++ { - rr := dns.answer[i]; - h := rr.Header(); - if h.class == _DNS_ClassINET && h.name == name { - switch h.rrtype { - case _DNS_TypeA: - n := len(addrs); - a := rr.(*_DNS_RR_A).a; - addrs = addrs[0:n+1]; - addrs[n] = fmt.Sprintf("%d.%d.%d.%d", (a>>24), (a>>16)&0xFF, (a>>8)&0xFF, a&0xFF); - case _DNS_TypeCNAME: - // redirect to cname - name = rr.(*_DNS_RR_CNAME).cname; - continue Cname - } - } - } - if len(addrs) == 0 { - return nil, DNS_NameNotFound - } - return addrs, nil - } - - // Too many redirects - return nil, DNS_RedirectLoop -} - -// Do a lookup for a single name, which must be rooted -// (otherwise answer will not find the answers). -func tryOneName(cfg *_DNS_Config, name string) (addrs []string, err os.Error) { - err = DNS_NoServers; - 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. - c, cerr := Dial("udp", "", cfg.servers[i] + ":53"); - if cerr != nil { - err = cerr; - continue; - } - msg, merr := _Exchange(cfg, c, name); - c.Close(); - if merr != nil { - err = merr; - continue; - } - addrs, aerr := answer(name, msg); - if aerr != nil && aerr != DNS_NameNotFound { - err = aerr; - continue; - } - return addrs, aerr; - } - return; -} - -var cfg *_DNS_Config -var dnserr os.Error - -func loadConfig() { - cfg, dnserr = _DNS_ReadConfig(); -} - -// LookupHost looks up the host name using the local DNS resolver. -// It returns the canonical name for the host and an array of that -// host's addresses. -func LookupHost(name string) (cname string, addrs []string, err os.Error) -{ - // TODO(rsc): Pick out obvious non-DNS names to avoid - // sending stupid requests to the server? - - once.Do(loadConfig); - if dnserr != nil || cfg == nil { - // better error than file not found. - err = DNS_MissingConfig; - 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 || strings.Count(name, ".") >= cfg.ndots { - rname := name; - if !rooted { - rname += "."; - } - // Can try as ordinary name. - addrs, aerr := tryOneName(cfg, rname); - if aerr == nil { - return rname, addrs, nil; - } - err = aerr; - } - if rooted { - return - } - - // Otherwise, try suffixes. - for i := 0; i < len(cfg.search); i++ { - newname := name+"."+cfg.search[i]; - if newname[len(newname)-1] != '.' { - newname += "." - } - addrs, aerr := tryOneName(cfg, newname); - if aerr == nil { - return newname, addrs, nil; - } - err = aerr; - } - return -} diff --git a/src/lib/net/dnsconfig.go b/src/lib/net/dnsconfig.go deleted file mode 100644 index e56d964f2..000000000 --- a/src/lib/net/dnsconfig.go +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Read system DNS config from /etc/resolv.conf - -package net - -import ( - "io"; - "net"; - "os"; - "strconv"; -) - -type _DNS_Config 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 _DNS_configError os.Error; - -// 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 _DNS_ReadConfig() (*_DNS_Config, os.Error) { - // TODO(rsc): 6g won't let me say file, err := - var file *file; - var err os.Error; - file, err = open("/etc/resolv.conf"); - if err != nil { - return nil, err - } - conf := new(_DNS_Config); - conf.servers = make([]string, 3)[0:0]; // small, but the standard limit - conf.search = make([]string, 0); - conf.ndots = 1; - conf.timeout = 1; - conf.attempts = 1; - 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]; - if len(ParseIP(name)) != 0 { - 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, i, ok := dtoi(s, 6); - if n < 1 { - n = 1 - } - conf.ndots = n; - case len(s) >= 8 && s[0:8] == "timeout:": - n, i, ok := dtoi(s, 8); - if n < 1 { - n = 1 - } - conf.timeout = n; - case len(s) >= 8 && s[0:9] == "attempts:": - n, i, ok := 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/lib/net/dnsmsg.go b/src/lib/net/dnsmsg.go deleted file mode 100644 index d7a467fc6..000000000 --- a/src/lib/net/dnsmsg.go +++ /dev/null @@ -1,679 +0,0 @@ -// Copyright 2009 The Go 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. -// -// 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 _DNS_RR_Header.rrtype and _DNS_Question.qtype - _DNS_TypeA = 1; - _DNS_TypeNS = 2; - _DNS_TypeMD = 3; - _DNS_TypeMF = 4; - _DNS_TypeCNAME = 5; - _DNS_TypeSOA = 6; - _DNS_TypeMB = 7; - _DNS_TypeMG = 8; - _DNS_TypeMR = 9; - _DNS_TypeNULL = 10; - _DNS_TypeWKS = 11; - _DNS_TypePTR = 12; - _DNS_TypeHINFO = 13; - _DNS_TypeMINFO = 14; - _DNS_TypeMX = 15; - _DNS_TypeTXT = 16; - - // valid _DNS_Question.qtype only - _DNS_TypeAXFR = 252; - _DNS_TypeMAILB = 253; - _DNS_TypeMAILA = 254; - _DNS_TypeALL = 255; - - // valid _DNS_Question.qclass - _DNS_ClassINET = 1; - _DNS_ClassCSNET = 2; - _DNS_ClassCHAOS = 3; - _DNS_ClassHESIOD = 4; - _DNS_ClassANY = 255; - - // _DNS_Msg.rcode - _DNS_RcodeSuccess = 0; - _DNS_RcodeFormatError = 1; - _DNS_RcodeServerFailure = 2; - _DNS_RcodeNameError = 3; - _DNS_RcodeNotImplemented = 4; - _DNS_RcodeRefused = 5; -) - -// The wire format for the DNS packet header. -type __DNS_Header struct { - id uint16; - bits uint16; - qdcount, ancount, nscount, arcount uint16; -} - -const ( - // __DNS_Header.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 _DNS_Question 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 _DNS_RR_Header struct { - name string "domain-name"; - rrtype uint16; - class uint16; - ttl uint32; - rdlength uint16; // length of data after header -} - -func (h *_DNS_RR_Header) Header() *_DNS_RR_Header { - return h -} - -type _DNS_RR interface { - Header() *_DNS_RR_Header -} - - -// Specific DNS RR formats for each query type. - -type _DNS_RR_CNAME struct { - _DNS_RR_Header; - cname string "domain-name"; -} - -type _DNS_RR_HINFO struct { - _DNS_RR_Header; - cpu string; - os string; -} - -type _DNS_RR_MB struct { - _DNS_RR_Header; - mb string "domain-name"; -} - -type _DNS_RR_MG struct { - _DNS_RR_Header; - mg string "domain-name"; -} - -type _DNS_RR_MINFO struct { - _DNS_RR_Header; - rmail string "domain-name"; - email string "domain-name"; -} - -type _DNS_RR_MR struct { - _DNS_RR_Header; - mr string "domain-name"; -} - -type _DNS_RR_MX struct { - _DNS_RR_Header; - pref uint16; - mx string "domain-name"; -} - -type _DNS_RR_NS struct { - _DNS_RR_Header; - ns string "domain-name"; -} - -type _DNS_RR_PTR struct { - _DNS_RR_Header; - ptr string "domain-name"; -} - -type _DNS_RR_SOA struct { - _DNS_RR_Header; - ns string "domain-name"; - mbox string "domain-name"; - serial uint32; - refresh uint32; - retry uint32; - expire uint32; - minttl uint32; -} - -type _DNS_RR_TXT struct { - _DNS_RR_Header; - txt string; // not domain name -} - -type _DNS_RR_A struct { - _DNS_RR_Header; - a uint32 "ipv4"; -} - - -// 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()_DNS_RR { - _DNS_TypeCNAME: func() _DNS_RR { return new(_DNS_RR_CNAME) }, - _DNS_TypeHINFO: func() _DNS_RR { return new(_DNS_RR_HINFO) }, - _DNS_TypeMB: func() _DNS_RR { return new(_DNS_RR_MB) }, - _DNS_TypeMG: func() _DNS_RR { return new(_DNS_RR_MG) }, - _DNS_TypeMINFO: func() _DNS_RR { return new(_DNS_RR_MINFO) }, - _DNS_TypeMR: func() _DNS_RR { return new(_DNS_RR_MR) }, - _DNS_TypeMX: func() _DNS_RR { return new(_DNS_RR_MX) }, - _DNS_TypeNS: func() _DNS_RR { return new(_DNS_RR_NS) }, - _DNS_TypePTR: func() _DNS_RR { return new(_DNS_RR_PTR) }, - _DNS_TypeSOA: func() _DNS_RR { return new(_DNS_RR_SOA) }, - _DNS_TypeTXT: func() _DNS_RR { return new(_DNS_RR_TXT) }, - _DNS_TypeA: func() _DNS_RR { return new(_DNS_RR_A) }, -} - -// Pack a domain name s into msg[off:]. -// Domain names are a sequence of counted strings -// split at the dots. They end with a zero-length string. -func packDomainName(s string, msg []byte, off int) (off1 int, ok bool) { - // Add trailing dot to canonicalize name. - if n := len(s); n == 0 || s[n-1] != '.' { - s += "."; - } - - // Each dot ends a segment of the name. - // We trade each dot byte for a length byte. - // There is also a trailing zero. - // Check that we have all the space we need. - tot := len(s) + 1; - if off+tot > len(msg) { - return len(msg), false - } - - // Emit sequence of counted strings, chopping at dots. - begin := 0; - for i := 0; i < len(s); i++ { - if s[i] == '.' { - if i - begin >= 1<<6 { // top two bits of length must be clear - return len(msg), false - } - msg[off] = byte(i - begin); - off++; - for j := begin; j < i; j++ { - msg[off] = s[j]; - off++; - } - begin = i+1; - } - } - msg[off] = 0; - off++; - return off, true -} - -// Unpack a domain name. -// In addition to the simple sequences of counted strings above, -// domain names are allowed to refer to strings elsewhere in the -// packet, to avoid repeating common suffixes when returning -// many entries in a single domain. The pointers are marked -// by a length byte with the top two bits set. Ignoring those -// two bits, that byte and the next give a 14 bit offset from msg[0] -// where we should pick up the trail. -// Note that if we jump elsewhere in the packet, -// we return off1 == the offset after the first pointer we found, -// which is where the next record will start. -// In theory, the pointers are only allowed to jump backward. -// We let them jump anywhere and stop jumping after a while. -func unpackDomainName(msg []byte, off int) (s string, off1 int, ok bool) { - s = ""; - ptr := 0; // number of pointers followed -Loop: - for { - if off >= len(msg) { - return "", len(msg), false - } - c := int(msg[off]); - off++; - switch c&0xC0 { - case 0x00: - if c == 0x00 { - // end of name - break Loop - } - // literal string - if off+c > len(msg) { - return "", len(msg), false - } - s += string(msg[off:off+c]) + "."; - off += c; - case 0xC0: - // pointer to somewhere else in msg. - // remember location after first ptr, - // since that's how many bytes we consumed. - // also, don't follow too many pointers -- - // maybe there's a loop. - if off >= len(msg) { - return "", len(msg), false - } - c1 := msg[off]; - off++; - if ptr == 0 { - off1 = off - } - if ptr++; ptr > 10 { - return "", len(msg), false - } - off = (c^0xC0)<<8 | int(c1); - default: - // 0x80 and 0x40 are reserved - return "", len(msg), false - } - } - if ptr == 0 { - off1 = off - } - return s, off1, true -} - -// Pack a reflect.StructValue into msg. Struct members can only be uint16, uint32, string, -// and other (often anonymous) structs. -func packStructValue(val reflect.StructValue, msg []byte, off int) (off1 int, ok bool) { - for i := 0; i < val.Len(); i++ { - fld := val.Field(i); - name, typ, tag, xxx := val.Type().(reflect.StructType).Field(i); - switch fld.Kind() { - default: - fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", fld.Type()); - return len(msg), false; - case reflect.StructKind: - off, ok = packStructValue(fld.(reflect.StructValue), msg, off); - case reflect.Uint16Kind: - i := fld.(reflect.Uint16Value).Get(); - if off+2 > len(msg) { - return len(msg), false - } - msg[off] = byte(i>>8); - msg[off+1] = byte(i); - off += 2; - case reflect.Uint32Kind: - i := fld.(reflect.Uint32Value).Get(); - 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+4] = byte(i); - off += 4; - case reflect.StringKind: - // There are multiple string encodings. - // The tag distinguishes ordinary strings from domain names. - s := fld.(reflect.StringValue).Get(); - switch tag { - default: - fmt.Fprintf(os.Stderr, "net: dns: unknown string tag %v", 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++; - for i := 0; i < len(s); i++ { - msg[off+i] = s[i]; - } - off += len(s); - } - } - } - return off, true -} - -func packStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) { - val := reflect.NewValue(any).(reflect.PtrValue).Sub().(reflect.StructValue); - off, ok = packStructValue(val, msg, off); - return off, ok -} - -// 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.Len(); i++ { - name, typ, tag, xxx := val.Type().(reflect.StructType).Field(i); - fld := val.Field(i); - switch fld.Kind() { - default: - fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", fld.Type()); - return len(msg), false; - case reflect.StructKind: - off, ok = unpackStructValue(fld.(reflect.StructValue), msg, off); - case reflect.Uint16Kind: - if off+2 > len(msg) { - return len(msg), false - } - i := uint16(msg[off])<<8 | uint16(msg[off+1]); - fld.(reflect.Uint16Value).Set(i); - off += 2; - case reflect.Uint32Kind: - 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]); - fld.(reflect.Uint32Value).Set(i); - off += 4; - case reflect.StringKind: - var s string; - switch tag { - default: - fmt.Fprintf(os.Stderr, "net: dns: unknown string tag %v", 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); - } - fld.(reflect.StringValue).Set(s); - } - } - return off, true -} - -func unpackStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) { - val := reflect.NewValue(any).(reflect.PtrValue).Sub().(reflect.StructValue); - off, ok = unpackStructValue(val, msg, off); - return off, ok -} - -// Generic struct printer. -// Doesn't care about the string tag "domain-name", -// but does look for an "ipv4" tag on uint32 variables, -// printing them as IP addresses. -func printStructValue(val reflect.StructValue) string { - s := "{"; - for i := 0; i < val.Len(); i++ { - if i > 0 { - s += ", "; - } - name, typ, tag, xxx := val.Type().(reflect.StructType).Field(i); - fld := val.Field(i); - if name != "" && name != "?" { // BUG? Shouldn't the reflect library hide "?" ? - s += name + "="; - } - kind := fld.Kind(); - switch { - case kind == reflect.StructKind: - s += printStructValue(fld.(reflect.StructValue)); - case kind == reflect.Uint32Kind && tag == "ipv4": - i := fld.(reflect.Uint32Value).Get(); - s += fmt.Sprintf("%d.%d.%d.%d", (i>>24)&0xFF, (i>>16)&0xFF, (i>>8)&0xFF, i&0xFF); - default: - s += fmt.Sprint(fld.Interface()) - } - } - s += "}"; - return s; -} - -func printStruct(any interface{}) string { - val := reflect.NewValue(any).(reflect.PtrValue).Sub().(reflect.StructValue); - s := printStructValue(val); - return s -} - -// Resource record packer. -func packRR(rr _DNS_RR, 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 _DNS_RR, off1 int, ok bool) { - // unpack just the header, to find the rr type and length - var h _DNS_RR_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 __DNS_Msg_Top struct { - id uint16; - response bool; - opcode int; - authoritative bool; - truncated bool; - recursion_desired bool; - recursion_available bool; - rcode int; -} - -type _DNS_Msg struct { - __DNS_Msg_Top; - question []_DNS_Question; - answer []_DNS_RR; - ns []_DNS_RR; - extra []_DNS_RR; -} - - -func (dns *_DNS_Msg) Pack() (msg []byte, ok bool) { - var dh __DNS_Header; - - // Convert convenient _DNS_Msg into wire-like __DNS_Header. - 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 = packStruct(answer[i], msg, off); - } - for i := 0; i < len(ns); i++ { - off, ok = packStruct(ns[i], msg, off); - } - for i := 0; i < len(extra); i++ { - off, ok = packStruct(extra[i], msg, off); - } - if !ok { - return nil, false - } - return msg[0:off], true -} - -func (dns *_DNS_Msg) Unpack(msg []byte) bool { - // Header. - var dh __DNS_Header; - 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([]_DNS_Question, dh.qdcount); - dns.answer = make([]_DNS_RR, dh.ancount); - dns.ns = make([]_DNS_RR, dh.nscount); - dns.extra = make([]_DNS_RR, 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 *_DNS_Msg) String() string { - s := "DNS: "+printStruct(&dns.__DNS_Msg_Top)+"\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/lib/net/fd.go b/src/lib/net/fd.go deleted file mode 100644 index 9404ed0bd..000000000 --- a/src/lib/net/fd.go +++ /dev/null @@ -1,429 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// TODO(rsc): All the prints in this file should go to standard error. - -package net - -import ( - "net"; - "once"; - "os"; - "sync"; - "syscall"; -) - -// Network file descriptor. -type netFD struct { - // immutable until Close - fd int; - file *os.File; - cr chan *netFD; - cw chan *netFD; - net string; - laddr string; - raddr string; - - // 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; -} - -// 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. - -type pollServer struct { - cr, cw chan *netFD; // buffered >= 1 - pr, pw *os.File; - pending map[int] *netFD; - poll *pollster; // low-level OS hooks - deadline int64; // next deadline (nsec since 1970) -} -func (s *pollServer) Run(); - -func newPollServer() (s *pollServer, err os.Error) { - s = new(pollServer); - s.cr = make(chan *netFD, 1); - s.cw = make(chan *netFD, 1); - if s.pr, s.pw, err = os.Pipe(); err != nil { - return nil, err - } - var e int; - if e = syscall.SetNonblock(s.pr.Fd(), true); e != 0 { - Errno: - err = os.ErrnoToError(e); - Error: - s.pr.Close(); - s.pw.Close(); - return nil, err; - } - if e = syscall.SetNonblock(s.pw.Fd(), true); e != 0 { - goto Errno; - } - if s.poll, err = newpollster(); err != nil { - goto Error; - } - if err = s.poll.AddFD(s.pr.Fd(), 'r', true); err != nil { - s.poll.Close(); - goto Error - } - s.pending = make(map[int] *netFD); - go s.Run(); - return s, nil -} - -func (s *pollServer) AddFD(fd *netFD, mode int) { - // TODO(rsc): This check handles a race between - // one goroutine reading and another one closing, - // but it doesn't solve the race completely: - // it still could happen that one goroutine closes - // but we read fd.fd before it does, and then - // another goroutine creates a new open file with - // that fd, which we'd now be referring to. - // The fix is probably to send the Close call - // through the poll server too, except that - // not all Reads and Writes go through the poll - // server even now. - intfd := fd.fd; - if intfd < 0 { - // fd closed underfoot - if mode == 'r' { - fd.cr <- fd - } else { - fd.cw <- fd - } - return - } - if err := s.poll.AddFD(intfd, mode, false); err != nil { - panicln("pollServer AddFD ", intfd, ": ", err.String(), "\n"); - return - } - - var t int64; - key := intfd << 1; - if mode == 'r' { - fd.ncr++; - t = fd.rdeadline; - } else { - fd.ncw++; - key++; - t = fd.wdeadline; - } - s.pending[key] = fd; - if t > 0 && (s.deadline == 0 || t < s.deadline) { - s.deadline = t; - } -} - -func (s *pollServer) LookupFD(fd int, mode int) *netFD { - key := fd << 1; - if mode == 'w' { - key++; - } - netfd, ok := s.pending[key]; - if !ok { - return nil - } - s.pending[key] = nil, false; - return netfd -} - -func (s *pollServer) WakeFD(fd *netFD, mode int) { - if mode == 'r' { - for fd.ncr > 0 { - fd.ncr--; - fd.cr <- fd - } - } else { - for fd.ncw > 0 { - fd.ncw--; - fd.cw <- fd - } - } -} - -func (s *pollServer) Now() int64 { - sec, nsec, err := os.Time(); - if err != nil { - panic("net: os.Time: ", err.String()); - } - nsec += sec * 1e9; - return nsec; -} - -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.fd, mode); - fd.rdeadline = -1; - } else { - s.poll.DelFD(fd.fd, mode); - fd.wdeadline = -1; - } - s.WakeFD(fd, mode); - } else if next_deadline == 0 || t < next_deadline { - next_deadline = t; - } - } - } - s.deadline = next_deadline; -} - -func (s *pollServer) Run() { - var scratch [100]byte; - for { - var t = s.deadline; - if t > 0 { - t = t - s.Now(); - if t < 0 { - s.CheckDeadlines(); - continue; - } - } - fd, mode, err := s.poll.WaitFD(t); - if err != nil { - print("pollServer WaitFD: ", err.String(), "\n"); - return - } - if fd < 0 { - // Timeout happened. - s.CheckDeadlines(); - continue; - } - if fd == s.pr.Fd() { - // Drain our wakeup pipe. - for nn, e := s.pr.Read(&scratch); nn > 0; { - nn, e = s.pr.Read(&scratch) - } - - // Read from channels - for fd, ok := <-s.cr; ok; fd, ok = <-s.cr { - s.AddFD(fd, 'r') - } - for fd, ok := <-s.cw; ok; fd, ok = <-s.cw { - s.AddFD(fd, 'w') - } - } else { - netfd := s.LookupFD(fd, mode); - if netfd == nil { - print("pollServer: unexpected wakeup for fd=", netfd, " mode=", string(mode), "\n"); - continue - } - s.WakeFD(netfd, mode); - } - } -} - -var wakeupbuf [1]byte; -func (s *pollServer) Wakeup() { - s.pw.Write(&wakeupbuf) -} - -func (s *pollServer) WaitRead(fd *netFD) { - s.cr <- fd; - s.Wakeup(); - <-fd.cr -} - -func (s *pollServer) WaitWrite(fd *netFD) { - s.cw <- fd; - s.Wakeup(); - <-fd.cw -} - - -// Network FD methods. -// All the network FDs use a single pollServer. - -var pollserver *pollServer - -func _StartServer() { - p, err := newPollServer(); - if err != nil { - print("Start pollServer: ", err.String(), "\n") - } - pollserver = p -} - -func newFD(fd int, net, laddr, raddr string) (f *netFD, err os.Error) { - if pollserver == nil { - once.Do(_StartServer); - } - if e := syscall.SetNonblock(fd, true); e != 0 { - return nil, os.ErrnoToError(e); - } - f = new(netFD); - f.fd = fd; - f.net = net; - f.laddr = laddr; - f.raddr = raddr; - f.file = os.NewFile(fd, "net: " + net + " " + laddr + " " + raddr); - f.cr = make(chan *netFD, 1); - f.cw = make(chan *netFD, 1); - return f, nil -} - -func (fd *netFD) Close() os.Error { - if fd == nil || fd.file == nil { - return os.EINVAL - } - - // 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.file.Fd(), false); - - e := fd.file.Close(); - fd.file = nil; - fd.fd = -1; - return e -} - -func (fd *netFD) Read(p []byte) (n int, err os.Error) { - if fd == nil || fd.file == nil { - return -1, os.EINVAL - } - fd.rio.Lock(); - defer fd.rio.Unlock(); - if fd.rdeadline_delta > 0 { - fd.rdeadline = pollserver.Now() + fd.rdeadline_delta; - } else { - fd.rdeadline = 0; - } - n, err = fd.file.Read(p); - for err == os.EAGAIN && fd.rdeadline >= 0 { - pollserver.WaitRead(fd); - n, err = fd.file.Read(p) - } - return n, err -} - -func (fd *netFD) Write(p []byte) (n int, err os.Error) { - if fd == nil || fd.file == nil { - return -1, os.EINVAL - } - fd.wio.Lock(); - defer fd.wio.Unlock(); - if fd.wdeadline_delta > 0 { - fd.wdeadline = pollserver.Now() + fd.wdeadline_delta; - } else { - fd.wdeadline = 0; - } - err = nil; - nn := 0; - for nn < len(p) { - n, err = fd.file.Write(p[nn:len(p)]); - if n > 0 { - nn += n - } - if nn == len(p) { - break; - } - if err == os.EAGAIN && fd.wdeadline >= 0 { - pollserver.WaitWrite(fd); - continue; - } - if n == 0 || err != nil { - break; - } - } - return nn, err -} - -func sockaddrToString(sa syscall.Sockaddr) (name string, err os.Error) - -func (fd *netFD) accept() (nfd *netFD, err os.Error) { - if fd == nil || fd.file == nil { - return nil, os.EINVAL - } - - // See ../syscall/exec.go for description of ForkLock. - // It is okay to hold the lock across syscall.Accept - // because we have put fd.fd into non-blocking mode. - syscall.ForkLock.RLock(); - var s, e int; - var sa syscall.Sockaddr; - for { - s, sa, e = syscall.Accept(fd.fd); - if e != syscall.EAGAIN { - break; - } - syscall.ForkLock.RUnlock(); - pollserver.WaitRead(fd); - syscall.ForkLock.RLock(); - } - if e != 0 { - syscall.ForkLock.RUnlock(); - return nil, os.ErrnoToError(e) - } - syscall.CloseOnExec(s); - syscall.ForkLock.RUnlock(); - - raddr, err1 := sockaddrToString(sa); - if err1 != nil { - raddr = "invalid-address"; - } - if nfd, err = newFD(s, fd.net, fd.laddr, raddr); err != nil { - syscall.Close(s); - return nil, err - } - return nfd, nil -} - diff --git a/src/lib/net/fd_darwin.go b/src/lib/net/fd_darwin.go deleted file mode 100644 index 42bf51221..000000000 --- a/src/lib/net/fd_darwin.go +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright 2009 The Go 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 ( - "net"; - "os"; - "syscall"; -) - -var kqueuePhaseError = &Error{"kqueue phase error"} - -type pollster struct { - kq int; - eventbuf [10]syscall.Kevent_t; - events []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.ErrnoToError(e) - } - p.events = p.eventbuf[0:0]; - return p, nil -} - -func (p *pollster) AddFD(fd int, mode int, repeat bool) os.Error { - var kmode int; - if mode == 'r' { - kmode = syscall.EVFILT_READ - } else { - kmode = syscall.EVFILT_WRITE - } - var events [1]syscall.Kevent_t; - ev := &events[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, &events, &events, nil); - if e != 0 { - return os.ErrnoToError(e) - } - if n != 1 || (ev.Flags & syscall.EV_ERROR) == 0 || int(ev.Ident) != fd || int(ev.Filter) != kmode { - return kqueuePhaseError - } - if ev.Data != 0 { - return os.ErrnoToError(int(ev.Data)) - } - return nil -} - -func (p *pollster) DelFD(fd int, mode int) { - var kmode int; - if mode == 'r' { - kmode = syscall.EVFILT_READ - } else { - kmode = syscall.EVFILT_WRITE - } - var events [1]syscall.Kevent_t; - ev := &events[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, &events, &events, nil); -} - -func (p *pollster) WaitFD(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); - } - nn, e := syscall.Kevent(p.kq, nil, &p.eventbuf, t); - if e != 0 { - if e == syscall.EINTR { - continue - } - return -1, 0, os.ErrnoToError(e) - } - if nn == 0 { - return -1, 0, nil; - } - p.events = p.eventbuf[0:nn] - } - ev := &p.events[0]; - p.events = p.events[1:len(p.events)]; - 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.ErrnoToError(syscall.Close(p.kq)) -} diff --git a/src/lib/net/fd_linux.go b/src/lib/net/fd_linux.go deleted file mode 100644 index bd822589e..000000000 --- a/src/lib/net/fd_linux.go +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright 2009 The Go 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 ( - "net"; - "os"; - "syscall"; -) - -const ( - readFlags = syscall.EPOLLIN | syscall.EPOLLRDHUP; - writeFlags = syscall.EPOLLOUT -) - -type pollster struct { - epfd int; - - // Events we're already waiting for - events map[int] uint32; -} - -func newpollster() (p *pollster, err os.Error) { - p = new(pollster); - var e int; - - // The arg to epoll_create is a hint to the kernel - // about the number of FDs we will care about. - // We don't know. - if p.epfd, e = syscall.EpollCreate(16); e != 0 { - return nil, os.ErrnoToError(e) - } - p.events = make(map[int] uint32); - return p, nil -} - -func (p *pollster) AddFD(fd int, mode int, repeat bool) os.Error { - var ev syscall.EpollEvent; - var already bool; - ev.Fd = int32(fd); - ev.Events, already = p.events[fd]; - if !repeat { - ev.Events |= syscall.EPOLLONESHOT; - } - if mode == 'r' { - ev.Events |= readFlags; - } else { - ev.Events |= writeFlags; - } - - var op int; - if already { - op = syscall.EPOLL_CTL_MOD; - } else { - op = syscall.EPOLL_CTL_ADD; - } - if e := syscall.EpollCtl(p.epfd, op, fd, &ev); e != 0 { - return os.ErrnoToError(e) - } - p.events[fd] = ev.Events; - return nil -} - -func (p *pollster) StopWaiting(fd int, bits uint) { - events, already := p.events[fd]; - if !already { - print("Epoll unexpected fd=", fd, "\n"); - return; - } - - // If syscall.EPOLLONESHOT is not set, the wait - // is a repeating wait, so don't change it. - if events & syscall.EPOLLONESHOT == 0 { - return; - } - - // Disable the given bits. - // If we're still waiting for other events, modify the fd - // event in the kernel. Otherwise, delete it. - events &= ^uint32(bits); - if int32(events) & ^syscall.EPOLLONESHOT != 0 { - var ev syscall.EpollEvent; - ev.Fd = int32(fd); - ev.Events = events; - if e := syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_MOD, fd, &ev); e != 0 { - print("Epoll modify fd=", fd, ": ", os.ErrnoToError(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.ErrnoToError(e).String(), "\n"); - } - p.events[fd] = 0, false; - } -} - -func (p *pollster) DelFD(fd int, mode int) { - if mode == 'r' { - p.StopWaiting(fd, readFlags); - } else { - p.StopWaiting(fd, writeFlags); - } -} - -func (p *pollster) WaitFD(nsec int64) (fd int, mode int, err os.Error) { - // Get an event. - var evarray [1]syscall.EpollEvent; - ev := &evarray[0]; - var msec int = -1; - if nsec > 0 { - msec = int((nsec + 1e6 - 1)/1e6); - } - n, e := syscall.EpollWait(p.epfd, &evarray, msec); - for e == syscall.EAGAIN || e == syscall.EINTR { - n, e = syscall.EpollWait(p.epfd, &evarray, msec); - } - if e != 0 { - return -1, 0, os.ErrnoToError(e); - } - if n == 0 { - return -1, 0, nil; - } - fd = int(ev.Fd); - - if ev.Events & writeFlags != 0 { - p.StopWaiting(fd, writeFlags); - return fd, 'w', nil; - } - if ev.Events & readFlags != 0 { - p.StopWaiting(fd, readFlags); - return fd, 'r', nil; - } - - // Other events are error conditions - wake whoever is waiting. - events, already := 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.ErrnoToError(syscall.Close(p.epfd)); -} diff --git a/src/lib/net/ip.go b/src/lib/net/ip.go deleted file mode 100644 index 774f048ca..000000000 --- a/src/lib/net/ip.go +++ /dev/null @@ -1,421 +0,0 @@ -// Copyright 2009 The Go 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 ( - "net" -) - -// IP address lengths (bytes). -const ( - IPv4len = 4; - IPv6len = 16 -) - -// An IP is a single IP address, an array of bytes. -// Functions in this package accept either 4-byte (IP v4) -// or 16-byte (IP v6) arrays as input. Unless otherwise -// specified, functions in this package always return -// IP addresses in 16-byte form using the canonical -// embedding. -// -// Note that in this documentation, referring to an -// IP address as an IPv4 address or an IPv6 address -// is a semantic property of the address, not just the -// length of the byte array: a 16-byte array can still -// be an IPv4 address. -type IP []byte; - -// An IP mask is an IP address. -type IPMask []byte; - -// IPv4 returns the IP address (in 16-byte form) of the -// IPv4 address a.b.c.d. -func IPv4(a, b, c, d byte) IP { - p := make(IP, IPv6len); - for i := 0; i < 10; i++ { - p[i] = 0 - } - p[10] = 0xff; - p[11] = 0xff; - p[12] = a; - p[13] = b; - p[14] = c; - p[15] = d; - return p -} - -// Well-known IPv4 addresses -var ( - IPv4bcast = IPv4(255, 255, 255, 255); // broadcast - IPv4allsys = IPv4(224, 0, 0, 1); // all systems - IPv4allrouter = IPv4(224, 0, 0, 2); // all routers - IPv4zero = IPv4(0, 0, 0, 0); // all zeros -) - -// Well-known IPv6 addresses -var ( - IPzero = make(IP, IPv6len); // all zeros -) - -// Is p all zeros? -func isZeros(p IP) bool { - for i := 0; i < len(p); i++ { - if p[i] != 0 { - return false - } - } - return true -} - -// To4 converts the IPv4 address ip to a 4-byte representation. -// If ip is not an IPv4 address, To4 returns nil. -func (ip IP) To4() IP { - if len(ip) == IPv4len { - return ip - } - if len(ip) == IPv6len - && isZeros(ip[0:10]) - && ip[10] == 0xff - && ip[11] == 0xff { - return ip[12:16] - } - return nil -} - -// To16 converts the IP address ip to a 16-byte representation. -// If ip is not an IP address (it is the wrong length), To16 returns nil. -func (ip IP) To16() IP { - if len(ip) == IPv4len { - return IPv4(ip[0], ip[1], ip[2], ip[3]) - } - if len(ip) == IPv6len { - return ip - } - return nil -} - -// Default route masks for IPv4. -var ( - classAMask = IPMask(IPv4(0xff, 0, 0, 0)); - classBMask = IPMask(IPv4(0xff, 0xff, 0, 0)); - classCMask = IPMask(IPv4(0xff, 0xff, 0xff, 0)); -) - -// DefaultMask returns the default IP mask for the IP address ip. -// Only IPv4 addresses have default masks; DefaultMask returns -// nil if ip is not a valid IPv4 address. -func (ip IP) DefaultMask() IPMask { - if ip = ip.To4(); ip == nil { - return nil - } - switch true { - case ip[0] < 0x80: - return classAMask; - case ip[0] < 0xC0: - return classBMask; - default: - return classCMask; - } - return nil; // not reached -} - -// Mask returns the result of masking the IP address ip with mask. -func (ip IP) Mask(mask IPMask) IP { - n := len(ip); - if n != len(mask) { - return nil - } - out := make(IP, n); - for i := 0; i < n; i++ { - out[i] = ip[i] & mask[i]; - } - return out -} - -// Convert i to decimal string. -func itod(i uint) string { - if i == 0 { - return "0" - } - - // Assemble decimal in reverse order. - var b [32]byte; - bp := len(b); - for ; i > 0; i /= 10 { - bp--; - b[bp] = byte(i%10) + '0' - } - - return string(b[bp:len(b)]) -} - -// 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:len(b)]) -} - -// 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 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 - } - } - - // Print with possible :: in place of run of zeros - var s string; - for i := 0; i < 16; i += 2 { - if i == e0 { - s += "::"; - i = e1; - if i >= 16 { - break - } - } else if i > 0 { - s += ":" - } - s += itox((uint(p[i])<<8) | uint(p[i+1])) - } - return s -} - -// If mask is a sequence of 1 bits followed by 0 bits, -// return the number of 1 bits. -func simpleMaskLength(mask IPMask) int { - var i int; - for i = 0; i < len(mask); i++ { - if mask[i] != 0xFF { - break - } - } - n := 8*i; - v := mask[i]; - for v & 0x80 != 0 { - n++; - v <<= 1 - } - if v != 0 { - return -1 - } - for i++; i < len(mask); i++ { - if mask[i] != 0 { - return -1 - } - } - 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 >= 0 { - return itod(uint(n)) - } - } - 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 j > 0 { - if s[i] != '.' { - return nil - } - i++; - } - var ( - n int; - ok bool - ) - n, i, ok = dtoi(s, i); - if !ok || n > 0xFF { - return nil - } - p[j] = byte(n) - } - if i != len(s) { - return nil - } - return IPv4(p[0], p[1], p[2], p[3]) -} - -// Parse IPv6 address. Many forms. -// The basic form is a sequence of eight colon-separated -// 16-bit hex numbers separated by colons, -// as in 0123:4567:89ab:cdef:0123:4567:89ab:cdef. -// Two exceptions: -// * A run of zeros can be replaced with "::". -// * The last 32 bits can be in IPv4 form. -// Thus, ::ffff:1.2.3.4 is the IPv4 address 1.2.3.4. -func parseIPv6(s string) IP { - p := make(IP, 16); - ellipsis := -1; // position of ellipsis in p - i := 0; // index in string s - - // Might have leading ellipsis - if len(s) >= 2 && s[0] == ':' && s[1] == ':' { - ellipsis = 0; - i = 2; - // Might be only ellipsis - if i == len(s) { - return p - } - } - - // Loop, parsing hex numbers followed by colon. - j := 0; -L: for j < IPv6len { - // Hex number. - n, i1, ok := xtoi(s, i); - if !ok || n > 0xFFFF { - return nil - } - - // If followed by dot, might be in trailing IPv4. - if i1 < len(s) && s[i1] == '.' { - if ellipsis < 0 && j != IPv6len - IPv4len { - // Not the right place. - return nil - } - if j+IPv4len > IPv6len { - // Not enough room. - return nil - } - p4 := parseIPv4(s[i:len(s)]); - if p4 == nil { - return nil - } - // BUG: p[j:j+4] = p4 - p[j] = p4[12]; - p[j+1] = p4[13]; - p[j+2] = p4[14]; - p[j+3] = p4[15]; - i = len(s); - j += 4; - break - } - - // Save this 16-bit chunk. - p[j] = byte(n>>8); - p[j+1] = byte(n); - j += 2; - - // Stop at end of string. - i = i1; - if i == len(s) { - break - } - - // Otherwise must be followed by colon and more. - if s[i] != ':' && i+1 == len(s) { - return nil - } - i++; - - // Look for ellipsis. - if s[i] == ':' { - if ellipsis >= 0 { // already have one - return nil - } - ellipsis = j; - if i++; i == len(s) { // can be at end - break - } - } - } - - // Must have used entire string. - if i != len(s) { - return nil - } - - // If didn't parse enough, expand ellipsis. - if j < IPv6len { - if ellipsis < 0 { - return nil - } - n := IPv6len - j; - for k := j-1; k >= ellipsis; k-- { - p[k+n] = p[k] - } - for k := ellipsis+n-1; k>=ellipsis; k-- { - p[k] = 0 - } - } - return p -} - -// ParseIP parses s as an IP address, returning the result. -// The string s can be in dotted decimal ("74.125.19.99") -// or IPv6 ("2001:4860:0:2001::68") form. -// If s is not a valid textual representation of an IP address, -// ParseIP returns nil. -func ParseIP(s string) IP { - p := parseIPv4(s); - if p != nil { - return p - } - return parseIPv6(s) -} - diff --git a/src/lib/net/ip_test.go b/src/lib/net/ip_test.go deleted file mode 100644 index fb2ae8216..000000000 --- a/src/lib/net/ip_test.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package net - -import ( - "net"; - "testing" -) - -func isEqual(a, b IP) bool { - if a == nil && b == nil { - return true - } - if a == nil || b == nil || len(a) != len(b) { - return false - } - for i := 0; i < len(a); i++ { - if a[i] != b[i] { - return false - } - } - return true -} - -type parseIPTest struct { - in string; - out IP; -} -var parseiptests = []parseIPTest{ - parseIPTest{"127.0.1.2", IPv4(127, 0, 1, 2)}, - parseIPTest{"127.0.0.1", IPv4(127, 0, 0, 1)}, - parseIPTest{"127.0.0.256", nil}, - parseIPTest{"abc", nil}, - parseIPTest{"::ffff:127.0.0.1", IPv4(127, 0, 0, 1)}, - parseIPTest{"2001:4860:0:2001::68", - IP{0x20,0x01, 0x48,0x60, 0,0, 0x20,0x01, - 0,0, 0,0, 0,0, 0x00,0x68}}, - parseIPTest{"::ffff:4a7d:1363", IPv4(74, 125, 19, 99)}, -} - -func TestParseIP(t *testing.T) { - for i := 0; i < len(parseiptests); i++ { - tt := parseiptests[i]; - if out := ParseIP(tt.in); !isEqual(out, tt.out) { - t.Errorf("ParseIP(%#q) = %v, want %v", tt.in, out, tt.out); - } - } -} diff --git a/src/lib/net/net.go b/src/lib/net/net.go deleted file mode 100644 index 5c442e6a4..000000000 --- a/src/lib/net/net.go +++ /dev/null @@ -1,862 +0,0 @@ -// Copyright 2009 The Go Authors. 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 ( - "net"; - "os"; - "strconv"; - "syscall"; -) - -var ( - BadAddress os.Error = &Error{"malformed address"}; - MissingAddress os.Error = &Error{"missing address"}; - UnknownNetwork os.Error = &Error{"unknown network"}; - UnknownHost os.Error = &Error{"unknown host"}; - UnknownSocketFamily os.Error = &Error{"unknown socket family"}; -) - - -// Conn is a generic network connection. -type Conn interface { - // Read blocks until data is ready from the connection - // and then reads into b. It returns the number - // of bytes read, or 0 if the connection has been closed. - Read(b []byte) (n int, err os.Error); - - // Write writes the data in b to the connection. - Write(b []byte) (n int, err os.Error); - - // Close closes the connection. - Close() os.Error; - - // For packet-based protocols such as UDP, - // ReadFrom reads the next packet from the network, - // returning the number of bytes read and the remote - // address that sent them. - ReadFrom(b []byte) (n int, addr string, err os.Error); - - // For packet-based protocols such as UDP, - // WriteTo writes the byte buffer b to the network - // as a single payload, sending it to the target address. - WriteTo(addr string, b []byte) (n int, err os.Error); - - // SetReadBuffer sets the size of the operating system's - // receive buffer associated with the connection. - SetReadBuffer(bytes int) os.Error; - - // SetReadBuffer sets the size of the operating system's - // transmit buffer associated with the connection. - SetWriteBuffer(bytes int) os.Error; - - // 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 os.EAGAIN. - // 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 os.EAGAIN. - // 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; - - // 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. - SetLinger(sec int) os.Error; - - // SetReuseAddr sets whether it is okay to reuse addresses - // from recent connections that were not properly closed. - SetReuseAddr(reuseaddr bool) os.Error; - - // SetDontRoute sets whether outgoing messages should - // bypass the system routing tables. - SetDontRoute(dontroute bool) os.Error; - - // SetKeepAlive sets whether the operating system should send - // keepalive messages on the connection. - SetKeepAlive(keepalive bool) os.Error; - - // BindToDevice binds a connection to a particular network device. - BindToDevice(dev string) os.Error; -} - -// Should we try to use the IPv4 socket interface if we're -// only dealing with IPv4 sockets? As long as the host system -// understands IPv6, it's okay to pass IPv4 addresses to the IPv6 -// interface. That simplifies our code and is most general. -// Unfortunately, we need to run on kernels built without IPv6 support too. -// So probe the kernel to figure it out. -func kernelSupportsIPv6() bool { - fd, e := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP); - if fd >= 0 { - syscall.Close(fd) - } - return e == 0 -} - -var preferIPv4 = !kernelSupportsIPv6() - -// TODO(rsc): if syscall.OS == "linux", we're supposd to read -// /proc/sys/net/core/somaxconn, -// to take advantage of kernels that have raised the limit. -func listenBacklog() int { - return syscall.SOMAXCONN -} - -func LookupHost(name string) (cname string, addrs []string, err os.Error) - -// Split "host:port" into "host" and "port". -// Host cannot contain colons unless it is bracketed. -func splitHostPort(hostport string) (host, port string, err os.Error) { - // The port starts after the last colon. - var i int; - for i = len(hostport)-1; i >= 0; i-- { - if hostport[i] == ':' { - break - } - } - if i < 0 { - return "", "", BadAddress - } - - host = hostport[0:i]; - port = hostport[i+1:len(hostport)]; - - // 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 { - return "", "", BadAddress - } - } - return host, port, nil -} - -// Join "host" and "port" into "host:port". -// If host contains colons, will join into "[host]:port". -func joinHostPort(host, port string) string { - // If host has colons, have to bracket it. - if byteIndex(host, ':') >= 0 { - return "[" + host + "]:" + port - } - return host + ":" + port -} - -// Convert "host:port" into IP address and port. -// For now, host and port must be numeric literals. -// Eventually, we'll have name resolution. -func hostPortToIP(net, hostport, mode string) (ip IP, iport int, err os.Error) { - var host, port string; - host, port, err = splitHostPort(hostport); - if err != nil { - return nil, 0, err - } - - var addr IP; - if host == "" { - if mode == "listen" { - if preferIPv4 { - addr = IPv4zero; - } else { - addr = IPzero; // wildcard - listen to all - } - } else { - return nil, 0, MissingAddress; - } - } - - // Try as an IP address. - if addr == nil { - addr = ParseIP(host); - } - if addr == nil { - // Not an IP address. Try as a DNS name. - hostname, addrs, err := LookupHost(host); - if err != nil { - return nil, 0, err - } - if len(addrs) == 0 { - return nil, 0, UnknownHost - } - addr = ParseIP(addrs[0]); - if addr == nil { - // should not happen - return nil, 0, BadAddress - } - } - - p, i, ok := dtoi(port, 0); - if !ok || i != len(port) { - p, err = LookupPort(net, port); - if err != nil { - return nil, 0, err - } - } - if p < 0 || p > 0xFFFF { - return nil, 0, BadAddress - } - - return addr, p, nil -} - -func sockaddrToString(sa syscall.Sockaddr) (name string, err os.Error) { - switch a := sa.(type) { - case *syscall.SockaddrInet4: - return joinHostPort(IP(&a.Addr).String(), strconv.Itoa(a.Port)), nil; - case *syscall.SockaddrInet6: - return joinHostPort(IP(&a.Addr).String(), strconv.Itoa(a.Port)), nil; - case *syscall.SockaddrUnix: - return a.Name, nil; - } - return "", UnknownSocketFamily -} - -func ipToSockaddr(family int, ip IP, port int) (syscall.Sockaddr, os.Error) { - switch family { - case syscall.AF_INET: - if ip = ip.To4(); ip == nil { - return nil, os.EINVAL - } - 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: - // IPv4 callers use 0.0.0.0 to mean "announce on any available address". - // In IPv6 mode, Linux treats that as meaning "announce on 0.0.0.0", - // which it refuses to do. Rewrite to the IPv6 all zeros. - if p4 := ip.To4(); p4 != nil && p4[0] == 0 && p4[1] == 0 && p4[2] == 0 && p4[3] == 0 { - ip = IPzero; - } - if ip = ip.To16(); ip == nil { - return nil, os.EINVAL - } - s := new(syscall.SockaddrInet6); - for i := 0; i < IPv6len; i++ { - s.Addr[i] = ip[i]; - } - s.Port = port; - return s, nil; - } - return nil, os.EINVAL; -} - -// Boolean to int. -func boolint(b bool) int { - if b { - return 1 - } - return 0 -} - -// Generic socket creation. -func socket(net, laddr, raddr string, f, p, t int, la, ra syscall.Sockaddr) (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.ErrnoToError(e) - } - syscall.CloseOnExec(s); - syscall.ForkLock.RUnlock(); - - // Allow reuse of recently-used addresses. - syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); - - var r int64; - if la != nil { - e = syscall.Bind(s, la); - if e != 0 { - syscall.Close(s); - return nil, os.ErrnoToError(e) - } - } - - if ra != nil { - e = syscall.Connect(s, ra); - if e != 0 { - syscall.Close(s); - return nil, os.ErrnoToError(e) - } - } - - fd, err = newFD(s, net, laddr, raddr); - if err != nil { - syscall.Close(s); - return nil, err - } - - return fd, nil -} - - -// Generic implementation of Conn interface; not exported. -type connBase struct { - fd *netFD; - raddr string; -} - -func (c *connBase) File() *os.File { - if c == nil { - return nil - } - return c.fd.file; -} - -func (c *connBase) sysFD() int { - if c == nil || c.fd == nil { - return -1; - } - return c.fd.fd; -} - -func (c *connBase) Read(b []byte) (n int, err os.Error) { - n, err = c.fd.Read(b); - return n, err -} - -func (c *connBase) Write(b []byte) (n int, err os.Error) { - n, err = c.fd.Write(b); - return n, err -} - -func (c *connBase) ReadFrom(b []byte) (n int, raddr string, err os.Error) { - if c == nil { - return -1, "", os.EINVAL - } - n, err = c.Read(b); - return n, c.raddr, err -} - -func (c *connBase) WriteTo(raddr string, b []byte) (n int, err os.Error) { - if c == nil { - return -1, os.EINVAL - } - if raddr != c.raddr { - return -1, os.EINVAL - } - n, err = c.Write(b); - return n, err -} - -func (c *connBase) Close() os.Error { - if c == nil { - return os.EINVAL - } - return c.fd.Close() -} - - -func setsockoptInt(fd, level, opt int, value int) os.Error { - return os.ErrnoToError(syscall.SetsockoptInt(fd, level, opt, value)); -} - -func setsockoptNsec(fd, level, opt int, nsec int64) os.Error { - var tv = syscall.NsecToTimeval(nsec); - return os.ErrnoToError(syscall.SetsockoptTimeval(fd, level, opt, &tv)); -} - -func (c *connBase) SetReadBuffer(bytes int) os.Error { - return setsockoptInt(c.sysFD(), syscall.SOL_SOCKET, syscall.SO_RCVBUF, bytes); -} - -func (c *connBase) SetWriteBuffer(bytes int) os.Error { - return setsockoptInt(c.sysFD(), syscall.SOL_SOCKET, syscall.SO_SNDBUF, bytes); -} - -func (c *connBase) SetReadTimeout(nsec int64) os.Error { - c.fd.rdeadline_delta = nsec; - return nil; -} - -func (c *connBase) SetWriteTimeout(nsec int64) os.Error { - c.fd.wdeadline_delta = nsec; - return nil; -} - -func (c *connBase) SetTimeout(nsec int64) os.Error { - if e := c.SetReadTimeout(nsec); e != nil { - return e - } - return c.SetWriteTimeout(nsec) -} - -func (c *connBase) SetReuseAddr(reuse bool) os.Error { - return setsockoptInt(c.sysFD(), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, boolint(reuse)); -} - -func (c *connBase) BindToDevice(dev string) os.Error { - // TODO(rsc): call setsockopt with null-terminated string pointer - return os.EINVAL -} - -func (c *connBase) SetDontRoute(dontroute bool) os.Error { - return setsockoptInt(c.sysFD(), syscall.SOL_SOCKET, syscall.SO_DONTROUTE, boolint(dontroute)); -} - -func (c *connBase) SetKeepAlive(keepalive bool) os.Error { - return setsockoptInt(c.sysFD(), syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, boolint(keepalive)); -} - -func (c *connBase) SetLinger(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; - } - e := syscall.SetsockoptLinger(c.sysFD(), syscall.SOL_SOCKET, syscall.SO_LINGER, &l); - return os.ErrnoToError(e); -} - - -// Internet sockets (TCP, UDP) - -func internetSocket(net, laddr, raddr string, proto int, mode string) (fd *netFD, err os.Error) { - // Parse addresses (unless they are empty). - var lip, rip IP; - var lport, rport int; - var lerr, rerr os.Error; - - if laddr != "" { - lip, lport, lerr = hostPortToIP(net, laddr, mode); - if lerr != nil { - return nil, lerr - } - } - if raddr != "" { - rip, rport, rerr = hostPortToIP(net, raddr, mode); - if rerr != nil { - return nil, rerr - } - } - - // Figure out IP version. - // If network has a suffix like "tcp4", obey it. - vers := 0; - switch net[len(net)-1] { - case '4': - vers = 4; - case '6': - vers = 6; - default: - // Otherwise, guess. - // If the addresses are IPv4 and we prefer IPv4, use 4; else 6. - if preferIPv4 && (lip == nil || lip.To4() != nil) && (rip == nil || rip.To4() != nil) { - vers = 4 - } else { - vers = 6 - } - } - - var family int; - if vers == 4 { - family = syscall.AF_INET - } else { - family = syscall.AF_INET6 - } - - var la, ra syscall.Sockaddr; - if lip != nil { - la, lerr = ipToSockaddr(family, lip, lport); - if lerr != nil { - return nil, lerr - } - } - if rip != nil { - ra, rerr = ipToSockaddr(family, rip, rport); - if rerr != nil { - return nil, rerr - } - } - - fd, err = socket(net, laddr, raddr, family, proto, 0, la, ra); - return fd, err -} - - -// TCP connections. - -// ConnTCP is an implementation of the Conn interface -// for TCP network connections. -type ConnTCP struct { - connBase -} - -func (c *ConnTCP) SetNoDelay(nodelay bool) os.Error { - if c == nil { - return os.EINVAL - } - return setsockoptInt(c.sysFD(), syscall.IPPROTO_TCP, syscall.TCP_NODELAY, boolint(nodelay)) -} - -func newConnTCP(fd *netFD, raddr string) *ConnTCP { - c := new(ConnTCP); - c.fd = fd; - c.raddr = raddr; - c.SetNoDelay(true); - return c -} - -// DialTCP is like Dial but can only connect to TCP networks -// and returns a ConnTCP structure. -func DialTCP(net, laddr, raddr string) (c *ConnTCP, err os.Error) { - if raddr == "" { - return nil, MissingAddress - } - fd, e := internetSocket(net, laddr, raddr, syscall.SOCK_STREAM, "dial"); - if e != nil { - return nil, e - } - return newConnTCP(fd, raddr), nil -} - - -// UDP connections. - -// TODO(rsc): UDP headers mode - -// ConnUDP is an implementation of the Conn interface -// for UDP network connections. -type ConnUDP struct { - connBase -} - -func newConnUDP(fd *netFD, raddr string) *ConnUDP { - c := new(ConnUDP); - c.fd = fd; - c.raddr = raddr; - return c -} - -// DialUDP is like Dial but can only connect to UDP networks -// and returns a ConnUDP structure. -func DialUDP(net, laddr, raddr string) (c *ConnUDP, err os.Error) { - if raddr == "" { - return nil, MissingAddress - } - fd, e := internetSocket(net, laddr, raddr, syscall.SOCK_DGRAM, "dial"); - if e != nil { - return nil, e - } - return newConnUDP(fd, raddr), nil -} - - -// TODO: raw IP connections - -// TODO: raw ethernet connections - - -// Unix domain sockets - -func unixSocket(net, laddr, raddr string, mode string) (fd *netFD, err os.Error) { - var proto int; - switch net { - default: - return nil, UnknownNetwork; - case "unix": - proto = syscall.SOCK_STREAM; - case "unix-dgram": - proto = syscall.SOCK_DGRAM; - } - - var la, ra syscall.Sockaddr; - switch mode { - case "dial": - if laddr != "" { - return nil, BadAddress; - } - if raddr == "" { - return nil, MissingAddress; - } - ra = &syscall.SockaddrUnix{Name: raddr}; - - case "listen": - if laddr == "" { - return nil, MissingAddress; - } - la = &syscall.SockaddrUnix{Name: laddr}; - if raddr != "" { - return nil, BadAddress; - } - } - - fd, err = socket(net, laddr, raddr, syscall.AF_UNIX, proto, 0, la, ra); - return fd, err -} - -// ConnUnix is an implementation of the Conn interface -// for connections to Unix domain sockets. -type ConnUnix struct { - connBase -} - -func newConnUnix(fd *netFD, raddr string) *ConnUnix { - c := new(ConnUnix); - c.fd = fd; - c.raddr = raddr; - return c; -} - -// DialUnix is like Dial but can only connect to Unix domain sockets -// and returns a ConnUnix structure. The laddr argument must be -// the empty string; it is included only to match the signature of -// the other dial routines. -func DialUnix(net, laddr, raddr string) (c *ConnUnix, err os.Error) { - fd, e := unixSocket(net, laddr, raddr, "dial"); - if e != nil { - return nil, e - } - return newConnUnix(fd, raddr), nil; -} - -// ListenerUnix is a Unix domain socket listener. -// Clients should typically use variables of type Listener -// instead of assuming Unix domain sockets. -type ListenerUnix struct { - fd *netFD; - laddr string -} - -// ListenUnix announces on the Unix domain socket laddr and returns a Unix listener. -// Net can be either "unix" (stream sockets) or "unix-dgram" (datagram sockets). -func ListenUnix(net, laddr string) (l *ListenerUnix, err os.Error) { - fd, e := unixSocket(net, laddr, "", "listen"); - if e != nil { - // Check for socket ``in use'' but ``refusing connections,'' - // which means some program created it and exited - // without unlinking it from the file system. - // Clean up on that program's behalf and try again. - // Don't do this for Linux's ``abstract'' sockets, which begin with @. - if e != os.EADDRINUSE || laddr[0] == '@' { - return nil, e; - } - fd1, e1 := unixSocket(net, "", laddr, "dial"); - if e1 == nil { - fd1.Close(); - } - if e1 != os.ECONNREFUSED { - return nil, e; - } - syscall.Unlink(laddr); - fd1, e1 = unixSocket(net, laddr, "", "listen"); - if e1 != nil { - return nil, e; - } - fd = fd1; - } - e1 := syscall.Listen(fd.fd, 8); // listenBacklog()); - if e1 != 0 { - syscall.Close(fd.fd); - return nil, os.ErrnoToError(e1); - } - return &ListenerUnix{fd, laddr}, nil; -} - -// AcceptUnix accepts the next incoming call and returns the new connection -// and the remote address. -func (l *ListenerUnix) AcceptUnix() (c *ConnUnix, raddr string, err os.Error) { - if l == nil || l.fd == nil || l.fd.fd < 0 { - return nil, "", os.EINVAL - } - fd, e := l.fd.accept(); - if e != nil { - return nil, "", e - } - return newConnUnix(fd, fd.raddr), raddr, nil -} - -// Accept implements the Accept method in the Listener interface; -// it waits for the next call and returns a generic Conn. -func (l *ListenerUnix) Accept() (c Conn, raddr string, err os.Error) { - // TODO(rsc): 6g bug prevents saying - // c, raddr, err = l.AcceptUnix(); - // return; - c1, r1, e1 := l.AcceptUnix(); - return c1, r1, e1; -} - - -// Close stops listening on the Unix address. -// Already accepted connections are not closed. -func (l *ListenerUnix) 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.laddr[0] != '@' { - syscall.Unlink(l.laddr); - } - err := l.fd.Close(); - l.fd = nil; - return err; -} - -// Dial connects to the remote address raddr on the network net. -// If the string laddr is not empty, it is used as the local address -// for the connection. -// -// Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only), -// "udp", "udp4" (IPv4-only), and "udp6" (IPv6-only). -// -// For IP networks, addresses have the form host:port. If host is -// a literal IPv6 address, it must be enclosed in square brackets. -// -// Examples: -// Dial("tcp", "", "12.34.56.78:80") -// Dial("tcp", "", "google.com:80") -// Dial("tcp", "", "[de:ad:be:ef::ca:fe]:80") -// Dial("tcp", "127.0.0.1:123", "127.0.0.1:88") -func Dial(net, laddr, raddr string) (c Conn, err os.Error) { - switch net { - case "tcp", "tcp4", "tcp6": - c, err := DialTCP(net, laddr, raddr); - if err != nil { - return nil, err - } - return c, nil; - case "udp", "udp4", "upd6": - c, err := DialUDP(net, laddr, raddr); - return c, err; - case "unix", "unix-dgram": - c, err := DialUnix(net, laddr, raddr); - return c, err; -/* - case "ether": - c, err := DialEther(net, laddr, raddr); - return c, err; - case "ipv4": - c, err := DialIPv4(net, laddr, raddr); - return c, err; - case "ipv6": - c, err := DialIPv6(net, laddr, raddr); - return c, err -*/ - } - return nil, UnknownNetwork -} - -// A Listener is a generic network listener. -// Accept waits for the next connection and Close closes the connection. -type Listener interface { - Accept() (c Conn, raddr string, err os.Error); - Close() os.Error; -} - -// ListenerTCP is a TCP network listener. -// Clients should typically use variables of type Listener -// instead of assuming TCP. -type ListenerTCP struct { - fd *netFD; - laddr string -} - -// ListenTCP announces on the TCP address laddr and returns a TCP listener. -// Net must be "tcp", "tcp4", or "tcp6". -func ListenTCP(net, laddr string) (l *ListenerTCP, err os.Error) { - fd, e := internetSocket(net, laddr, "", syscall.SOCK_STREAM, "listen"); - if e != nil { - return nil, e - } - e1 := syscall.Listen(fd.fd, listenBacklog()); - if e1 != 0 { - syscall.Close(fd.fd); - return nil, os.ErrnoToError(e1) - } - l = new(ListenerTCP); - l.fd = fd; - return l, nil -} - -// AcceptTCP accepts the next incoming call and returns the new connection -// and the remote address. -func (l *ListenerTCP) AcceptTCP() (c *ConnTCP, raddr string, err os.Error) { - if l == nil || l.fd == nil || l.fd.fd < 0 { - return nil, "", os.EINVAL - } - fd, e := l.fd.accept(); - if e != nil { - return nil, "", e - } - return newConnTCP(fd, fd.raddr), fd.raddr, nil -} - -// Accept implements the Accept method in the Listener interface; -// it waits for the next call and returns a generic Conn. -func (l *ListenerTCP) Accept() (c Conn, raddr string, err os.Error) { - c1, r1, e1 := l.AcceptTCP(); - if e1 != nil { - return nil, "", e1 - } - return c1, r1, nil -} - -// Close stops listening on the TCP address. -// Already Accepted connections are not closed. -func (l *ListenerTCP) Close() os.Error { - if l == nil || l.fd == nil { - return os.EINVAL - } - return l.fd.Close() -} - -// Listen announces on the local network address laddr. -// The network string net must be "tcp", "tcp4", "tcp6", -// "unix", or "unix-dgram". -func Listen(net, laddr string) (l Listener, err os.Error) { - switch net { - case "tcp", "tcp4", "tcp6": - l, err := ListenTCP(net, laddr); - if err != nil { - return nil, err; - } - return l, nil; - case "unix", "unix-dgram": - l, err := ListenUnix(net, laddr); - if err != nil { - return nil, err; - } - return l, nil; -/* - more here -*/ - // BUG(rsc): Listen should support UDP. - } - return nil, UnknownNetwork -} - diff --git a/src/lib/net/parse.go b/src/lib/net/parse.go deleted file mode 100644 index de47cb812..000000000 --- a/src/lib/net/parse.go +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright 2009 The Go 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. - -package net - -import ( - "io"; - "os"; -) - -type Error struct { - os.ErrorString -} - -type file struct { - file *os.File; - data []byte; -} - -func (f *file) close() { - f.file.Close() -} - -func (f *file) getLineFromData() (s string, ok bool) { - data := f.data; - 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; - for j := 0; j < n; j++ { - data[j] = data[i+j]; - } - f.data = data[0:n]; - return - } - } - 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.FullRead(f.file, f.data[ln:cap(f.data)]); - if n >= 0 { - f.data = f.data[0:ln+n]; - } - } - s, ok = f.getLineFromData(); - return -} - -func open(name string) (*file, os.Error) { - fd, err := os.Open(name, os.O_RDONLY, 0); - if err != nil { - return nil, err; - } - return &file{fd, make([]byte, 1024)[0:0]}, 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:len(s)]); - 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 -} - diff --git a/src/lib/net/parse_test.go b/src/lib/net/parse_test.go deleted file mode 100644 index ce0bb4709..000000000 --- a/src/lib/net/parse_test.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2009 The Go Authors. 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"; - "net"; - "os"; - "testing"; -) - -func TestReadLine(t *testing.T) { - filename := "/etc/services"; // a nice big file - - fd, err := os.Open(filename, os.O_RDONLY, 0); - if err != nil { - t.Fatalf("open %s: %v", filename, err); - } - br := bufio.NewReader(fd); - - var file *file; - file, err = open(filename); - if file == nil { - t.Fatalf("net.open(%s) = nil", filename); - } - - lineno := 1; - byteno := 0; - for { - bline, berr := br.ReadLineString('\n', false); - 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/lib/net/port.go b/src/lib/net/port.go deleted file mode 100644 index 21e3b48aa..000000000 --- a/src/lib/net/port.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Read system port mappings from /etc/services - -package net - -import ( - "io"; - "net"; - "once"; - "os"; - "strconv"; -) - -// The error returned by LookupPort when a network service -// is not listed in the database. -var ErrNoService = &Error{"unknown network service"}; - -var services map[string] map[string] int -var servicesError os.Error - -func readServices() { - services = make(map[string] map[string] int); - var file *file; - file, servicesError = open("/etc/services"); - 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:len(portnet)]; // "tcp" - m, ok1 := services[netw]; - if !ok1 { - m = make(map[string] int); - services[netw] = m; - } - for i := 0; i < len(f); i++ { - if i != 1 { // f[1] was port/net - m[f[i]] = port; - } - } - } - file.close(); -} - -// LookupPort looks up the port for the given network and service. -func LookupPort(network, service string) (port int, err os.Error) { - once.Do(readServices); - - switch network { - case "tcp4", "tcp6": - network = "tcp"; - case "udp4", "udp6": - network = "udp"; - } - - m, ok := services[network]; - if !ok { - return 0, ErrNoService; - } - port, ok = m[service]; - if !ok { - return 0, ErrNoService; - } - return port, nil; -} diff --git a/src/lib/net/port_test.go b/src/lib/net/port_test.go deleted file mode 100644 index c535d4caa..000000000 --- a/src/lib/net/port_test.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package net - -import ( - "net"; - "testing"; -) - -type portTest struct { - netw string; - name string; - port int; - ok bool; -} - -var porttests = []portTest { - portTest{ "tcp", "echo", 7, true }, - portTest{ "tcp", "discard", 9, true }, - portTest{ "tcp", "systat", 11, true }, - portTest{ "tcp", "daytime", 13, true }, - portTest{ "tcp", "chargen", 19, true }, - portTest{ "tcp", "ftp-data", 20, true }, - portTest{ "tcp", "ftp", 21, true }, - portTest{ "tcp", "ssh", 22, true }, - portTest{ "tcp", "telnet", 23, true }, - portTest{ "tcp", "smtp", 25, true }, - portTest{ "tcp", "time", 37, true }, - portTest{ "tcp", "domain", 53, true }, - portTest{ "tcp", "gopher", 70, true }, - portTest{ "tcp", "finger", 79, true }, - portTest{ "tcp", "http", 80, true }, - - portTest{ "udp", "echo", 7, true }, - portTest{ "udp", "tacacs", 49, true }, - portTest{ "udp", "tftp", 69, true }, - portTest{ "udp", "bootpc", 68, true }, - portTest{ "udp", "bootps", 67, true }, - portTest{ "udp", "domain", 53, true }, - portTest{ "udp", "ntp", 123, true }, - portTest{ "udp", "snmp", 161, true }, - portTest{ "udp", "syslog", 514, true }, - portTest{ "udp", "nfs", 2049, true }, - - portTest{ "--badnet--", "zzz", 0, false }, - portTest{ "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/lib/net/server_test.go b/src/lib/net/server_test.go deleted file mode 100644 index 586b55365..000000000 --- a/src/lib/net/server_test.go +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package net - -import ( - "io"; - "net"; - "os"; - "syscall"; - "testing"; -) - -func runEcho(fd io.ReadWriter, done chan<- int) { - var buf [1024]byte; - - for { - n, err := fd.Read(&buf); - if err != nil || n == 0 { - break; - } - fd.Write(buf[0:n]) - } - done <- 1 -} - -func runServe(t *testing.T, network, addr string, listening, done chan<- int) { - l, err := net.Listen(network, addr); - if err != nil { - t.Fatalf("net.Listen(%q, %q) = _, %v", network, addr, err); - } - listening <- 1; - - for { - fd, addr, 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) { - fd, err := net.Dial(network, "", addr); - if err != nil { - t.Fatalf("net.Dial(%q, %q, %q) = _, %v", network, "", addr, err); - } - - b := io.StringBytes("hello, world\n"); - var b1 [100]byte; - - n, errno := fd.Write(b); - if n != len(b) { - t.Fatalf("fd.Write(%q) = %d, %v", b, n, errno); - } - - n, errno = fd.Read(&b1); - if n != len(b) { - t.Fatalf("fd.Read() = %d, %v", n, errno); - } - fd.Close(); -} - -func doTest(t *testing.T, network, listenaddr, dialaddr string) { - t.Logf("Test %s %s %s\n", network, listenaddr, dialaddr); - listening := make(chan int); - done := make(chan int); - go runServe(t, network, listenaddr, listening, done); - <-listening; // wait for server to start - connect(t, network, dialaddr); - <-done; // make sure server stopped -} - -func TestTcpServer(t *testing.T) { - doTest(t, "tcp", "0.0.0.0:9997", "127.0.0.1:9997"); - doTest(t, "tcp", "[::]:9997", "[::ffff:127.0.0.1]:9997"); - doTest(t, "tcp", "[::]:9997", "127.0.0.1:9997"); - doTest(t, "tcp", ":9997", "127.0.0.1:9997"); - doTest(t, "tcp", "0.0.0.0:9997", "[::ffff:127.0.0.1]:9997"); -} - -func TestUnixServer(t *testing.T) { - doTest(t, "unix", "/tmp/gotest.net", "/tmp/gotest.net"); - if syscall.OS == "linux" { - // Test abstract unix domain socket, a Linux-ism - doTest(t, "unix", "@gotest/net", "@gotest/net"); - } -} diff --git a/src/lib/net/timeout_test.go b/src/lib/net/timeout_test.go deleted file mode 100644 index e08ce88ce..000000000 --- a/src/lib/net/timeout_test.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package net - -import ( - "net"; - "os"; - "testing"; - "time"; -) - -func testTimeout(t *testing.T, network, addr string) { - fd, err := net.Dial(network, "", addr); - defer fd.Close(); - if err != nil { - t.Errorf("dial %s %s failed: %v", network, addr, err); - } - t0 := time.Nanoseconds(); - fd.SetReadTimeout(1e8); // 100ms - var b [100]byte; - n, err1 := fd.Read(&b); - t1 := time.Nanoseconds(); - if n != 0 || err1 != os.EAGAIN { - t.Errorf("fd.Read on %s %s did not return 0, EAGAIN: %v, %v", network, addr, n, err1); - } - if t1 - t0 < 0.5e8 || t1 - t0 > 1.5e8 { - t.Errorf("fd.Read on %s %s took %f seconds, expected 0.1", network, addr, float64(t1 - t0) / 1e9); - } -} - -func TestTimeoutUDP(t *testing.T) { - testTimeout(t, "udp", "127.0.0.1:53"); -} - -func TestTimeoutTCP(t *testing.T) { - // 74.125.19.99 is www.google.com. - // could use dns, but dns depends on - // timeouts and this is the timeout test. - testTimeout(t, "tcp", "74.125.19.99:80"); -} diff --git a/src/lib/once/Makefile b/src/lib/once/Makefile deleted file mode 100644 index 6350402c2..000000000 --- a/src/lib/once/Makefile +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m >Makefile - -D= - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - once.$O\ - - -phases: a1 -_obj$D/once.a: phases - -a1: $(O1) - $(AR) grc _obj$D/once.a once.$O - rm -f $(O1) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/once.a - -$(O1): newpkg -$(O2): a1 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/once.a - -packages: _obj$D/once.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/once.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/once.a diff --git a/src/lib/once/once.go b/src/lib/once/once.go deleted file mode 100644 index 6047df236..000000000 --- a/src/lib/once/once.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// This package provides a single function, Do, to run a function -// exactly once, usually used as part of initialization. -package once - -import "sync" - -type job struct { - done bool; - sync.Mutex; // should probably be sync.Notification or some such -} - -var jobs = make(map[func()]*job) -var joblock sync.Mutex; - -// Do is the the only exported piece of the package. -// For one-time initialization that is not done during init, -// wrap the initialization in a niladic function f() and call -// Do(f) -// If multiple processes call Do(f) simultaneously -// with the same f argument, only one will call f, and the -// others will block until f finishes running. -func Do(f func()) { - joblock.Lock(); - j, present := jobs[f]; - if !present { - // run it - j = new(job); - j.Lock(); - jobs[f] = j; - joblock.Unlock(); - f(); - j.done = true; - j.Unlock(); - } else { - // wait for it - joblock.Unlock(); - if j.done != true { - j.Lock(); - j.Unlock(); - } - } -} diff --git a/src/lib/once/once_test.go b/src/lib/once/once_test.go deleted file mode 100644 index 9506ff3d7..000000000 --- a/src/lib/once/once_test.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package once - -import ( - "once"; - "testing"; -) - -var ncall int; -func call() { - ncall++ -} - -func TestOnce(t *testing.T) { - ncall = 0; - once.Do(call); - if ncall != 1 { - t.Fatalf("once.Do(call) didn't call(): ncall=%d", ncall); - } - once.Do(call); - if ncall != 1 { - t.Fatalf("second once.Do(call) did call(): ncall=%d", ncall); - } - once.Do(call); - if ncall != 1 { - t.Fatalf("third once.Do(call) did call(): ncall=%d", ncall); - } -} diff --git a/src/lib/os/Makefile b/src/lib/os/Makefile deleted file mode 100644 index c5f790f15..000000000 --- a/src/lib/os/Makefile +++ /dev/null @@ -1,91 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m dir_${GOOS}_${GOARCH}.go env.go error.go file.go path.go stat_${GOOS}_${GOARCH}.go time.go types.go exec.go proc.go getwd.go >Makefile - -D= - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - error.$O\ - types.$O\ - -O2=\ - proc.$O\ - stat_$(GOOS)_$(GOARCH).$O\ - time.$O\ - -O3=\ - env.$O\ - file.$O\ - -O4=\ - dir_$(GOOS)_$(GOARCH).$O\ - exec.$O\ - getwd.$O\ - path.$O\ - - -phases: a1 a2 a3 a4 -_obj$D/os.a: phases - -a1: $(O1) - $(AR) grc _obj$D/os.a error.$O types.$O - rm -f $(O1) - -a2: $(O2) - $(AR) grc _obj$D/os.a proc.$O stat_$(GOOS)_$(GOARCH).$O time.$O - rm -f $(O2) - -a3: $(O3) - $(AR) grc _obj$D/os.a env.$O file.$O - rm -f $(O3) - -a4: $(O4) - $(AR) grc _obj$D/os.a dir_$(GOOS)_$(GOARCH).$O exec.$O getwd.$O path.$O - rm -f $(O4) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/os.a - -$(O1): newpkg -$(O2): a1 -$(O3): a2 -$(O4): a3 -$(O5): a4 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/os.a - -packages: _obj$D/os.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/os.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/os.a diff --git a/src/lib/os/dir_darwin_386.go b/src/lib/os/dir_darwin_386.go deleted file mode 100644 index 2803ecee2..000000000 --- a/src/lib/os/dir_darwin_386.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2009 The Go Authors. 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 ( - "os"; - "syscall"; - "unsafe"; -) - -const ( - blockSize = 4096 // TODO(r): use statfs -) - -// Negative count means read until EOF. -func readdirnames(file *File, count int) (names []string, err Error) { - // If this file has no dirinfo, create one. - if file.dirinfo == nil { - file.dirinfo = new(dirInfo); - // The buffer must be at least a block long. - // TODO(r): use fstatfs to find fs block size. - file.dirinfo.buf = make([]byte, blockSize); - } - d := file.dirinfo; - size := count; - if size < 0 { - size = 100 - } - names = make([]string, 0, size); // Empty with room to grow. - for count != 0 { - // Refill the buffer if necessary - if d.bufp >= d.nbuf { - var errno int; - d.bufp = 0; - // Final argument is (basep *uintptr) and the syscall doesn't take nil. - d.nbuf, errno = syscall.Getdirentries(file.fd, d.buf, new(uintptr)); - if errno != 0 { - d.nbuf = 0; - return names, ErrnoToError(errno) - } - if d.nbuf == 0 { - break // EOF - } - } - // Drain the buffer - for count != 0 && d.bufp < d.nbuf { - dirent := (*syscall.Dirent)(unsafe.Pointer(&d.buf[d.bufp])); - if dirent.Reclen == 0 { - d.bufp = d.nbuf; - break - } - d.bufp += int(dirent.Reclen); - if dirent.Ino == 0 { // File absent in directory. - continue - } - bytes := (*[len(dirent.Name)]byte)(unsafe.Pointer(&dirent.Name[0])); - var name = string(bytes[0:dirent.Namlen]); - if name == "." || name == ".." { // Useless names - continue - } - count--; - if len(names) == cap(names) { - nnames := make([]string, len(names), 2*len(names)); - for i := 0; i < len(names); i++ { - nnames[i] = names[i] - } - names = nnames; - } - names = names[0:len(names)+1]; - names[len(names)-1] = name; - } - } - return names, nil -} diff --git a/src/lib/os/dir_darwin_amd64.go b/src/lib/os/dir_darwin_amd64.go deleted file mode 100644 index 2803ecee2..000000000 --- a/src/lib/os/dir_darwin_amd64.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2009 The Go Authors. 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 ( - "os"; - "syscall"; - "unsafe"; -) - -const ( - blockSize = 4096 // TODO(r): use statfs -) - -// Negative count means read until EOF. -func readdirnames(file *File, count int) (names []string, err Error) { - // If this file has no dirinfo, create one. - if file.dirinfo == nil { - file.dirinfo = new(dirInfo); - // The buffer must be at least a block long. - // TODO(r): use fstatfs to find fs block size. - file.dirinfo.buf = make([]byte, blockSize); - } - d := file.dirinfo; - size := count; - if size < 0 { - size = 100 - } - names = make([]string, 0, size); // Empty with room to grow. - for count != 0 { - // Refill the buffer if necessary - if d.bufp >= d.nbuf { - var errno int; - d.bufp = 0; - // Final argument is (basep *uintptr) and the syscall doesn't take nil. - d.nbuf, errno = syscall.Getdirentries(file.fd, d.buf, new(uintptr)); - if errno != 0 { - d.nbuf = 0; - return names, ErrnoToError(errno) - } - if d.nbuf == 0 { - break // EOF - } - } - // Drain the buffer - for count != 0 && d.bufp < d.nbuf { - dirent := (*syscall.Dirent)(unsafe.Pointer(&d.buf[d.bufp])); - if dirent.Reclen == 0 { - d.bufp = d.nbuf; - break - } - d.bufp += int(dirent.Reclen); - if dirent.Ino == 0 { // File absent in directory. - continue - } - bytes := (*[len(dirent.Name)]byte)(unsafe.Pointer(&dirent.Name[0])); - var name = string(bytes[0:dirent.Namlen]); - if name == "." || name == ".." { // Useless names - continue - } - count--; - if len(names) == cap(names) { - nnames := make([]string, len(names), 2*len(names)); - for i := 0; i < len(names); i++ { - nnames[i] = names[i] - } - names = nnames; - } - names = names[0:len(names)+1]; - names[len(names)-1] = name; - } - } - return names, nil -} diff --git a/src/lib/os/dir_linux_386.go b/src/lib/os/dir_linux_386.go deleted file mode 100644 index c4594a52d..000000000 --- a/src/lib/os/dir_linux_386.go +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2009 The Go 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 the porting dust settles, consider -// whether this file should be dir_linux.go (and similarly -// dir_darwin.go) instead of having one copy per architecture. - -package os - -import ( - "os"; - "syscall"; - "unsafe"; -) - -const ( - blockSize = 4096 // TODO(r): use statfs -) - -func clen(n []byte) int { - for i := 0; i < len(n); i++ { - if n[i] == 0 { - return i - } - } - return len(n) -} - -// Negative count means read until EOF. -func readdirnames(file *File, count int) (names []string, err Error) { - // If this file has no dirinfo, create one. - if file.dirinfo == nil { - file.dirinfo = new(dirInfo); - // The buffer must be at least a block long. - // TODO(r): use fstatfs to find fs block size. - file.dirinfo.buf = make([]byte, blockSize); - } - d := file.dirinfo; - size := count; - if size < 0 { - size = 100 - } - names = make([]string, 0, size); // Empty with room to grow. - for count != 0 { - // Refill the buffer if necessary - if d.bufp >= d.nbuf { - var errno int; - d.nbuf, errno = syscall.Getdents(file.fd, d.buf); - if d.nbuf < 0 { - return names, ErrnoToError(errno) - } - if d.nbuf == 0 { - break // EOF - } - d.bufp = 0; - } - // Drain the buffer - for count != 0 && d.bufp < d.nbuf { - dirent := (*syscall.Dirent)(unsafe.Pointer(&d.buf[d.bufp])); - d.bufp += int(dirent.Reclen); - if dirent.Ino == 0 { // File absent in directory. - continue - } - bytes := (*[len(dirent.Name)]byte)(unsafe.Pointer(&dirent.Name[0])); - var name = string(bytes[0:clen(bytes)]); - if name == "." || name == ".." { // Useless names - continue - } - count--; - if len(names) == cap(names) { - nnames := make([]string, len(names), 2*len(names)); - for i := 0; i < len(names); i++ { - nnames[i] = names[i] - } - names = nnames; - } - names = names[0:len(names)+1]; - names[len(names)-1] = name; - } - } - return names, nil; -} diff --git a/src/lib/os/dir_linux_amd64.go b/src/lib/os/dir_linux_amd64.go deleted file mode 100644 index 05b3d4c65..000000000 --- a/src/lib/os/dir_linux_amd64.go +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package os - -import ( - "os"; - "syscall"; - "unsafe"; -) - -const ( - blockSize = 4096 // TODO(r): use statfs -) - -func clen(n []byte) int { - for i := 0; i < len(n); i++ { - if n[i] == 0 { - return i - } - } - return len(n) -} - -// Negative count means read until EOF. -func readdirnames(file *File, count int) (names []string, err Error) { - // If this file has no dirinfo, create one. - if file.dirinfo == nil { - file.dirinfo = new(dirInfo); - // The buffer must be at least a block long. - // TODO(r): use fstatfs to find fs block size. - file.dirinfo.buf = make([]byte, blockSize); - } - d := file.dirinfo; - size := count; - if size < 0 { - size = 100 - } - names = make([]string, 0, size); // Empty with room to grow. - for count != 0 { - // Refill the buffer if necessary - if d.bufp >= d.nbuf { - var errno int; - d.nbuf, errno = syscall.Getdents(file.fd, d.buf); - if d.nbuf < 0 { - return names, ErrnoToError(errno) - } - if d.nbuf == 0 { - break // EOF - } - d.bufp = 0; - } - // Drain the buffer - for count != 0 && d.bufp < d.nbuf { - dirent := (*syscall.Dirent)(unsafe.Pointer(&d.buf[d.bufp])); - d.bufp += int(dirent.Reclen); - if dirent.Ino == 0 { // File absent in directory. - continue - } - bytes := (*[len(dirent.Name)]byte)(unsafe.Pointer(&dirent.Name[0])); - var name = string(bytes[0:clen(bytes)]); - if name == "." || name == ".." { // Useless names - continue - } - count--; - if len(names) == cap(names) { - nnames := make([]string, len(names), 2*len(names)); - for i := 0; i < len(names); i++ { - nnames[i] = names[i] - } - names = nnames; - } - names = names[0:len(names)+1]; - names[len(names)-1] = name; - } - } - return names, nil; -} diff --git a/src/lib/os/env.go b/src/lib/os/env.go deleted file mode 100644 index 748750413..000000000 --- a/src/lib/os/env.go +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Environment variables. - -package os - -import ( - "once"; - "os"; -) - -// ENOENV is the Error indicating that an environment variable does not exist. -var ENOENV = NewError("no such environment variable"); - -var env map[string] string; - - -func copyenv() { - env = make(map[string] string); - for i, s := range os.Envs { - for j := 0; j < len(s); j++ { - if s[j] == '=' { - env[s[0:j]] = s[j+1:len(s)]; - break; - } - } - } -} - -// Getenv retrieves the value of the environment variable named by the key. -// It returns the value and an error, if any. -func Getenv(key string) (value string, err Error) { - once.Do(copyenv); - - if len(key) == 0 { - return "", EINVAL; - } - v, ok := env[key]; - if !ok { - return "", ENOENV; - } - return v, nil; -} - -// Setenv sets the value of the environment variable named by the key. -// It returns an Error, if any. -func Setenv(key, value string) Error { - once.Do(copyenv); - - if len(key) == 0 { - return EINVAL; - } - env[key] = value; - return nil; -} - -// Clearenv deletes all environment variables. -func Clearenv() { - once.Do(copyenv); // prevent copyenv in Getenv/Setenv - env = make(map[string] string); -} - -// Environ returns an array of strings representing the environment, -// in the form "key=value". -func Environ() []string { - once.Do(copyenv); - a := make([]string, len(env)); - i := 0; - for k, v := range(env) { - // check i < len(a) for safety, - // in case env is changing underfoot. - if i < len(a) { - a[i] = k + "=" + v; - i++; - } - } - return a[0:i]; -} diff --git a/src/lib/os/error.go b/src/lib/os/error.go deleted file mode 100644 index 718499b21..000000000 --- a/src/lib/os/error.go +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package os - -import syscall "syscall" - -// An Error can represent any printable error condition. -type Error interface { - String() string -} - -// A helper type that can be embedded or wrapped to simplify satisfying -// Error. -type ErrorString string -func (e ErrorString) String() string { - return string(e) -} - -// NewError converts s to an ErrorString, which satisfies the Error interface. -func NewError(s string) Error { - return ErrorString(s) -} - -// Errno is the Unix error number. Names such as EINVAL are simple -// wrappers to convert the error number into an Error. -type Errno int64 -func (e Errno) String() string { - return syscall.Errstr(int(e)) -} - -// ErrnoToError converts errno to an Error (underneath, an Errno). -// It returns nil for the "no error" errno. -func ErrnoToError(errno int) Error { - if errno == 0 { - return nil - } - return Errno(errno) -} - -// 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); - ENOTBLK Error = Errno(syscall.ENOTBLK); - 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); - ETXTBSY Error = Errno(syscall.ETXTBSY); - 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); -) - diff --git a/src/lib/os/exec.go b/src/lib/os/exec.go deleted file mode 100644 index d283c7267..000000000 --- a/src/lib/os/exec.go +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2009 The Go Authors. 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 ( - "os"; - "syscall"; -) - -// ForkExec forks the current process and invokes Exec with the file, arguments, -// and environment specified by argv0, argv, and envv. It returns the process -// id of the forked process and an Error, if any. The fd array specifies the -// file descriptors to be set up in the new process: fd[0] will be Unix file -// descriptor 0 (standard input), fd[1] descriptor 1, and so on. A nil entry -// will cause the child to have no open file descriptor with that index. -// If dir is not empty, the child chdirs into the directory before execing the program. -func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []*File) - (pid int, err Error) -{ - // Create array of integer (system) fds. - intfd := make([]int, len(fd)); - for i, f := range(fd) { - if f == nil { - intfd[i] = -1; - } else { - intfd[i] = f.Fd(); - } - } - - p, e := syscall.ForkExec(argv0, argv, envv, dir, intfd); - return int(p), ErrnoToError(e); -} - -// Exec replaces the current process with an execution of the program -// named by argv0, with arguments argv and environment envv. -// If successful, Exec never returns. If it fails, it returns an Error. -// ForkExec is almost always a better way to execute a program. -func Exec(argv0 string, argv []string, envv []string) Error { - if envv == nil { - envv = Environ(); - } - e := syscall.Exec(argv0, argv, envv); - return ErrnoToError(e); -} - -// 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 os.Rusage struct, -// since syscall one might have different field types across -// different OS. - -// Waitmsg stores the information about an exited process as reported by Wait. -type Waitmsg struct { - Pid int; // The process's id. - syscall.WaitStatus; // System-dependent status info. - Rusage *syscall.Rusage; // System-dependent resource usage info. -} - -// Options for Wait. -const ( - WNOHANG = syscall.WNOHANG; // Don't wait if no process has exited. - WSTOPPED = syscall.WSTOPPED; // If set, status of stopped subprocesses is also reported. - WUNTRACED = WSTOPPED; - WRUSAGE = 1<<30; // Record resource usage. -) - -// Wait waits for process pid to exit or stop, and then returns a -// Waitmsg describing its status and an Error, if any. The options -// (WNOHANG etc.) affect the behavior of the Wait call. -func Wait(pid int, options int) (w *Waitmsg, err Error) { - var status syscall.WaitStatus; - var rusage *syscall.Rusage; - if options & WRUSAGE != 0 { - rusage = new(syscall.Rusage); - options ^= WRUSAGE; - } - pid1, e := syscall.Wait4(pid, &status, options, rusage); - if e != 0 { - return nil, ErrnoToError(e); - } - w = new(Waitmsg); - w.Pid = pid; - w.WaitStatus = status; - w.Rusage = rusage; - return w, nil; -} - -// Getpid returns the process id of the caller. -func Getpid() int { - p, r2, e := syscall.Syscall(syscall.SYS_GETPID, 0, 0, 0); - return int(p) -} - -// Getppid returns the process id of the caller's parent. -func Getppid() int { - p, r2, e := syscall.Syscall(syscall.SYS_GETPPID, 0, 0, 0); - return int(p) -} diff --git a/src/lib/os/file.go b/src/lib/os/file.go deleted file mode 100644 index 1562b1b0e..000000000 --- a/src/lib/os/file.go +++ /dev/null @@ -1,383 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// The os package provides a platform-independent interface to operating -// system functionality. The design is Unix-like. -package os - -import ( - "os"; - "syscall"; -) - -// 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. -} - -// File represents an open file descriptor. -type File struct { - fd int; - name string; - dirinfo *dirInfo; // nil unless directory being read - nepipe int; // number of consecutive EPIPE in Write -} - -// Fd returns the integer Unix file descriptor referencing the open file. -func (file *File) Fd() int { - return file.fd -} - -// Name returns the name of the file as presented to Open. -func (file *File) Name() string { - return file.name -} - -// NewFile returns a new File with the given file descriptor and name. -func NewFile(file int, name string) *File { - if file < 0 { - return nil - } - return &File{file, name, nil, 0} -} - -// Stdin, Stdout, and Stderr are open Files pointing to the standard input, -// standard output, and standard error file descriptors. -var ( - Stdin = NewFile(0, "/dev/stdin"); - Stdout = NewFile(1, "/dev/stdout"); - Stderr = NewFile(2, "/dev/stderr"); -) - -// Flags to Open wrapping those of the underlying system. Not all flags -// may be implemented on a given system. -const ( - O_RDONLY = syscall.O_RDONLY; // open the file read-only. - O_WRONLY = syscall.O_WRONLY; // open the file write-only. - O_RDWR = syscall.O_RDWR; // open the file read-write. - O_APPEND = syscall.O_APPEND; // open the file append-only. - O_ASYNC = syscall.O_ASYNC; // generate a signal when I/O is available. - O_CREAT = syscall.O_CREAT; // create a new file if none exists. - O_NOCTTY = syscall.O_NOCTTY; // do not make file the controlling tty. - O_NONBLOCK = syscall.O_NONBLOCK; // open in non-blocking mode. - O_NDELAY = O_NONBLOCK; // synonym for O_NONBLOCK - O_SYNC = syscall.O_SYNC; // open for synchronous I/O. - O_TRUNC = syscall.O_TRUNC; // if possible, truncate file when opened. -) - -// Open opens the named file with specified flag (O_RDONLY etc.) and perm, (0666 etc.) -// if applicable. If successful, methods on the returned File can be used for I/O. -// It returns the File and an Error, if any. -func Open(name string, flag int, perm int) (file *File, err Error) { - r, e := syscall.Open(name, flag | syscall.O_CLOEXEC, perm); - if e != 0 { - return nil, ErrnoToError(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), ErrnoToError(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 { - return EINVAL - } - err := ErrnoToError(syscall.Close(file.fd)); - file.fd = -1; // so it can't be closed again - return err; -} - -// 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 a nil Error. -// TODO(r): Add Pread, Pwrite (maybe ReadAt, WriteAt). -func (file *File) Read(b []byte) (ret int, err Error) { - if file == nil { - return 0, EINVAL - } - n, e := syscall.Read(file.fd, b); - if n < 0 { - n = 0; - } - return n, ErrnoToError(e); -} - -// Write writes len(b) bytes to the File. -// It returns the number of bytes written and an Error, if any. -// If the byte count differs from len(b), it usually implies an error occurred. -func (file *File) Write(b []byte) (ret int, err Error) { - if file == nil { - return 0, EINVAL - } - n, e := syscall.Write(file.fd, b); - if n < 0 { - n = 0 - } - if e == syscall.EPIPE { - file.nepipe++; - if file.nepipe >= 10 { - os.Exit(syscall.EPIPE); - } - } else { - file.nepipe = 0; - } - return n, ErrnoToError(e) -} - -// Seek sets the offset for the next Read or Write on file to offset, interpreted -// according to whence: 0 means relative to the origin of the file, 1 means -// relative to the current offset, and 2 means relative to the end. -// It returns the new offset and an Error, if any. -func (file *File) Seek(offset int64, whence int) (ret int64, err Error) { - r, e := syscall.Seek(file.fd, offset, whence); - if e != 0 { - return -1, ErrnoToError(e) - } - if file.dirinfo != nil && r != 0 { - return -1, ErrnoToError(syscall.EISDIR) - } - return r, nil -} - -// WriteString is like Write, but writes the contents of string s rather than -// an array of bytes. -func (file *File) WriteString(s string) (ret int, err Error) { - if file == nil { - return 0, EINVAL - } - b := syscall.StringByteSlice(s); - b = b[0:len(b)-1]; - r, e := syscall.Write(file.fd, b); - if r < 0 { - r = 0 - } - return int(r), ErrnoToError(e) -} - -// Pipe returns a connected pair of Files; reads from r return bytes written to w. -// It returns the files and an Error, if any. -func Pipe() (r *File, w *File, err Error) { - var p [2]int; - - // See ../syscall/exec.go for description of lock. - syscall.ForkLock.RLock(); - e := syscall.Pipe(&p); - if e != 0 { - syscall.ForkLock.RUnlock(); - return nil, nil, ErrnoToError(e) - } - syscall.CloseOnExec(p[0]); - syscall.CloseOnExec(p[1]); - syscall.ForkLock.RUnlock(); - - return NewFile(p[0], "|0"), NewFile(p[1], "|1"), nil -} - -// Mkdir creates a new directory with the specified name and permission bits. -// It returns an error, if any. -func Mkdir(name string, perm int) Error { - return ErrnoToError(syscall.Mkdir(name, perm)); -} - -// Stat returns a Dir structure describing the named file and an error, if any. -// If name names a valid symbolic link, the returned Dir describes -// the file pointed at by the link and has dir.FollowedSymlink set to true. -// If name names an invalid symbolic link, the returned Dir describes -// the link itself and has dir.FollowedSymlink set to false. -func Stat(name string) (dir *Dir, err Error) { - var lstat, stat syscall.Stat_t; - e := syscall.Lstat(name, &lstat); - if e != 0 { - return nil, ErrnoToError(e); - } - statp := &lstat; - if lstat.Mode & syscall.S_IFMT == syscall.S_IFLNK { - e := syscall.Stat(name, &stat); - if e == 0 { - statp = &stat; - } - } - return dirFromStat(name, new(Dir), &lstat, statp), nil -} - -// Stat returns the Dir structure describing file. -// It returns the Dir and an error, if any. -func (file *File) Stat() (dir *Dir, err Error) { - var stat syscall.Stat_t; - e := syscall.Fstat(file.fd, &stat); - if e != 0 { - return nil, ErrnoToError(e) - } - return dirFromStat(file.name, new(Dir), &stat, &stat), nil -} - -// Lstat returns the Dir structure describing the named file and an error, if any. -// If the file is a symbolic link, the returned Dir describes the -// symbolic link. Lstat makes no attempt to follow the link. -func Lstat(name string) (dir *Dir, err Error) { - var stat syscall.Stat_t; - e := syscall.Lstat(name, &stat); - if e != 0 { - return nil, ErrnoToError(e) - } - return dirFromStat(name, new(Dir), &stat, &stat), nil -} - -// Readdirnames has a non-portable implemenation so its code is separated into an -// operating-system-dependent file. -func readdirnames(file *File, count int) (names []string, err Error) - -// Readdirnames reads the contents of the directory associated with file and -// returns an array of up to count names, in directory order. Subsequent -// calls on the same file will yield further names. -// A negative count means to read until EOF. -// Readdirnames returns the array and an Error, if any. -func (file *File) Readdirnames(count int) (names []string, err Error) { - return readdirnames(file, count); -} - -// Readdir reads the contents of the directory associated with file and -// returns an array of up to count Dir structures, as would be returned -// by Stat, in directory order. Subsequent calls on the same file will yield further Dirs. -// A negative count means to read until EOF. -// Readdir returns the array and an Error, if any. -func (file *File) Readdir(count int) (dirs []Dir, err Error) { - dirname := file.name; - if dirname == "" { - dirname = "."; - } - dirname += "/"; - names, err1 := file.Readdirnames(count); - if err1 != nil { - return nil, err1 - } - dirs = make([]Dir, len(names)); - for i, filename := range names { - dirp, err := Stat(dirname + filename); - if dirp == nil || err != nil { - dirs[i].Name = filename // rest is already zeroed out - } else { - dirs[i] = *dirp - } - } - return -} - -// Chdir changes the current working directory to the named directory. -func Chdir(dir string) Error { - return ErrnoToError(syscall.Chdir(dir)); -} - -// Chdir changes the current working directory to the file, -// which must be a directory. -func (f *File) Chdir() Error { - return ErrnoToError(syscall.Fchdir(f.fd)); -} - -// Remove removes the named file or directory. -func Remove(name string) Error { - // System call interface forces us to know - // whether name is a file or directory. - // Try both: it is cheaper on average than - // doing a Stat plus the right one. - e := syscall.Unlink(name); - if e == 0 { - return nil; - } - e1 := syscall.Rmdir(name); - if e1 == 0 { - return nil; - } - - // Both failed: figure out which error to return. - // OS X and Linux differ on whether unlink(dir) - // returns EISDIR, so can't use that. However, - // both agree that rmdir(file) returns ENOTDIR, - // so we can use that to decide which error is real. - // Rmdir might also return ENOTDIR if given a bad - // file path, like /etc/passwd/foo, but in that case, - // both errors will be ENOTDIR, so it's okay to - // use the error from unlink. - if e1 != syscall.ENOTDIR { - e = e1; - } - return ErrnoToError(e); -} - -// Link creates a hard link. -func Link(oldname, newname string) Error { - return ErrnoToError(syscall.Link(oldname, newname)); -} - -// Symlink creates a symbolic link. -func Symlink(oldname, newname string) Error { - return ErrnoToError(syscall.Symlink(oldname, newname)); -} - -// Readlink reads the contents of a symbolic link: the destination of -// the link. It returns the contents and an Error, if any. -func Readlink(name string) (string, Error) { - for len := 128; ; len *= 2 { - b := make([]byte, len); - n, e := syscall.Readlink(name, b); - if e != 0 { - return "", ErrnoToError(e); - } - if n < len { - return string(b[0:n]), nil; - } - } - // Silence 6g. - return "", nil; -} - -// Chmod changes the mode of the named file to mode. -// If the file is a symbolic link, it changes the uid and gid of the link's target. -func Chmod(name string, mode int) Error { - return ErrnoToError(syscall.Chmod(name, mode)); -} - -// Chmod changes the mode of the file to mode. -func (f *File) Chmod(mode int) Error { - return ErrnoToError(syscall.Fchmod(f.fd, mode)); -} - -// 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 { - return ErrnoToError(syscall.Chown(name, uid, gid)); -} - -// 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 { - return ErrnoToError(syscall.Lchown(name, uid, gid)); -} - -// Chown changes the numeric uid and gid of the named file. -func (f *File) Chown(uid, gid int) Error { - return ErrnoToError(syscall.Fchown(f.fd, uid, gid)); -} - -// 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 { - return ErrnoToError(syscall.Truncate(name, size)); -} - -// Truncate changes the size of the file. -// It does not change the I/O offset. -func (f *File) Truncate(size int64) Error { - return ErrnoToError(syscall.Ftruncate(f.fd, size)); -} - diff --git a/src/lib/os/getwd.go b/src/lib/os/getwd.go deleted file mode 100644 index 2d7b754b5..000000000 --- a/src/lib/os/getwd.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2009 The Go Authors. 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 ( - "os"; - "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, ErrnoToError(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. - elem := make([]string, 0, 16); - pwd = ""; - for parent := "..";; parent = "../" + parent { - if len(parent) >= 1024 { // Sanity check - return "", ENAMETOOLONG; - } - fd, err := Open(parent, O_RDONLY, 0); - if err != nil { - return "", err; - } - - for { - names, err := fd.Readdirnames(100); - if err != nil { - fd.Close(); - return "", err; - } - for i, name := range names { - d, err := 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/lib/os/os_test.go b/src/lib/os/os_test.go deleted file mode 100644 index 9f3e833f3..000000000 --- a/src/lib/os/os_test.go +++ /dev/null @@ -1,549 +0,0 @@ -// Copyright 2009 The Go Authors. 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 ( - "fmt"; - "io"; - "os"; - "testing"; -) - -var dot = []string{ - "dir_darwin_amd64.go", - "dir_linux_amd64.go", - "env.go", - "error.go", - "file.go", - "os_test.go", - "time.go", - "types.go", - "stat_darwin_amd64.go", - "stat_linux_amd64.go" -} - -var etc = []string{ - "group", - "hosts", - "passwd", -} - -func size(name string, t *testing.T) uint64 { - file, err := Open(name, O_RDONLY, 0); - defer file.Close(); - if err != nil { - t.Fatal("open failed:", err); - } - var buf [100]byte; - len := 0; - for { - n, e := file.Read(&buf); - if n < 0 || e != nil { - t.Fatal("read failed:", err); - } - if n == 0 { - break - } - len += n; - } - return uint64(len) -} - -func TestStat(t *testing.T) { - dir, err := Stat("/etc/passwd"); - if err != nil { - t.Fatal("stat failed:", err); - } - if dir.Name != "passwd" { - t.Error("name should be passwd; is", dir.Name); - } - filesize := size("/etc/passwd", t); - if dir.Size != filesize { - t.Error("size should be ", filesize, "; is", dir.Size); - } -} - -func TestFstat(t *testing.T) { - file, err1 := Open("/etc/passwd", O_RDONLY, 0); - defer file.Close(); - if err1 != nil { - t.Fatal("open failed:", err1); - } - dir, err2 := file.Stat(); - if err2 != nil { - t.Fatal("fstat failed:", err2); - } - if dir.Name != "passwd" { - t.Error("name should be passwd; is", dir.Name); - } - filesize := size("/etc/passwd", t); - if dir.Size != filesize { - t.Error("size should be ", filesize, "; is", dir.Size); - } -} - -func TestLstat(t *testing.T) { - dir, err := Lstat("/etc/passwd"); - if err != nil { - t.Fatal("lstat failed:", err); - } - if dir.Name != "passwd" { - t.Error("name should be passwd; is", dir.Name); - } - filesize := size("/etc/passwd", t); - if dir.Size != filesize { - t.Error("size should be ", filesize, "; is", dir.Size); - } -} - -func testReaddirnames(dir string, contents []string, t *testing.T) { - file, err := Open(dir, O_RDONLY, 0); - defer file.Close(); - if err != nil { - t.Fatalf("open %q failed: %v", dir, err); - } - s, err2 := file.Readdirnames(-1); - if err2 != nil { - t.Fatalf("readdirnames %q failed: %v", err2); - } - for i, m := range contents { - found := false; - for j, n := range s { - if n == "." || n == ".." { - t.Errorf("got %s in directory", n); - } - if m == n { - if found { - t.Error("present twice:", m); - } - found = true - } - } - if !found { - t.Error("could not find", m); - } - } -} - -func testReaddir(dir string, contents []string, t *testing.T) { - file, err := Open(dir, O_RDONLY, 0); - defer file.Close(); - if err != nil { - t.Fatalf("open %q failed: %v", dir, err); - } - s, err2 := file.Readdir(-1); - if err2 != nil { - t.Fatalf("readdir %q failed: %v", dir, err2); - } - for i, m := range contents { - found := false; - for j, n := range s { - if 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("/etc", etc, t); -} - -func TestReaddir(t *testing.T) { - testReaddir(".", dot, t); - testReaddir("/etc", etc, t); -} - -// Read the directory one entry at a time. -func smallReaddirnames(file *File, length int, t *testing.T) []string { - names := make([]string, length); - count := 0; - for { - d, err := file.Readdirnames(1); - if err != nil { - t.Fatalf("readdir %q failed: %v", file.Name(), err); - } - if len(d) == 0 { - break - } - names[count] = d[0]; - count++; - } - return names[0:count] -} - -// Check that reading a directory one entry at a time gives the same result -// as reading it all at once. -func TestReaddirnamesOneAtATime(t *testing.T) { - dir := "/usr/bin"; // big directory that doesn't change often. - file, err := Open(dir, O_RDONLY, 0); - defer file.Close(); - if err != nil { - t.Fatalf("open %q failed: %v", dir, err); - } - all, err1 := file.Readdirnames(-1); - if err1 != nil { - t.Fatalf("readdirnames %q failed: %v", dir, err1); - } - file1, err2 := Open(dir, O_RDONLY, 0); - if err2 != nil { - t.Fatalf("open %q failed: %v", dir, err2); - } - small := smallReaddirnames(file1, len(all)+100, t); // +100 in case we screw up - for i, n := range all { - if small[i] != n { - t.Errorf("small read %q %q mismatch: %v", small[i], n); - } - } -} - -func TestHardLink(t *testing.T) { - from, to := "hardlinktestfrom", "hardlinktestto"; - Remove(from); // Just in case. - file, err := Open(to, O_CREAT | O_WRONLY, 0666); - if err != nil { - t.Fatalf("open %q failed: %v", to, err); - } - defer Remove(to); - if err = file.Close(); err != nil { - t.Errorf("close %q failed: %v", to, err); - } - err = Link(to, from); - if err != nil { - t.Fatalf("link %q, %q failed: %v", to, from, err); - } - defer Remove(from); - tostat, err := Stat(to); - if err != nil { - t.Fatalf("stat %q failed: %v", to, err); - } - fromstat, err := Stat(from); - if err != nil { - t.Fatalf("stat %q failed: %v", from, err); - } - if tostat.Dev != fromstat.Dev || tostat.Ino != fromstat.Ino { - t.Errorf("link %q, %q did not create hard link", to, from); - } -} - -func TestSymLink(t *testing.T) { - from, to := "symlinktestfrom", "symlinktestto"; - Remove(from); // Just in case. - file, err := Open(to, O_CREAT | O_WRONLY, 0666); - if err != nil { - t.Fatalf("open %q failed: %v", to, err); - } - defer Remove(to); - if err = file.Close(); err != nil { - t.Errorf("close %q failed: %v", to, err); - } - err = Symlink(to, from); - if err != nil { - t.Fatalf("symlink %q, %q failed: %v", to, from, err); - } - defer Remove(from); - tostat, err := Stat(to); - if err != nil { - t.Fatalf("stat %q failed: %v", to, err); - } - if tostat.FollowedSymlink { - t.Fatalf("stat %q claims to have followed a symlink", to); - } - fromstat, err := Stat(from); - if err != nil { - t.Fatalf("stat %q failed: %v", from, err); - } - if tostat.Dev != fromstat.Dev || tostat.Ino != fromstat.Ino { - t.Errorf("symlink %q, %q did not create symlink", to, from); - } - fromstat, err = Lstat(from); - if err != nil { - t.Fatalf("lstat %q failed: %v", from, err); - } - if !fromstat.IsSymlink() { - t.Fatalf("symlink %q, %q did not create symlink", to, from); - } - fromstat, err = Stat(from); - if err != nil { - t.Fatalf("stat %q failed: %v", from, err); - } - if !fromstat.FollowedSymlink { - t.Fatalf("stat %q did not follow symlink"); - } - s, err := Readlink(from); - if err != nil { - t.Fatalf("readlink %q failed: %v", from, err); - } - if s != to { - t.Fatalf("after symlink %q != %q", s, to); - } - file, err = Open(from, O_RDONLY, 0); - if err != nil { - t.Fatalf("open %q failed: %v", from, err); - } - file.Close(); -} - -func TestLongSymlink(t *testing.T) { - s := "0123456789abcdef"; - s = s + s + s + s + s + s + s + s + s + s + s + s + s + s + s + s + s; - from := "longsymlinktestfrom"; - 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 TestForkExec(t *testing.T) { - r, w, err := Pipe(); - if err != nil { - t.Fatalf("Pipe: %v", err); - } - pid, err := ForkExec("/bin/pwd", []string{"pwd"}, nil, "/", []*File{nil, w, Stderr}); - if err != nil { - t.Fatalf("ForkExec: %v", err); - } - w.Close(); - - var b io.ByteBuffer; - io.Copy(r, &b); - output := string(b.Data()); - expect := "/\n"; - if output != expect { - t.Errorf("exec /bin/pwd returned %q wanted %q", output, expect); - } - Wait(pid, 0); -} - -func checkMode(t *testing.T, path string, mode uint32) { - dir, err := Stat(path); - if err != nil { - t.Fatalf("Stat %q (looking for mode %#o): %s", path, mode, err); - } - if dir.Mode & 0777 != mode { - t.Errorf("Stat %q: mode %#o want %#o", path, dir.Mode, 0777); - } -} - -func TestChmod(t *testing.T) { - MkdirAll("_obj", 0777); - const Path = "_obj/_TestChmod_"; - fd, err := Open(Path, O_WRONLY | O_CREAT, 0666); - if err != nil { - t.Fatalf("create %s: %s", Path, err); - } - - if err = Chmod(Path, 0456); err != nil { - t.Fatalf("chmod %s 0456: %s", Path, err); - } - checkMode(t, Path, 0456); - - if err = fd.Chmod(0123); err != nil { - t.Fatalf("fchmod %s 0123: %s", Path, err); - } - checkMode(t, Path, 0123); - - fd.Close(); - Remove(Path); -} - -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 %#o/%#o): %s", path, uid, gid, err); - } - if dir.Uid != uint32(uid) { - t.Errorf("Stat %q: uid %#o want %#o", path, dir.Uid, uid); - } - if dir.Gid != uint32(gid) { - t.Errorf("Stat %q: gid %#o want %#o", path, dir.Gid, uid); - } -} - -func TestChown(t *testing.T) { - // Use /tmp, not _obj, to make sure we're on a local file system, - // so that the group ids returned by Getgroups will be allowed - // on the file. If _obj is on NFS, the Getgroups groups are - // basically useless. - - const Path = "/tmp/_TestChown_"; - fd, err := Open(Path, O_WRONLY | O_CREAT, 0666); - if err != nil { - t.Fatalf("create %s: %s", Path, err); - } - dir, err := fd.Stat(); - if err != nil { - t.Fatalf("fstat %s: %s", Path, err); - } - defer fd.Close(); - defer Remove(Path); - - // Can't change uid unless root, but can try - // changing the group id. First try our current group. - gid := Getgid(); - if err = Chown(Path, -1, gid); err != nil { - t.Fatalf("chown %s -1 %d: %s", Path, gid, err); - } - checkUidGid(t, Path, int(dir.Uid), gid); - - // Then try all the auxiliary groups. - groups, err := Getgroups(); - if err != nil { - t.Fatalf("getgroups: %s", err); - } - for i, g := range groups { - if err = Chown(Path, -1, g); err != nil { - t.Fatalf("chown %s -1 %d: %s", Path, g, err); - } - checkUidGid(t, Path, int(dir.Uid), g); - - // change back to gid to test fd.Chown - if err = fd.Chown(-1, gid); err != nil { - t.Fatalf("fchown %s -1 %d: %s", Path, gid, err); - } - checkUidGid(t, Path, int(dir.Uid), gid); - } -} - -func checkSize(t *testing.T, path string, size uint64) { - dir, err := 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 TestTruncate(t *testing.T) { - MkdirAll("_obj", 0777); - const Path = "_obj/_TestTruncate_"; - fd, err := Open(Path, O_WRONLY | O_CREAT, 0666); - if err != nil { - t.Fatalf("create %s: %s", Path, err); - } - - checkSize(t, Path, 0); - fd.Write(io.StringBytes("hello, world\n")); - checkSize(t, Path, 13); - fd.Truncate(10); - checkSize(t, Path, 10); - fd.Truncate(1024); - checkSize(t, Path, 1024); - fd.Truncate(0); - checkSize(t, Path, 0); - fd.Write(io.StringBytes("surprise!")); - checkSize(t, Path, 13 + 9); // wrote at offset past where hello, world was. - fd.Close(); - Remove(Path); -} - -func TestChdirAndGetwd(t *testing.T) { - fd, err := Open(".", O_RDONLY, 0); - if err != nil { - t.Fatalf("Open .: %s", err); - } - // These are chosen carefully not to be symlinks on a Mac - // (unlike, say, /var, /etc, and /tmp). - dirs := []string{ "/bin", "/", "/usr/local/bin" }; - for mode := 0; mode < 2; mode++ { - for i, d := range dirs { - if mode == 0 { - err = Chdir(d); - } else { - fd1, err := Open(d, O_RDONLY, 0); - if err != nil { - t.Errorf("Open %s: %s", d, err); - continue; - } - err = fd1.Chdir(); - fd1.Close(); - } - pwd, err1 := Getwd(); - err2 := fd.Chdir(); - if err2 != nil { - // We changed the current directory and cannot go back. - // Don't let the tests continue; they'll scribble - // all over some other directory. - fmt.Fprintf(Stderr, "fchdir back to dot failed: %s\n", err2); - Exit(1); - } - if err != nil { - fd.Close(); - t.Fatalf("Chdir %s: %s", d, err); - } - if err1 != nil { - fd.Close(); - t.Fatalf("Getwd in %s: %s", d, err1); - } - if pwd != d { - fd.Close(); - t.Fatalf("Getwd returned %q want %q", pwd, d); - } - } - } - fd.Close(); -} - -func TestTime(t *testing.T) { - // Just want to check that Time() is getting something. - // A common failure mode on Darwin is to get 0, 0, - // because it returns the time in registers instead of - // filling in the structure passed to the system call. - // TODO(rsc): 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, err := Open("_obj/seektest", O_CREAT|O_RDWR|O_TRUNC, 0666); - if err != nil { - t.Fatalf("open _obj/seektest: %s", err); - } - - const data = "hello, world\n"; - io.WriteString(f, data); - - type test struct { - in int64; - whence int; - out int64; - } - var tests = []test { - test{ 0, 1, int64(len(data)) }, - test{ 0, 0, 0 }, - test{ 5, 0, 5 }, - test{ 0, 2, int64(len(data)) }, - test{ 0, 0, 0 }, - test{ -1, 2, int64(len(data)) - 1 }, - test{ 1<<40, 0, 1<<40 }, - test{ 1<<40, 2, 1<<40 + int64(len(data)) } - }; - for i, tt := range tests { - off, err := f.Seek(tt.in, tt.whence); - if off != tt.out || err != nil { - t.Errorf("#%d: Seek(%v, %v) = %v, %v want %v, nil", i, tt.in, tt.whence, off, err, tt.out); - } - } - f.Close(); -} diff --git a/src/lib/os/path.go b/src/lib/os/path.go deleted file mode 100644 index 0b86b8f8b..000000000 --- a/src/lib/os/path.go +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package os - -import "os" - -// PathError reports an error and the file path where it occurred. -type PathError struct { - Path string; - Error Error; -} - -func (p *PathError) String() string { - return p.Path + ": " + p.Error.String(); -} - -// 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 int) Error { - // If path exists, stop with success or error. - dir, err := os.Lstat(path); - if err == nil { - if dir.IsDirectory() { - return nil; - } - return &PathError{path, ENOTDIR}; - } - - // Doesn't already exist; make sure parent does. - i := len(path); - for i > 0 && path[i-1] == '/' { // Skip trailing slashes. - i--; - } - - j := i; - for j > 0 && path[j-1] != '/' { // Scan backward over element. - j--; - } - - if j > 0 { - // Create parent - err = MkdirAll(path[0:j-1], perm); - if err != nil { - return err; - } - } - - // Now parent exists, try to create. - err = Mkdir(path, perm); - if err != nil { - // Handle arguments like "foo/." by - // double-checking that directory doesn't exist. - dir, err1 := os.Lstat(path); - if err1 == nil && dir.IsDirectory() { - return nil; - } - return &PathError{path, err}; - } - return nil; -} - -// RemoveAll removes path and any children it contains. -// It removes everything it can but returns the first error -// it encounters. -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, err1 := os.Lstat(path); - if err1 != nil { - return &PathError{path, err1}; - } - if !dir.IsDirectory() { - // Not a directory; return the error from Remove. - return &PathError{path, err}; - } - - // Directory. - fd, err := Open(path, os.O_RDONLY, 0); - if err != nil { - return &PathError{path, err}; - } - defer fd.Close(); - - // Remove contents & return first error. - err = nil; - for { - names, err1 := fd.Readdirnames(100); - for i, name := range names { - err1 := RemoveAll(path + "/" + name); - if err1 != nil && err == nil { - err = err1; - } - } - // If Readdirnames returned an error, use it. - if err1 != nil && err == nil { - err = &PathError{path, err1}; - } - if len(names) == 0 { - break; - } - } - - // Remove directory. - err1 = Remove(path); - if err1 != nil && err == nil { - err = &PathError{path, err1}; - } - return err; -} diff --git a/src/lib/os/path_test.go b/src/lib/os/path_test.go deleted file mode 100644 index bb6148920..000000000 --- a/src/lib/os/path_test.go +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2009 The Go Authors. 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 ( - "os"; - "testing"; -) - -func TestMkdirAll(t *testing.T) { - // Create new dir, in _obj so it will get - // cleaned up by make if not by us. - path := "_obj/_TestMkdirAll_/dir/./dir2"; - err := MkdirAll(path, 0777); - if err != nil { - t.Fatalf("MkdirAll %q: %s", path, err); - } - - // 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"; - fd, err := os.Open(fpath, os.O_WRONLY | os.O_CREAT, 0666); - if err != nil { - t.Fatalf("create %q: %s", fpath, err); - } - - // Can't make directory named after file. - err = MkdirAll(fpath, 0777); - if err == nil { - t.Fatalf("MkdirAll %q: no error"); - } - perr, ok := err.(*PathError); - if !ok { - t.Fatalf("MkdirAll %q returned %T, not *PathError", fpath, err); - } - if perr.Path != fpath { - t.Fatalf("MkdirAll %q returned wrong error path: %q not %q", fpath, perr.Path, fpath); - } - - // Can't make subdirectory of file. - ffpath := fpath + "/subdir"; - err = MkdirAll(ffpath, 0777); - if err == nil { - t.Fatalf("MkdirAll %q: no error"); - } - perr, ok = err.(*PathError); - if !ok { - t.Fatalf("MkdirAll %q returned %T, not *PathError", ffpath, err); - } - if perr.Path != fpath { - t.Fatalf("MkdirAll %q returned wrong error path: %q not %q", ffpath, perr.Path, fpath); - } - - RemoveAll("_obj/_TestMkdirAll_"); -} - -func TestRemoveAll(t *testing.T) { - // Work directory. - path := "_obj/_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 := os.Open(fpath, os.O_WRONLY | os.O_CREAT, 0666); - if err != nil { - t.Fatalf("create %q: %s", fpath, err); - } - fd.Close(); - if err = RemoveAll(path); err != nil { - t.Fatalf("RemoveAll %q (first): %s", path, err); - } - if dir, err := os.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 = os.Open(fpath, os.O_WRONLY | os.O_CREAT, 0666); - if err != nil { - t.Fatalf("create %q: %s", fpath, err); - } - fd.Close(); - fd, err = os.Open(dpath+"/file", os.O_WRONLY | os.O_CREAT, 0666); - if err != nil { - t.Fatalf("create %q: %s", fpath, err); - } - fd.Close(); - if err = RemoveAll(path); err != nil { - t.Fatalf("RemoveAll %q (second): %s", path, err); - } - if dir, err := os.Lstat(path); err == nil { - t.Fatalf("Lstat %q succeeded after RemoveAll (second)", path); - } - - // Make directory with file and subdirectory and trigger error. - if err = MkdirAll(dpath, 0777); err != nil { - t.Fatalf("MkdirAll %q: %s", dpath, err); - } - - // TODO(rsc): toss tmp once bug152 is fixed - tmp := []string{fpath, dpath+"/file1", path+"/zzz"}; - for i, s := range tmp { - fd, err = os.Open(s, os.O_WRONLY | os.O_CREAT, 0666); - if err != nil { - t.Fatalf("create %q: %s", s, err); - } - fd.Close(); - } - if err = os.Chmod(dpath, 0); err != nil { - t.Fatalf("Chmod %q 0: %s", dpath, err); - } - if err = RemoveAll(path); err == nil { - dir, err := Lstat(path); - if err == nil { - t.Errorf("Can lstat %q after supposed RemoveAll", path); - } - t.Fatalf("RemoveAll %q succeeded with chmod 0 subdirectory", path, err); - } - perr, ok := err.(*PathError); - if !ok { - t.Fatalf("RemoveAll %q returned %T not *PathError", path, err); - } - if perr.Path != dpath { - t.Fatalf("RemoveAll %q failed at %q not %q", path, perr.Path, dpath); - } - if err = os.Chmod(dpath, 0777); err != nil { - t.Fatalf("Chmod %q 0777: %s", dpath, err); - } - for i, s := range []string{fpath, path+"/zzz"} { - if dir, err := os.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 dir, err := os.Lstat(path); err == nil { - t.Fatalf("Lstat %q succeeded after RemoveAll (final)", path); - } -} diff --git a/src/lib/os/proc.go b/src/lib/os/proc.go deleted file mode 100644 index d2fd6493e..000000000 --- a/src/lib/os/proc.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Process etc. - -package os - -import ( - "syscall"; - "os"; - "unsafe"; -) - -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, os.Error) { - gids, errno := syscall.Getgroups(); - return gids, ErrnoToError(errno); -} - -// Exit causes the current program to exit with the given status code. -// Conventionally, code zero indicates success, non-zero an error. -func Exit(code int) { - syscall.Exit(code); -} - diff --git a/src/lib/os/proc_linux.go b/src/lib/os/proc_linux.go deleted file mode 100644 index a802284f3..000000000 --- a/src/lib/os/proc_linux.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package os - -import ( - "os"; - "syscall"; -) - -var Args []string; // provided by runtime -var Envs []string; // provided by runtime - -// 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.Syscall(syscall.SYS_EXIT_GROUP, int64(code), 0, 0) -} - diff --git a/src/lib/os/stat_darwin_386.go b/src/lib/os/stat_darwin_386.go deleted file mode 100644 index a6d7b78d1..000000000 --- a/src/lib/os/stat_darwin_386.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// 386, Darwin - -package os - -import syscall "syscall" -import os "os" - -func isSymlink(stat *syscall.Stat_t) bool { - return stat.Mode & syscall.S_IFMT == syscall.S_IFLNK -} - -func dirFromStat(name string, dir *Dir, lstat, stat *syscall.Stat_t) *Dir { - dir.Dev = uint64(stat.Dev); - dir.Ino = stat.Ino; - dir.Nlink = uint64(stat.Nlink); - dir.Mode = uint32(stat.Mode); - dir.Uid = stat.Uid; - dir.Gid = stat.Gid; - dir.Rdev = uint64(stat.Rdev); - dir.Size = uint64(stat.Size); - dir.Blksize = uint64(stat.Blksize); - dir.Blocks = uint64(stat.Blocks); - dir.Atime_ns = uint64(syscall.TimespecToNsec(stat.Atimespec)); - dir.Mtime_ns = uint64(syscall.TimespecToNsec(stat.Mtimespec)); - dir.Ctime_ns = uint64(syscall.TimespecToNsec(stat.Ctimespec)); - for i := len(name) - 1; i >= 0; i-- { - if name[i] == '/' { - name = name[i+1:len(name)]; - break; - } - } - dir.Name = name; - if isSymlink(lstat) && !isSymlink(stat) { - dir.FollowedSymlink = true; - } - return dir; -} diff --git a/src/lib/os/stat_darwin_amd64.go b/src/lib/os/stat_darwin_amd64.go deleted file mode 100644 index 1771ca160..000000000 --- a/src/lib/os/stat_darwin_amd64.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// AMD64, Darwin - -package os - -import syscall "syscall" -import os "os" - -func isSymlink(stat *syscall.Stat_t) bool { - return stat.Mode & syscall.S_IFMT == syscall.S_IFLNK -} - -func dirFromStat(name string, dir *Dir, lstat, stat *syscall.Stat_t) *Dir { - dir.Dev = uint64(stat.Dev); - dir.Ino = stat.Ino; - dir.Nlink = uint64(stat.Nlink); - dir.Mode = uint32(stat.Mode); - dir.Uid = stat.Uid; - dir.Gid = stat.Gid; - dir.Rdev = uint64(stat.Rdev); - dir.Size = uint64(stat.Size); - dir.Blksize = uint64(stat.Blksize); - dir.Blocks = uint64(stat.Blocks); - dir.Atime_ns = uint64(syscall.TimespecToNsec(stat.Atimespec)); - dir.Mtime_ns = uint64(syscall.TimespecToNsec(stat.Mtimespec)); - dir.Ctime_ns = uint64(syscall.TimespecToNsec(stat.Ctimespec)); - for i := len(name) - 1; i >= 0; i-- { - if name[i] == '/' { - name = name[i+1:len(name)]; - break; - } - } - dir.Name = name; - if isSymlink(lstat) && !isSymlink(stat) { - dir.FollowedSymlink = true; - } - return dir; -} diff --git a/src/lib/os/stat_linux_386.go b/src/lib/os/stat_linux_386.go deleted file mode 100644 index 13ee942c9..000000000 --- a/src/lib/os/stat_linux_386.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2009 The Go 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 the porting dust settles, consider -// whether this file should be stat_linux.go (and similarly -// stat_darwin.go) instead of having one copy per architecture. - -// 386, Linux - -package os - -import ( - "os"; - "syscall"; -) - -func isSymlink(stat *syscall.Stat_t) bool { - return stat.Mode & syscall.S_IFMT == syscall.S_IFLNK -} - -func dirFromStat(name string, dir *Dir, lstat, stat *syscall.Stat_t) *Dir { - dir.Dev = stat.Dev; - dir.Ino = uint64(stat.Ino); - dir.Nlink = uint64(stat.Nlink); - dir.Mode = stat.Mode; - dir.Uid = stat.Uid; - dir.Gid = stat.Gid; - dir.Rdev = stat.Rdev; - dir.Size = uint64(stat.Size); - dir.Blksize = uint64(stat.Blksize); - dir.Blocks = uint64(stat.Blocks); - dir.Atime_ns = uint64(syscall.TimespecToNsec(stat.Atim)); - dir.Mtime_ns = uint64(syscall.TimespecToNsec(stat.Mtim)); - dir.Ctime_ns = uint64(syscall.TimespecToNsec(stat.Ctim)); - for i := len(name) - 1; i >= 0; i-- { - if name[i] == '/' { - name = name[i+1:len(name)]; - break; - } - } - dir.Name = name; - if isSymlink(lstat) && !isSymlink(stat) { - dir.FollowedSymlink = true; - } - return dir; -} diff --git a/src/lib/os/stat_linux_amd64.go b/src/lib/os/stat_linux_amd64.go deleted file mode 100644 index 9b3018178..000000000 --- a/src/lib/os/stat_linux_amd64.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// AMD64, Linux - -package os - -import syscall "syscall" -import os "os" - -func isSymlink(stat *syscall.Stat_t) bool { - return stat.Mode & syscall.S_IFMT == syscall.S_IFLNK -} - -func dirFromStat(name string, dir *Dir, lstat, stat *syscall.Stat_t) *Dir { - dir.Dev = stat.Dev; - dir.Ino = stat.Ino; - dir.Nlink = stat.Nlink; - dir.Mode = stat.Mode; - dir.Uid = stat.Uid; - dir.Gid = stat.Gid; - dir.Rdev = stat.Rdev; - dir.Size = uint64(stat.Size); - dir.Blksize = uint64(stat.Blksize); - dir.Blocks = uint64(stat.Blocks); - dir.Atime_ns = uint64(syscall.TimespecToNsec(stat.Atim)); - dir.Mtime_ns = uint64(syscall.TimespecToNsec(stat.Mtim)); - dir.Ctime_ns = uint64(syscall.TimespecToNsec(stat.Ctim)); - for i := len(name) - 1; i >= 0; i-- { - if name[i] == '/' { - name = name[i+1:len(name)]; - break; - } - } - dir.Name = name; - if isSymlink(lstat) && !isSymlink(stat) { - dir.FollowedSymlink = true; - } - return dir; -} diff --git a/src/lib/os/time.go b/src/lib/os/time.go deleted file mode 100644 index 3eee243cc..000000000 --- a/src/lib/os/time.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package os - -import ( - "os"; - "syscall" -) - - -// Time returns the current time, in whole seconds and -// fractional nanoseconds, plus an Error if any. The current -// time is thus 1e9*sec+nsec, in nanoseconds. The zero of -// time is the Unix epoch. -func Time() (sec int64, nsec int64, err Error) { - var tv syscall.Timeval; - if errno := syscall.Gettimeofday(&tv); errno != 0 { - return 0, 0, ErrnoToError(errno) - } - return int64(tv.Sec), int64(tv.Usec)*1000, err; -} - diff --git a/src/lib/os/types.go b/src/lib/os/types.go deleted file mode 100644 index b5db86660..000000000 --- a/src/lib/os/types.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package 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 Dir describes a file and is returned by Stat, Fstat, and Lstat -type Dir 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 uint32; // user id of owner. - Gid uint32; // group id of owner. - Rdev uint64; // device type for special file. - Size uint64; // length in bytes. - Blksize uint64; // size of blocks, in bytes. - Blocks uint64; // number of blocks allocated for file. - Atime_ns uint64; // access time; nanoseconds since epoch. - Mtime_ns uint64; // modified time; nanoseconds since epoch. - Ctime_ns uint64; // status change time; nanoseconds since epoch. - Name string; // name of file as presented to Open. - FollowedSymlink bool; // followed a symlink to get this information -} - -// IsFifo reports whether the Dir describes a FIFO file. -func (dir *Dir) IsFifo() bool { - return (dir.Mode & syscall.S_IFMT) == syscall.S_IFIFO -} - -// IsChar reports whether the Dir describes a character special file. -func (dir *Dir) IsChar() bool { - return (dir.Mode & syscall.S_IFMT) == syscall.S_IFCHR -} - -// IsDirectory reports whether the Dir describes a directory. -func (dir *Dir) IsDirectory() bool { - return (dir.Mode & syscall.S_IFMT) == syscall.S_IFDIR -} - -// IsBlock reports whether the Dir describes a block special file. -func (dir *Dir) IsBlock() bool { - return (dir.Mode & syscall.S_IFMT) == syscall.S_IFBLK -} - -// IsRegular reports whether the Dir describes a regular file. -func (dir *Dir) IsRegular() bool { - return (dir.Mode & syscall.S_IFMT) == syscall.S_IFREG -} - -// IsSymlink reports whether the Dir describes a symbolic link. -func (dir *Dir) IsSymlink() bool { - return (dir.Mode & syscall.S_IFMT) == syscall.S_IFLNK -} - -// IsSocket reports whether the Dir describes a socket. -func (dir *Dir) IsSocket() bool { - return (dir.Mode & syscall.S_IFMT) == syscall.S_IFSOCK -} - -// Permission returns the file permission bits. -func (dir *Dir) Permission() int { - return int(dir.Mode & 0777) -} - diff --git a/src/lib/path/Makefile b/src/lib/path/Makefile deleted file mode 100644 index d9f9fd562..000000000 --- a/src/lib/path/Makefile +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m >Makefile - -D= - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - path.$O\ - - -phases: a1 -_obj$D/path.a: phases - -a1: $(O1) - $(AR) grc _obj$D/path.a path.$O - rm -f $(O1) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/path.a - -$(O1): newpkg -$(O2): a1 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/path.a - -packages: _obj$D/path.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/path.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/path.a diff --git a/src/lib/path/path.go b/src/lib/path/path.go deleted file mode 100644 index a7e2c26c3..000000000 --- a/src/lib/path/path.go +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// The path package implements utility routines for manipulating -// slash-separated filename paths. -package path - -import "io" - -// 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 := io.StringBytes(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 slash, -// separating it into a directory and file name component. -// If there is no slash in path, DirFile returns an empty dir and -// file set to path. -func Split(path string) (dir, file string) { - for i := len(path)-1; i >= 0; i-- { - if path[i] == '/' { - return path[0:i+1], path[i+1:len(path)]; - } - } - return "", path -} - -// Join joins dir and file into a single path, adding a separating -// slash if necessary. If dir is empty, it returns file. -func Join(dir, file string) string { - if dir == "" { - return file; - } - return Clean(dir + "/" + file); -} - -// 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 { - dot := -1; - for i := len(path)-1; i >= 0 && path[i] != '/'; i-- { - if path[i] == '.' { - return path[i:len(path)]; - } - } - return "" -} - diff --git a/src/lib/path/path_test.go b/src/lib/path/path_test.go deleted file mode 100644 index 1238ac1cd..000000000 --- a/src/lib/path/path_test.go +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright 2009 The Go Authors. 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 ( - "path"; - "testing" -) - -type CleanTest struct { - path, clean string -} - -var cleantests = []CleanTest { - // Already clean - CleanTest{"", "."}, - CleanTest{"abc", "abc"}, - CleanTest{"abc/def", "abc/def"}, - CleanTest{"a/b/c", "a/b/c"}, - CleanTest{".", "."}, - CleanTest{"..", ".."}, - CleanTest{"../..", "../.."}, - CleanTest{"../../abc", "../../abc"}, - CleanTest{"/abc", "/abc"}, - CleanTest{"/", "/"}, - - // Remove trailing slash - CleanTest{"abc/", "abc"}, - CleanTest{"abc/def/", "abc/def"}, - CleanTest{"a/b/c/", "a/b/c"}, - CleanTest{"./", "."}, - CleanTest{"../", ".."}, - CleanTest{"../../", "../.."}, - CleanTest{"/abc/", "/abc"}, - - // Remove doubled slash - CleanTest{"abc//def//ghi", "abc/def/ghi"}, - CleanTest{"//abc", "/abc"}, - CleanTest{"///abc", "/abc"}, - CleanTest{"//abc//", "/abc"}, - CleanTest{"abc//", "abc"}, - - // Remove . elements - CleanTest{"abc/./def", "abc/def"}, - CleanTest{"/./abc/def", "/abc/def"}, - CleanTest{"abc/.", "abc"}, - - // Remove .. elements - CleanTest{"abc/def/ghi/../jkl", "abc/def/jkl"}, - CleanTest{"abc/def/../ghi/../jkl", "abc/jkl"}, - CleanTest{"abc/def/..", "abc"}, - CleanTest{"abc/def/../..", "."}, - CleanTest{"/abc/def/../..", "/"}, - CleanTest{"abc/def/../../..", ".."}, - CleanTest{"/abc/def/../../..", "/"}, - CleanTest{"abc/def/../../../ghi/jkl/../../../mno", "../../mno"}, - - // Combinations - CleanTest{"abc/./../def", "def"}, - CleanTest{"abc//./../def", "def"}, - CleanTest{"abc/../../././../def", "../../def"}, -} - -func TestClean(t *testing.T) { - for i, 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 { - SplitTest{"a/b", "a/", "b"}, - SplitTest{"a/b/", "a/b/", ""}, - SplitTest{"a/", "a/", ""}, - SplitTest{"a", "", "a"}, - SplitTest{"/", "/", ""}, -} - -func TestSplit(t *testing.T) { - for i, 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 { - dir, file, path string -} - -var jointests = []JoinTest { - JoinTest{"a", "b", "a/b"}, - JoinTest{"a", "", "a"}, - JoinTest{"", "b", "b"}, - JoinTest{"/", "a", "/a"}, - JoinTest{"/", "", "/"}, - JoinTest{"a/", "b", "a/b"}, - JoinTest{"a/", "", "a"}, -} - -func TestJoin(t *testing.T) { - for i, test := range jointests { - if p := Join(test.dir, test.file); p != test.path { - t.Errorf("Join(%q, %q) = %q, want %q", test.dir, test.file, p, test.path); - } - } -} - -type ExtTest struct { - path, ext string -} - -var exttests = []ExtTest { - ExtTest{"path.go", ".go"}, - ExtTest{"path.pb.go", ".go"}, - ExtTest{"path", ""}, - ExtTest{"a.dir/b", ""}, - ExtTest{"a.dir/b.go", ".go"}, - ExtTest{"a.dir/", ""}, -} - -func TestExt(t *testing.T) { - for i, test := range exttests { - if x := Ext(test.path); x != test.ext { - t.Errorf("Ext(%q) = %q, want %q", test.path, x, test.ext); - } - } -} - diff --git a/src/lib/rand/Makefile b/src/lib/rand/Makefile deleted file mode 100644 index 63d26ac99..000000000 --- a/src/lib/rand/Makefile +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m >Makefile - -D= - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - rand.$O\ - - -phases: a1 -_obj$D/rand.a: phases - -a1: $(O1) - $(AR) grc _obj$D/rand.a rand.$O - rm -f $(O1) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/rand.a - -$(O1): newpkg -$(O2): a1 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/rand.a - -packages: _obj$D/rand.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/rand.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/rand.a diff --git a/src/lib/rand/rand.go b/src/lib/rand/rand.go deleted file mode 100644 index bc986cbcf..000000000 --- a/src/lib/rand/rand.go +++ /dev/null @@ -1,318 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Uniformly distributed pseudo-random numbers. -package rand - -/* - * 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 ( - rng_tap int; // index into vector - rng_feed int; // index into vector - rng_vec [_LEN]int64; // current feedback register - - // 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 }; -) - -// 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 Seed(seed int32) { - rng_tap = 0; - rng_feed = _LEN-_TAP; - - seed = seed%_M; - if seed < 0 { - seed += _M; - } - if seed == 0 { - seed = 89482311; - } - - x := 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 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; -} - -// Uint32 returns a pseudo-random 32-bit value as a uint32. -func Uint32() uint32 { - return uint32(Int63() >> 31); -} - -// Int31 returns a non-negative pseudo-random 31-bit integer as an int32. -func Int31() int32 { - return int32(Int63() >> 32); -} - -// Int returns a non-negative pseudo-random int. All bits but the top bit are random. -func Int() int { - u := uint(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 Int63n(n int64) int64 { - if n <= 0 { - return 0 - } - max := int64((1<<63)-1 - (1<<63) % uint64(n)); - v := Int63(); - for v > max { - v = Int63() - } - return v % n -} - -// Int31n returns, as an int32, a non-negative pseudo-random number in [0,n). -func Int31n(n int32) int32 { - return int32(Int63n(int64(n))) -} - -// Intn returns, as an int, a non-negative pseudo-random number in [0,n). -func Intn(n int) int { - return int(Int63n(int64(n))) -} - -// Float64 returns, as a float64, a pseudo-random number in [0.0,1.0). -func Float64() float64 { - x := float64(Int63()) / float64(_MAX); - for x >= 1 { - x = float64(Int63()) / float64(_MAX); - } - return x; -} - -// Float32 returns, as a float32, a pseudo-random number in [0.0,1.0). -func Float32() float32 { - return float32(Float64()) -} - -// Float returns, as a float, a pseudo-random number in [0.0,1.0). -func Float() float -{ - return float(Float64()) -} - -// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers [0,n). -func Perm(n int) []int { - m := make([]int, n); - for i:=0; iMakefile - -D= - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - type.$O\ - typestring.$O\ - -O2=\ - value.$O\ - -O3=\ - deepequal.$O\ - tostring.$O\ - - -phases: a1 a2 a3 -_obj$D/reflect.a: phases - -a1: $(O1) - $(AR) grc _obj$D/reflect.a type.$O typestring.$O - rm -f $(O1) - -a2: $(O2) - $(AR) grc _obj$D/reflect.a value.$O - rm -f $(O2) - -a3: $(O3) - $(AR) grc _obj$D/reflect.a deepequal.$O tostring.$O - rm -f $(O3) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/reflect.a - -$(O1): newpkg -$(O2): a1 -$(O3): a2 -$(O4): a3 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/reflect.a - -packages: _obj$D/reflect.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/reflect.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/reflect.a diff --git a/src/lib/reflect/all_test.go b/src/lib/reflect/all_test.go deleted file mode 100644 index 903b0f526..000000000 --- a/src/lib/reflect/all_test.go +++ /dev/null @@ -1,613 +0,0 @@ -// Copyright 2009 The Go Authors. 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 ( - "io"; - "os"; - "reflect"; - "testing"; - "unsafe"; -) - -var doprint bool = false - -func is_digit(c uint8) bool { - return '0' <= c && c <= '9' -} - -// streq, but '@' in t matches a string of digits -func match(s, t string) bool { - for i, j := 0, 0; i < len(s) && j < len(t); i, j = i+1, j+1 { - if s[i] == t[j] { - continue - } - if is_digit(s[i]) && t[j] == '@' { - for is_digit(s[i+1]) { - i++ - } - } else { - return false - } - } - return true; -} - -func assert(s, t string) { - if doprint { - println(t) - } - if !match(s, t) { - panicln(s, t) - } -} - -func typedump(s, t string) { - typ := ParseTypeString("", s); - assert(typeToString(typ, true), t); -} - -func valuedump(s, t string) { - typ := ParseTypeString("", s); - v := NewZeroValue(typ); - if v == nil { - panicln("valuedump", s); - } - switch v.Kind() { - case IntKind: - v.(IntValue).Set(132); - case Int8Kind: - v.(Int8Value).Set(8); - case Int16Kind: - v.(Int16Value).Set(16); - case Int32Kind: - v.(Int32Value).Set(32); - case Int64Kind: - v.(Int64Value).Set(64); - case UintKind: - v.(UintValue).Set(132); - case Uint8Kind: - v.(Uint8Value).Set(8); - case Uint16Kind: - v.(Uint16Value).Set(16); - case Uint32Kind: - v.(Uint32Value).Set(32); - case Uint64Kind: - v.(Uint64Value).Set(64); - case FloatKind: - v.(FloatValue).Set(3200.0); - case Float32Kind: - v.(Float32Value).Set(32.1); - case Float64Kind: - v.(Float64Value).Set(64.2); - case StringKind: - v.(StringValue).Set("stringy cheese"); - case BoolKind: - v.(BoolValue).Set(true); - } - assert(valueToString(v), t); -} - -type T struct { a int; b float64; c string; d *int } - -func TestAll(tt *testing.T) { // TODO(r): wrap up better - var s string; - var t Type; - - // Types - typedump("missing", "$missing$"); - typedump("int", "int"); - typedump("int8", "int8"); - typedump("int16", "int16"); - typedump("int32", "int32"); - typedump("int64", "int64"); - typedump("uint", "uint"); - typedump("uint8", "uint8"); - typedump("uint16", "uint16"); - typedump("uint32", "uint32"); - typedump("uint64", "uint64"); - typedump("float", "float"); - typedump("float32", "float32"); - typedump("float64", "float64"); - typedump("int8", "int8"); - typedump("whoknows.whatsthis", "$missing$"); - typedump("**int8", "**int8"); - typedump("**P.integer", "**P.integer"); - typedump("[32]int32", "[32]int32"); - typedump("[]int8", "[]int8"); - typedump("map[string]int32", "map[string]int32"); - typedump("chan<-string", "chan<-string"); - typedump("struct {c chan *int32; d float32}", "struct{c chan*int32; d float32}"); - typedump("func(a int8, b int32)", "func(a int8, b int32)"); - typedump("struct {c func(? chan *P.integer, ? *int8)}", "struct{c func(chan*P.integer, *int8)}"); - typedump("struct {a int8; b int32}", "struct{a int8; b int32}"); - typedump("struct {a int8; b int8; b int32}", "struct{a int8; b int8; b int32}"); - typedump("struct {a int8; b int8; c int8; b int32}", "struct{a int8; b int8; c int8; b int32}"); - typedump("struct {a int8; b int8; c int8; d int8; b int32}", "struct{a int8; b int8; c int8; d int8; b int32}"); - typedump("struct {a int8; b int8; c int8; d int8; e int8; b int32}", "struct{a int8; b int8; c int8; d int8; e int8; b int32}"); - typedump("struct {a int8 \"hi there\"; }", "struct{a int8 \"hi there\"}"); - typedump("struct {a int8 \"hi \\x00there\\t\\n\\\"\\\\\"; }", "struct{a int8 \"hi \\x00there\\t\\n\\\"\\\\\"}"); - typedump("struct {f func(args ...)}", "struct{f func(args ...)}"); - typedump("interface { a(? func(? func(? int) int) func(? func(? int)) int); b() }", "interface{a (func(func(int)(int))(func(func(int))(int))); b ()}"); - - // Values - valuedump("int8", "8"); - valuedump("int16", "16"); - valuedump("int32", "32"); - valuedump("int64", "64"); - valuedump("uint8", "8"); - valuedump("uint16", "16"); - valuedump("uint32", "32"); - valuedump("uint64", "64"); - valuedump("float32", "32.1"); - valuedump("float64", "64.2"); - valuedump("string", "stringy cheese"); - valuedump("bool", "true"); - valuedump("*int8", "*int8(0)"); - valuedump("**int8", "**int8(0)"); - valuedump("[5]int32", "[5]int32{0, 0, 0, 0, 0}"); - valuedump("**P.integer", "**P.integer(0)"); - valuedump("map[string]int32", "map[string]int32{}"); - valuedump("chan<-string", "chan<-string"); - valuedump("struct {c chan *int32; d float32}", "struct{c chan*int32; d float32}{chan*int32, 0}"); - valuedump("func(a int8, b int32)", "func(a int8, b int32)(0)"); - valuedump("struct {c func(? chan *P.integer, ? *int8)}", "struct{c func(chan*P.integer, *int8)}{func(chan*P.integer, *int8)(0)}"); - valuedump("struct {a int8; b int32}", "struct{a int8; b int32}{0, 0}"); - valuedump("struct {a int8; b int8; b int32}", "struct{a int8; b int8; b int32}{0, 0, 0}"); - - { var tmp = 123; - value := NewValue(tmp); - assert(valueToString(value), "123"); - } - { var tmp = 123.4; - value := NewValue(tmp); - assert(valueToString(value), "123.4"); - } - { - var tmp = byte(123); - value := NewValue(tmp); - assert(valueToString(value), "123"); - assert(typeToString(value.Type(), false), "uint8"); - } - { var tmp = "abc"; - value := NewValue(tmp); - assert(valueToString(value), "abc"); - } - { - var i int = 7; - var tmp = &T{123, 456.75, "hello", &i}; - value := NewValue(tmp); - assert(valueToString(value.(PtrValue).Sub()), "reflect.T{123, 456.75, hello, *int(@)}"); - } - { - type C chan *T; // TODO: should not be necessary - var tmp = new(C); - value := NewValue(tmp); - assert(valueToString(value), "*reflect.C·all_test(@)"); - } -// { -// type A [10]int; -// var tmp A = A{1,2,3,4,5,6,7,8,9,10}; -// value := NewValue(&tmp); -// assert(valueToString(value.(PtrValue).Sub()), "reflect.A·all_test{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}"); -// value.(PtrValue).Sub().(ArrayValue).Elem(4).(IntValue).Set(123); -// assert(valueToString(value.(PtrValue).Sub()), "reflect.A·all_test{1, 2, 3, 4, 123, 6, 7, 8, 9, 10}"); -// } - { - type AA []int; - var tmp = AA{1,2,3,4,5,6,7,8,9,10}; - value := NewValue(&tmp); // TODO: NewValue(tmp) too - assert(valueToString(value.(PtrValue).Sub()), "reflect.AA·all_test{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}"); - value.(PtrValue).Sub().(ArrayValue).Elem(4).(IntValue).Set(123); - assert(valueToString(value.(PtrValue).Sub()), "reflect.AA·all_test{1, 2, 3, 4, 123, 6, 7, 8, 9, 10}"); - } - - { - var ip *int32; - var i int32 = 1234; - vip := NewValue(&ip); - vi := NewValue(i); - vip.(PtrValue).Sub().(PtrValue).SetSub(vi); - if *ip != 1234 { - panicln("SetSub failure", *ip); - } - } - - var pt PtrType; - var st StructType; - var mt MapType; - var at ArrayType; - var ct ChanType; - var name string; - var typ Type; - var tag string; - var offset int; - - // Type strings - t = ParseTypeString("", "int8"); - assert(t.String(), "int8"); - - t = ParseTypeString("", "*int8"); - assert(t.String(), "*int8"); - pt = t.(PtrType); - assert(pt.Sub().String(), "int8"); - - t = ParseTypeString("", "*struct {c chan *int32; d float32}"); - assert(t.String(), "*struct {c chan *int32; d float32}"); - pt = t.(PtrType); - assert(pt.Sub().String(), "struct {c chan *int32; d float32}"); - st = pt.Sub().(StructType); - name, typ, tag, offset = st.Field(0); - assert(typ.String(), "chan *int32"); - name, typ, tag, offset = st.Field(1); - assert(typ.String(), "float32"); - - t = ParseTypeString("", "interface {a() *int}"); - assert(t.String(), "interface {a() *int}"); - - t = ParseTypeString("", "func(a int8, b int32)"); - assert(t.String(), "func(a int8, b int32)"); - - t = ParseTypeString("", "func(a int8, b int32) float"); - assert(t.String(), "func(a int8, b int32) float"); - - t = ParseTypeString("", "func(a int8, b int32) (a float, b float)"); - assert(t.String(), "func(a int8, b int32) (a float, b float)"); - - t = ParseTypeString("", "[32]int32"); - assert(t.String(), "[32]int32"); - at = t.(ArrayType); - assert(at.Elem().String(), "int32"); - - t = ParseTypeString("", "map[string]*int32"); - assert(t.String(), "map[string]*int32"); - mt = t.(MapType); - assert(mt.Key().String(), "string"); - assert(mt.Elem().String(), "*int32"); - - t = ParseTypeString("", "chan<-string"); - assert(t.String(), "chan<-string"); - ct = t.(ChanType); - assert(ct.Elem().String(), "string"); - - // make sure tag strings are not part of element type - t = ParseTypeString("", "struct{d []uint32 \"TAG\"}"); - st = t.(StructType); - name, typ, tag, offset = st.Field(0); - assert(typ.String(), "[]uint32"); - - t = ParseTypeString("", "[]int32"); - v := NewSliceValue(t.(ArrayType), 5, 10); - t1 := ParseTypeString("", "*[]int32"); - v1 := NewZeroValue(t1); - if v1 == nil { panic("V1 is nil"); } - v1.(PtrValue).SetSub(v); - a := v1.Interface().(*[]int32); - println(&a, len(a), cap(a)); - for i := 0; i < len(a); i++ { - v.Elem(i).(Int32Value).Set(int32(i)); - } - for i := 0; i < len(a); i++ { - println(a[i]); - } -} - -func TestInterfaceGet(t *testing.T) { - var inter struct { e interface{ } }; - inter.e = 123.456; - v1 := NewValue(&inter); - v2 := v1.(PtrValue).Sub().(StructValue).Field(0); - assert(v2.Type().String(), "interface { }"); - i2 := v2.(InterfaceValue).Get(); - v3 := NewValue(i2); - assert(v3.Type().String(), "float"); -} - -func TestInterfaceValue(t *testing.T) { - var inter struct { e interface{ } }; - inter.e = 123.456; - v1 := NewValue(&inter); - v2 := v1.(PtrValue).Sub().(StructValue).Field(0); - assert(v2.Type().String(), "interface { }"); - v3 := v2.(InterfaceValue).Value(); - assert(v3.Type().String(), "float"); - - i3 := v2.Interface(); - if f, ok := i3.(float); !ok { - a, typ, c := unsafe.Reflect(i3); - t.Error("v2.Interface() did not return float, got ", typ); - } -} - -func TestFunctionValue(t *testing.T) { - v := NewValue(func() {}); - if v.Interface() != v.Interface() { - t.Fatalf("TestFunction != itself"); - } - assert(v.Type().String(), "func()"); -} - -func TestCopyArray(t *testing.T) { - a := []int{ 1, 2, 3, 4, 10, 9, 8, 7 }; - b := []int{ 11, 22, 33, 44, 1010, 99, 88, 77, 66, 55, 44 }; - c := []int{ 11, 22, 33, 44, 1010, 99, 88, 77, 66, 55, 44 }; - va := NewValue(&a); - vb := NewValue(&b); - for i := 0; i < len(b); i++ { - if b[i] != c[i] { - t.Fatalf("b != c before test"); - } - } - for tocopy := 1; tocopy <= 7; tocopy++ { - vb.(PtrValue).Sub().(ArrayValue).CopyFrom(va.(PtrValue).Sub().(ArrayValue), tocopy); - for i := 0; i < tocopy; i++ { - if a[i] != b[i] { - t.Errorf("1 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("2 tocopy=%d a[%d]=%d, b[%d]=%d, c[%d]=%d", - tocopy, i, a[i], i, b[i], i, c[i]); - } else { - t.Errorf("3 tocopy=%d b[%d]=%d, c[%d]=%d", - tocopy, i, b[i], i, c[i]); - } - } else { - t.Logf("tocopy=%d elem %d is okay\n", tocopy, i); - } - } - } -} - -func TestBigUnnamedStruct(t *testing.T) { - b := struct{a,b,c,d int64}{1, 2, 3, 4}; - v := NewValue(b); - b1 := v.Interface().(struct{a,b,c,d int64}); - if b1.a != b.a || b1.b != b.b || b1.c != b.c || b1.d != b.d { - t.Errorf("NewValue(%v).Interface().(Big) = %v", b, b1); - } -} - -type big struct { - a, b, c, d, e int64 -} -func TestBigStruct(t *testing.T) { - b := big{1, 2, 3, 4, 5}; - v := NewValue(b); - b1 := v.Interface().(big); - if b1.a != b.a || b1.b != b.b || b1.c != b.c || b1.d != b.d || b1.e != b.e { - t.Errorf("NewValue(%v).Interface().(big) = %v", b, b1); - } -} - -type Basic struct { - x int; - y float32 -} - -type NotBasic Basic - -type Recursive struct { - x int; - r *Recursive -} - -type Complex struct { - a int; - b [3]*Complex; - c *string; - d map[float]float -} - -type DeepEqualTest struct { - a, b interface{}; - eq bool; -} - -var deepEqualTests = []DeepEqualTest { - // Equalities - DeepEqualTest{ 1, 1, true }, - DeepEqualTest{ int32(1), int32(1), true }, - DeepEqualTest{ 0.5, 0.5, true }, - DeepEqualTest{ float32(0.5), float32(0.5), true }, - DeepEqualTest{ "hello", "hello", true }, - DeepEqualTest{ make([]int, 10), make([]int, 10), true }, - DeepEqualTest{ &[3]int{ 1, 2, 3 }, &[3]int{ 1, 2, 3 }, true }, - DeepEqualTest{ Basic{ 1, 0.5 }, Basic{ 1, 0.5 }, true }, - // Inequalities - DeepEqualTest{ 1, 2, false }, - DeepEqualTest{ int32(1), int32(2), false }, - DeepEqualTest{ 0.5, 0.6, false }, - DeepEqualTest{ float32(0.5), float32(0.6), false }, - DeepEqualTest{ "hello", "hey", false }, - DeepEqualTest{ make([]int, 10), make([]int, 11), false }, - DeepEqualTest{ &[3]int{ 1, 2, 3 }, &[3]int{ 1, 2, 4 }, false }, - DeepEqualTest{ Basic{ 1, 0.5 }, Basic{ 1, 0.6 }, false }, - // Mismatched types - DeepEqualTest{ 1, 1.0, false }, - DeepEqualTest{ int32(1), int64(1), false }, - DeepEqualTest{ 0.5, "hello", false }, - DeepEqualTest{ []int{ 1, 2, 3 }, [3]int{ 1, 2, 3 }, false }, - DeepEqualTest{ &[3]interface{} { 1, 2, 4 }, &[3]interface{} { 1, 2, "s" }, false }, - DeepEqualTest{ Basic{ 1, 0.5 }, NotBasic{ 1, 0.5 }, false }, -} - -func TestDeepEqual(t *testing.T) { - for i, 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 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"); - } -} - -func TestDeepEqualComplexStruct(t *testing.T) { - m := make(map[float]float); - 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[float]float); - stra, strb := "hello", "helloo"; // Difference is here - a, b := new(Complex), new(Complex); - *a = Complex{5, [3]*Complex{a, b, a}, &stra, m}; - *b = Complex{5, [3]*Complex{b, a, a}, &strb, m}; - if DeepEqual(a, b) { - t.Error("DeepEqual(complex different) = true, want false"); - } -} - - -func check2ndField(x interface{}, offs uintptr, t *testing.T) { - s := NewValue(x).(StructValue); - name, ftype, tag, reflect_offset := s.Type().(StructType).Field(1); - if uintptr(reflect_offset) != offs { - t.Error("mismatched offsets in structure alignment:", reflect_offset, offs); - } -} - -// Check that structure alignment & offsets viewed through reflect agree with those -// from the compiler itself. -func TestAlignment(t *testing.T) { - type T1inner struct { - a int - } - type T1 struct { - T1inner; - f int; - } - type T2inner struct { - a, b int - } - type T2 struct { - T2inner; - f int; - } - - x := T1{T1inner{2}, 17}; - check2ndField(x, uintptr(unsafe.Pointer(&x.f)) - uintptr(unsafe.Pointer(&x)), t); - - x1 := T2{T2inner{2, 3}, 17}; - check2ndField(x1, uintptr(unsafe.Pointer(&x1.f)) - uintptr(unsafe.Pointer(&x1)), t); -} - -type Nillable interface { - IsNil() bool -} - -func Nil(a interface{}, t *testing.T) { - n := NewValue(a).(Nillable); - if !n.IsNil() { - t.Errorf("%v should be nil", a) - } -} - -func NotNil(a interface{}, t *testing.T) { - n := NewValue(a).(Nillable); - if n.IsNil() { - t.Errorf("value of type %v should not be nil", NewValue(a).Type().String()) - } -} - -func TestIsNil(t *testing.T) { - // These do not implement IsNil - doNotNil := []string{"int", "float32", "struct { a int }"}; - // These do implement IsNil - doNil := []string{"*int", "interface{}", "map[string]int", "func() bool", "chan int", "[]string"}; - for i, ts := range doNotNil { - ty := ParseTypeString("", ts); - v := NewZeroValue(ty); - if nilable, ok := v.(Nillable); ok { - t.Errorf("%s is nilable; should not be", ts) - } - } - - for i, ts := range doNil { - ty := ParseTypeString("", ts); - v := NewZeroValue(ty); - if nilable, ok := v.(Nillable); !ok { - t.Errorf("%s %T is not nilable; should be", ts, v) - } - } - // Check the implementations - var pi *int; - Nil(pi, t); - pi = new(int); - NotNil(pi, t); - - var si []int; - Nil(si, t); - si = make([]int, 10); - NotNil(si, t); - - // TODO: map and chan don't work yet - - var ii interface {}; - Nil(ii, t); - ii = pi; - NotNil(ii, t); - - var fi func(t *testing.T); - Nil(fi, t); - fi = TestIsNil; - NotNil(fi, t); -} - -func TestInterfaceExtraction(t *testing.T) { - var s struct { - w io.Writer; - } - - s.w = os.Stdout; - v := Indirect(NewValue(&s)).(StructValue).Field(0).Interface(); - if v != s.w.(interface{}) { - t.Errorf("Interface() on interface: ", v, s.w); - } -} - -func TestInterfaceEditing(t *testing.T) { - // strings are bigger than one word, - // so the interface conversion allocates - // memory to hold a string and puts that - // pointer in the interface. - var i interface{} = "hello"; - - // if i pass the interface value by value - // to NewValue, i should get a fresh copy - // of the value. - v := NewValue(i); - - // and setting that copy to "bye" should - // not change the value stored in i. - v.(StringValue).Set("bye"); - if i.(string) != "hello" { - t.Errorf(`Set("bye") changed i to %s`, i.(string)); - } - - // the same should be true of smaller items. - i = 123; - v = NewValue(i); - v.(IntValue).Set(234); - if i.(int) != 123 { - t.Errorf("Set(234) changed i to %d", i.(int)); - } -} diff --git a/src/lib/reflect/deepequal.go b/src/lib/reflect/deepequal.go deleted file mode 100644 index 57b52485f..000000000 --- a/src/lib/reflect/deepequal.go +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2009 The Go 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 - -import "reflect" - -// 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[Addr]Addr) bool { - if v1.Kind() != v2.Kind() { - return false; - } - - // Short circuit if references are identical or already seen - addr1 := v1.Addr(); - addr2 := v2.Addr(); - - if addr1 == addr2 { - return true; - } - if vaddr, ok := visited[addr1]; ok && vaddr == addr2 { - return true; - } - visited[addr1] = addr2; - - switch v1.Kind() { - case ArrayKind: - arr1 := v1.(ArrayValue); - arr2 := v2.(ArrayValue); - if arr1.IsSlice() != arr2.IsSlice() || arr1.Len() != arr2.Len() { - return false; - } - for i := 0; i < arr1.Len(); i++ { - if !deepValueEqual(arr1.Elem(i), arr2.Elem(i), visited) { - return false; - } - } - return true; - case InterfaceKind: - return deepValueEqual(NewValue(v1.(InterfaceValue).Get()), - NewValue(v2.(InterfaceValue).Get()), visited); - case MapKind: - // TODO(dnadasi): Implement this fully once MapValue is implemented - return v1.Interface() == v2.Interface(); - case PtrKind: - return deepValueEqual(v1.(PtrValue).Sub(), v2.(PtrValue).Sub(), visited); - case StructKind: - struct1 := v1.(StructValue); - struct2 := v2.(StructValue); - if struct1.Len() != struct2.Len() { - return false; - } - for i := 0; i < struct1.Len(); i++ { - if !deepValueEqual(struct1.Field(i), struct2.Field(i), visited) { - 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. Until reflection supports maps, maps are equal iff -// they are identical. -func DeepEqual(a1, a2 interface{}) bool { - v1 := NewValue(a1); - v2 := NewValue(a2); - if !equalType(v1.Type(), v2.Type()) { - return false; - } - return deepValueEqual(v1, v2, make(map[Addr]Addr)); -} diff --git a/src/lib/reflect/tostring.go b/src/lib/reflect/tostring.go deleted file mode 100644 index 43be4b9e8..000000000 --- a/src/lib/reflect/tostring.go +++ /dev/null @@ -1,234 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Reflection library. -// 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 - -import ( - "reflect"; - "strconv"; -) - -func typeToString(typ Type, expand bool) string -func valueToString(val Value) string - -func doubleQuote(s string) string { - out := "\""; - for i := 0; i < len(s); i++ { - c := s[i]; - switch c { - case '\n': - out += `\n`; - case '\t': - out += `\t`; - case '\x00': - out += `\x00`; - case '"': - out += `\"`; - case '\\': - out += `\\`; - default: - out += string(c); - } - } - out += "\""; - return out; -} - -type hasFields interface { - Field(i int) (name string, typ Type, tag string, offset int); - Len() int; -} - -func typeFieldsToString(t hasFields, sep string, iface bool) string { - var str string; - for i := 0; i < t.Len(); i++ { - str1, typ, tag, offset := t.Field(i); - if str1 != "" { - str1 += " " - } - str2 := typeToString(typ, false); - if iface && str2[0:4] == "func" { - str2 = str2[4:len(str2)] - } - str1 += str2; - if tag != "" { - str1 += " " + doubleQuote(tag); - } - if i < t.Len() - 1 { - str1 += sep + " "; - } - str += str1; - } - return str; -} - -// typeToString returns a textual representation of typ. The expand -// flag specifies whether to expand the contents of type names; if false, -// the name itself is used as the representation. -// Meant for debugging only; typ.String() serves for most purposes. -func typeToString(typ Type, expand bool) string { - var str string; - if name := typ.Name(); !expand && name != "" { - return name - } - switch(typ.Kind()) { - case MissingKind: - return "$missing$"; - case IntKind, Int8Kind, Int16Kind, Int32Kind, Int64Kind, - UintKind, Uint8Kind, Uint16Kind, Uint32Kind, Uint64Kind, - FloatKind, Float32Kind, Float64Kind, - StringKind, - DotDotDotKind: - return typ.Name(); - case PtrKind: - p := typ.(PtrType); - return "*" + typeToString(p.Sub(), false); - case ArrayKind: - a := typ.(ArrayType); - if a.IsSlice() { - str = "[]" - } else { - str = "[" + strconv.Itoa64(int64(a.Len())) + "]" - } - return str + typeToString(a.Elem(), false); - case MapKind: - m := typ.(MapType); - str = "map[" + typeToString(m.Key(), false) + "]"; - return str + typeToString(m.Elem(), false); - case ChanKind: - c := typ.(ChanType); - switch c.Dir() { - case RecvDir: - str = "<-chan"; - case SendDir: - str = "chan<-"; - case BothDir: - str = "chan"; - default: - panicln("reflect.typeToString: unknown chan direction"); - } - return str + typeToString(c.Elem(), false); - case StructKind: - return "struct{" + typeFieldsToString(typ.(StructType), ";", false) + "}"; - case InterfaceKind: - return "interface{" + typeFieldsToString(typ.(InterfaceType), ";", true) + "}"; - case FuncKind: - f := typ.(FuncType); - str = "func(" + typeFieldsToString(f.In(), ",", false) + ")"; - if f.Out() != nil { - str += "(" + typeFieldsToString(f.Out(), ",", false) + ")"; - } - return str; - default: - panicln("reflect.typeToString: can't print type ", typ.Kind()); - } - return "reflect.typeToString: can't happen"; -} - -// TODO: want an unsigned one too -func integer(v int64) string { - return strconv.Itoa64(v); -} - -// valueToString returns a textual representation of the reflection value val. -// For debugging only. -func valueToString(val Value) string { - var str string; - typ := val.Type(); - switch(val.Kind()) { - case MissingKind: - return "missing"; - case IntKind: - return integer(int64(val.(IntValue).Get())); - case Int8Kind: - return integer(int64(val.(Int8Value).Get())); - case Int16Kind: - return integer(int64(val.(Int16Value).Get())); - case Int32Kind: - return integer(int64(val.(Int32Value).Get())); - case Int64Kind: - return integer(int64(val.(Int64Value).Get())); - case UintKind: - return integer(int64(val.(UintValue).Get())); - case Uint8Kind: - return integer(int64(val.(Uint8Value).Get())); - case Uint16Kind: - return integer(int64(val.(Uint16Value).Get())); - case Uint32Kind: - return integer(int64(val.(Uint32Value).Get())); - case Uint64Kind: - return integer(int64(val.(Uint64Value).Get())); - case FloatKind: - if strconv.FloatSize == 32 { - return strconv.Ftoa32(float32(val.(FloatValue).Get()), 'g', -1); - } else { - return strconv.Ftoa64(float64(val.(FloatValue).Get()), 'g', -1); - } - case Float32Kind: - return strconv.Ftoa32(val.(Float32Value).Get(), 'g', -1); - case Float64Kind: - return strconv.Ftoa64(val.(Float64Value).Get(), 'g', -1); - case StringKind: - return val.(StringValue).Get(); - case BoolKind: - if val.(BoolValue).Get() { - return "true" - } else { - return "false" - } - case PtrKind: - v := val.(PtrValue); - return typeToString(typ, false) + "(" + integer(int64(uintptr(v.Get()))) + ")"; - case ArrayKind: - t := typ.(ArrayType); - v := val.(ArrayValue); - str += typeToString(t, false); - str += "{"; - for i := 0; i < v.Len(); i++ { - if i > 0 { - str += ", " - } - str += valueToString(v.Elem(i)); - } - str += "}"; - return str; - case MapKind: - t := typ.(MapType); - v := val.(MapValue); - str = typeToString(t, false); - str += "{"; - str += ""; - str += "}"; - return str; - case ChanKind: - str = typeToString(typ, false); - return str; - case StructKind: - t := typ.(StructType); - v := val.(StructValue); - str += typeToString(t, false); - str += "{"; - for i := 0; i < v.Len(); i++ { - if i > 0 { - str += ", " - } - str += valueToString(v.Field(i)); - } - str += "}"; - return str; - case InterfaceKind: - return "can't print interfaces yet"; - case FuncKind: - v := val.(FuncValue); - return typeToString(typ, false) + "(" + integer(int64(uintptr(v.Get()))) + ")"; - default: - panicln("reflect.valueToString: can't print type ", val.Kind()); - } - return "reflect.valueToString: can't happen"; -} diff --git a/src/lib/reflect/type.go b/src/lib/reflect/type.go deleted file mode 100644 index c8542183a..000000000 --- a/src/lib/reflect/type.go +++ /dev/null @@ -1,1047 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Reflection library. -// Types and parsing of type strings. - -// This package implements data ``reflection''. A program can use it to analyze types -// and values it does not know at compile time, such as the values passed in a call -// to a function with a ... parameter. This is achieved by extracting the dynamic -// contents of an interface value. -package reflect - -import ( - "sync"; - "unsafe"; - "utf8"; -) - -type Type interface - -func ExpandType(name string) Type - -func typestrings() string // implemented in C; declared here - -// These constants identify what kind of thing a Type represents: an int, struct, etc. -const ( - MissingKind = iota; - ArrayKind; - BoolKind; - ChanKind; - DotDotDotKind; - FloatKind; - Float32Kind; - Float64Kind; - FuncKind; - IntKind; - Int16Kind; - Int32Kind; - Int64Kind; - Int8Kind; - InterfaceKind; - MapKind; - PtrKind; - StringKind; - StructKind; - UintKind; - Uint16Kind; - Uint32Kind; - Uint64Kind; - Uint8Kind; - UintptrKind; -) - -// For sizes and alignments. - -type allTypes struct { - xarray []byte; - xbool bool; - xchan chan byte; - xfloat float; - xfloat32 float32; - xfloat64 float64; - xfunc func(); - xint int; - xint16 int16; - xint32 int32; - xint64 int64; - xint8 int8; - xinterface interface {}; - xmap map[byte]byte; - xptr *byte; - xslice []byte; - xstring string; - xuint uint; - xuint16 uint16; - xuint32 uint32; - xuint64 uint64; - xuint8 uint8; - xuintptr uintptr; -} - -var ( - x allTypes; - minStruct struct { uint8 }; -) - -const ( - minStructAlignMask = unsafe.Sizeof(minStruct) - 1; - ptrsize = unsafe.Sizeof(&x); - interfacesize = unsafe.Sizeof(x.xinterface); -) - -const missingString = "$missing$" // syntactic name for undefined type names -const dotDotDotString = "..." - -// Type is the generic interface to reflection types. Once its Kind is known, -// such as ArrayKind, the Type can be narrowed to the appropriate, more -// specific interface, such as ArrayType. Such narrowed types still implement -// the Type interface. -type Type interface { - // The kind of thing described: ArrayKind, BoolKind, etc. - Kind() int; - // The name declared for the type ("int", "BoolArray", etc.). - Name() string; - // For a named type, same as Name(); otherwise a representation of the type such as "[]int". - String() string; - // The number of bytes needed to store a value; analogous to unsafe.Sizeof(). - Size() int; - // The alignment of a value of this type when used as a field in a struct. - FieldAlign() int; -} - -// Fields and methods common to all types -type commonType struct { - kind int; - str string; - name string; - size int; -} - -func (c *commonType) Kind() int { - return c.kind -} - -func (c *commonType) Name() string { - return c.name -} - -func (c *commonType) String() string { - // If there is a name, show that instead of its expansion. - // This is important for reflection: a named type - // might have methods that the unnamed type does not. - if c.name != "" { - return c.name - } - return c.str -} - -func (c *commonType) Size() int { - return c.size -} - -// -- Basic - -type basicType struct { - commonType; - fieldAlign int; -} - -func newBasicType(name string, kind int, size int, fieldAlign int) Type { - return &basicType{ commonType{kind, name, name, size}, fieldAlign } -} - -func (t *basicType) FieldAlign() int { - return t.fieldAlign -} - -// Prebuilt basic Type objects representing the predeclared basic types. -// Most are self-evident except: -// Missing represents types whose representation cannot be discovered; usually an error. -// DotDotDot represents the pseudo-type of a ... parameter. -var ( - Missing = newBasicType(missingString, MissingKind, 1, 1); - DotDotDot = newBasicType(dotDotDotString, DotDotDotKind, unsafe.Sizeof(x.xinterface), unsafe.Alignof(x.xinterface)); - Bool = newBasicType("bool", BoolKind, unsafe.Sizeof(x.xbool), unsafe.Alignof(x.xbool)); - Int = newBasicType("int", IntKind, unsafe.Sizeof(x.xint), unsafe.Alignof(x.xint)); - Int8 = newBasicType("int8", Int8Kind, unsafe.Sizeof(x.xint8), unsafe.Alignof(x.xint8)); - Int16 = newBasicType("int16", Int16Kind, unsafe.Sizeof(x.xint16), unsafe.Alignof(x.xint16)); - Int32 = newBasicType("int32", Int32Kind, unsafe.Sizeof(x.xint32), unsafe.Alignof(x.xint32)); - Int64 = newBasicType("int64", Int64Kind, unsafe.Sizeof(x.xint64), unsafe.Alignof(x.xint64)); - Uint = newBasicType("uint", UintKind, unsafe.Sizeof(x.xuint), unsafe.Alignof(x.xuint)); - Uint8 = newBasicType("uint8", Uint8Kind, unsafe.Sizeof(x.xuint8), unsafe.Alignof(x.xuint8)); - Uint16 = newBasicType("uint16", Uint16Kind, unsafe.Sizeof(x.xuint16), unsafe.Alignof(x.xuint16)); - Uint32 = newBasicType("uint32", Uint32Kind, unsafe.Sizeof(x.xuint32), unsafe.Alignof(x.xuint32)); - Uint64 = newBasicType("uint64", Uint64Kind, unsafe.Sizeof(x.xuint64), unsafe.Alignof(x.xuint64)); - Uintptr = newBasicType("uintptr", UintptrKind, unsafe.Sizeof(x.xuintptr), unsafe.Alignof(x.xuintptr)); - Float = newBasicType("float", FloatKind, unsafe.Sizeof(x.xfloat), unsafe.Alignof(x.xfloat)); - Float32 = newBasicType("float32", Float32Kind, unsafe.Sizeof(x.xfloat32), unsafe.Alignof(x.xfloat32)); - Float64 = newBasicType("float64", Float64Kind, unsafe.Sizeof(x.xfloat64), unsafe.Alignof(x.xfloat64)); - String = newBasicType("string", StringKind, unsafe.Sizeof(x.xstring), unsafe.Alignof(x.xstring)); -) - -// Stub types allow us to defer evaluating type names until needed. -// If the name is empty, the type must be non-nil. - -type stubType struct { - name string; - typ Type; -} - -func newStubType(name string, typ Type) *stubType { - return &stubType{name, typ} -} - -func (t *stubType) Get() Type { - if t.typ == nil { - t.typ = ExpandType(t.name) - } - return t.typ -} - -// -- Pointer - -// PtrType represents a pointer. -type PtrType interface { - Type; - Sub() Type // The type of the pointed-to item; for "*int", it will be "int". -} - -type ptrTypeStruct struct { - commonType; - sub *stubType; -} - -func newPtrTypeStruct(name, typestring string, sub *stubType) *ptrTypeStruct { - return &ptrTypeStruct{ commonType{PtrKind, typestring, name, ptrsize}, sub} -} - -func (t *ptrTypeStruct) FieldAlign() int { - return unsafe.Alignof(x.xptr); -} - -func (t *ptrTypeStruct) Sub() Type { - return t.sub.Get() -} - -// -- Array - -// ArrayType represents an array or slice type. -type ArrayType interface { - Type; - IsSlice() bool; // True for slices, false for arrays. - Len() int; // 0 for slices, the length for array types. - Elem() Type; // The type of the elements. -} - -type arrayTypeStruct struct { - commonType; - elem *stubType; - isslice bool; // otherwise fixed array - len int; -} - -func newArrayTypeStruct(name, typestring string, open bool, len int, elem *stubType) *arrayTypeStruct { - return &arrayTypeStruct{ commonType{ArrayKind, typestring, name, 0 }, elem, open, len} -} - -func (t *arrayTypeStruct) Size() int { - if t.isslice { - return unsafe.Sizeof(x.xslice); - } - return t.len * t.elem.Get().Size(); -} - -func (t *arrayTypeStruct) FieldAlign() int { - if t.isslice { - return unsafe.Alignof(x.xslice); - } - return t.elem.Get().FieldAlign(); -} - -func (t *arrayTypeStruct) IsSlice() bool { - return t.isslice -} - -func (t *arrayTypeStruct) Len() int { - if t.isslice { - return 0 - } - return t.len -} - -func (t *arrayTypeStruct) Elem() Type { - return t.elem.Get() -} - -// -- Map - -// MapType represents a map type. -type MapType interface { - Type; - Key() Type; // The type of the keys. - Elem() Type; // The type of the elements/values. -} - -type mapTypeStruct struct { - commonType; - key *stubType; - elem *stubType; -} - -func newMapTypeStruct(name, typestring string, key, elem *stubType) *mapTypeStruct { - return &mapTypeStruct{ commonType{MapKind, typestring, name, ptrsize}, key, elem} -} - -func (t *mapTypeStruct) FieldAlign() int { - return unsafe.Alignof(x.xmap); -} - -func (t *mapTypeStruct) Key() Type { - return t.key.Get() -} - -func (t *mapTypeStruct) Elem() Type { - return t.elem.Get() -} - -// -- Chan - -// ChanType represents a chan type. -type ChanType interface { - Type; - Dir() int; // The direction of the channel. - Elem() Type; // The type of the elements. -} - -// Channel direction. -const ( - SendDir = 1 << iota; - RecvDir; - BothDir = SendDir | RecvDir; -) - -type chanTypeStruct struct { - commonType; - elem *stubType; - dir int; -} - -func newChanTypeStruct(name, typestring string, dir int, elem *stubType) *chanTypeStruct { - return &chanTypeStruct{ commonType{ChanKind, typestring, name, ptrsize}, elem, dir} -} - -func (t *chanTypeStruct) FieldAlign() int { - return unsafe.Alignof(x.xchan); -} - -func (t *chanTypeStruct) Dir() int { - return t.dir -} - -func (t *chanTypeStruct) Elem() Type { - return t.elem.Get() -} - -// -- Struct - -// StructType represents a struct type. -type StructType interface { - Type; - // Field returns, for field i, its name, Type, tag information, and byte offset. - // The indices are in declaration order starting at 0. - Field(i int) (name string, typ Type, tag string, offset int); - // Len is the number of fields. - Len() int; -} - -type structField struct { - name string; - typ *stubType; - tag string; - offset int; -} - -type structTypeStruct struct { - commonType; - field []structField; - fieldAlign int; -} - -func newStructTypeStruct(name, typestring string, field []structField) *structTypeStruct { - return &structTypeStruct{ commonType{StructKind, typestring, name, 0}, field, 0} -} - -func (t *structTypeStruct) FieldAlign() int { - t.Size(); // Compute size and alignment. - return t.fieldAlign -} - -func (t *structTypeStruct) Size() int { - if t.size > 0 { - return t.size - } - size := 0; - structAlignMask := 0; - for i := 0; i < len(t.field); i++ { - typ := t.field[i].typ.Get(); - elemsize := typ.Size(); - alignMask := typ.FieldAlign() - 1; - if alignMask > structAlignMask { - structAlignMask = alignMask - } - if alignMask > 0 { - size = (size + alignMask) &^ alignMask; - } - t.field[i].offset = size; - size += elemsize; - } - if (structAlignMask > 0) { - // 6g etc. always aligns structs to a minimum size, typically int64 - if structAlignMask < minStructAlignMask { - structAlignMask = minStructAlignMask - } - // TODO: In the PPC64 ELF ABI, floating point fields - // in a struct are aligned to a 4-byte boundary, but - // if the first field in the struct is a 64-bit float, - // the whole struct is aligned to an 8-byte boundary. - size = (size + structAlignMask) &^ structAlignMask; - t.fieldAlign = structAlignMask + 1; - } - t.size = size; - return size; -} - -func (t *structTypeStruct) Field(i int) (name string, typ Type, tag string, offset int) { - if t.field[i].offset == 0 { - t.Size(); // will compute offsets - } - return t.field[i].name, t.field[i].typ.Get(), t.field[i].tag, t.field[i].offset -} - -func (t *structTypeStruct) Len() int { - return len(t.field) -} - -// -- Interface - -// InterfaceType represents an interface type. -// It behaves much like a StructType, treating the methods as fields. -type InterfaceType interface { - Type; - // Field returns, for method i, its name, Type, the empty string, and 0. - // The indices are in declaration order starting at 0. TODO: is this true? - Field(int) (name string, typ Type, tag string, offset int); - Len() int; -} - -type interfaceTypeStruct struct { - commonType; - field []structField; -} - -func newInterfaceTypeStruct(name, typestring string, field []structField) *interfaceTypeStruct { - return &interfaceTypeStruct{ commonType{InterfaceKind, typestring, name, interfacesize}, field } -} - -func (t *interfaceTypeStruct) FieldAlign() int { - return unsafe.Alignof(x.xinterface); -} - -func (t *interfaceTypeStruct) Field(i int) (name string, typ Type, tag string, offset int) { - return t.field[i].name, t.field[i].typ.Get(), "", 0 -} - -func (t *interfaceTypeStruct) Len() int { - return len(t.field) -} - -var nilInterface = newInterfaceTypeStruct("nil", "", make([]structField, 0)); - -// -- Func - -// FuncType represents a function type. -type FuncType interface { - Type; - In() StructType; // The parameters in the form of a StructType. - Out() StructType; // The results in the form of a StructType. -} - -type funcTypeStruct struct { - commonType; - in *structTypeStruct; - out *structTypeStruct; -} - -func newFuncTypeStruct(name, typestring string, in, out *structTypeStruct) *funcTypeStruct { - return &funcTypeStruct{ commonType{FuncKind, typestring, name, ptrsize}, in, out } -} - -func (t *funcTypeStruct) FieldAlign() int { - return unsafe.Alignof(x.xfunc); -} - -func (t *funcTypeStruct) In() StructType { - return t.in -} - -func (t *funcTypeStruct) Out() StructType { - if t.out == nil { // nil.(StructType) != nil so make sure caller sees real nil - return nil - } - return t.out -} - -// Cache of expanded types keyed by type name. -var types map[string] Type - -// List of typename, typestring pairs -var typestring map[string] string -var initialized bool = false - -// Map of basic types to prebuilt stubTypes -var basicstub map[string] *stubType - -var missingStub *stubType; -var dotDotDotStub *stubType; - -// The database stored in the maps is global; use locking to guarantee safety. -var typestringlock sync.Mutex - -func lock() { - typestringlock.Lock() -} - -func unlock() { - typestringlock.Unlock() -} - -func init() { - lock(); // not necessary because of init ordering but be safe. - - types = make(map[string] Type); - typestring = make(map[string] string); - basicstub = make(map[string] *stubType); - - // Basics go into types table - types[missingString] = Missing; - types[dotDotDotString] = DotDotDot; - types["int"] = Int; - types["int8"] = Int8; - types["int16"] = Int16; - types["int32"] = Int32; - types["int64"] = Int64; - types["uint"] = Uint; - types["uint8"] = Uint8; - types["uint16"] = Uint16; - types["uint32"] = Uint32; - types["uint64"] = Uint64; - types["uintptr"] = Uintptr; - types["float"] = Float; - types["float32"] = Float32; - types["float64"] = Float64; - types["string"] = String; - types["bool"] = Bool; - - // Basics get prebuilt stubs - missingStub = newStubType(missingString, Missing); - dotDotDotStub = newStubType(dotDotDotString, DotDotDot); - basicstub[missingString] = missingStub; - basicstub[dotDotDotString] = dotDotDotStub; - basicstub["int"] = newStubType("int", Int); - basicstub["int8"] = newStubType("int8", Int8); - basicstub["int16"] = newStubType("int16", Int16); - basicstub["int32"] = newStubType("int32", Int32); - basicstub["int64"] = newStubType("int64", Int64); - basicstub["uint"] = newStubType("uint", Uint); - basicstub["uint8"] = newStubType("uint8", Uint8); - basicstub["uint16"] = newStubType("uint16", Uint16); - basicstub["uint32"] = newStubType("uint32", Uint32); - basicstub["uint64"] = newStubType("uint64", Uint64); - basicstub["uintptr"] = newStubType("uintptr", Uintptr); - basicstub["float"] = newStubType("float", Float); - basicstub["float32"] = newStubType("float32", Float32); - basicstub["float64"] = newStubType("float64", Float64); - basicstub["string"] = newStubType("string", String); - basicstub["bool"] = newStubType("bool", Bool); - - unlock(); -} - -/* - Parsing of type strings. These strings are how the run-time recovers type - information dynamically. - - Grammar - - stubtype = - represent as StubType when possible - type - identifier = - name - '?' - type = - basictypename - int8, string, etc. - typename - arraytype - structtype - interfacetype - chantype - maptype - pointertype - functiontype - typename = - name '.' name - doublequotedstring = - string in " "; escapes are \x00 (NUL) \n \t \" \\ - fieldlist = - [ field { [ ',' | ';' ] field } ] - field = - identifier stubtype [ doublequotedstring ] - arraytype = - '[' [ number ] ']' stubtype - structtype = - 'struct' '{' fieldlist '}' - interfacetype = - 'interface' '{' fieldlist '}' - chantype = - '<-' 'chan' stubtype - 'chan' '<-' stubtype - 'chan' stubtype - maptype = - 'map' '[' stubtype ']' stubtype - pointertype = - '*' stubtype - functiontype = - [ 'func' ] '(' fieldlist ')' [ '(' fieldlist ')' | stubtype ] - - In functiontype 'func' is optional because it is omitted in - the reflection string for interface types. - -*/ - -// Helper functions for token scanning -func isdigit(c uint8) bool { - return '0' <= c && c <= '9' -} - -func special(c uint8) bool { - s := "*[](){}<;,"; // Note: '.' is not in this list. "P.T" is an identifer, as is "?". - for i := 0; i < len(s); i++ { - if c == s[i] { - return true - } - } - return false; -} - -func hex00(s string, i int) bool { - return i + 2 < len(s) && s[i] == '0' && s[i+1] == '0' -} - -// Process backslashes. String known to be well-formed. -// Initial double-quote is left in, as an indication this token is a string. -func unescape(s string, backslash bool) string { - if !backslash { - return s - } - out := "\""; - for i := 1; i < len(s); i++ { - c := s[i]; - if c == '\\' { - i++; - c = s[i]; - switch c { - case 'n': - c = '\n'; - case 't': - c = '\t'; - case 'x': - if hex00(s, i+1) { - i += 2; - c = 0; - break; - } - // otherwise just put an 'x'; erroneous but safe. - // default is correct already; \\ is \; \" is " - } - } - out += string(c); - } - return out; -} - -// Simple parser for type strings -type typeParser struct { - str string; // string being parsed - token string; // the token being parsed now - tokstart int; // starting position of token - prevend int; // (one after) ending position of previous token - index int; // next character position in str -} - -// Return typestring starting at position i. It will finish at the -// end of the previous token (before trailing white space). -func (p *typeParser) TypeString(i int) string { - return p.str[i:p.prevend]; -} - -// Load next token into p.token -func (p *typeParser) Next() { - p.prevend = p.index; - token := ""; - for ; p.index < len(p.str) && p.str[p.index] == ' '; p.index++ { - } - p.tokstart = p.index; - if p.index >= len(p.str) { - p.token = ""; - return; - } - start := p.index; - c, w := utf8.DecodeRuneInString(p.str[p.index:len(p.str)]); - p.index += w; - switch { - case c == '<': - if p.index < len(p.str) && p.str[p.index] == '-' { - p.index++; - p.token = "<-"; - return; - } - fallthrough; // shouldn't happen but let the parser figure it out - case c == '.': - if p.index < len(p.str)+2 && p.str[p.index-1:p.index+2] == dotDotDotString { - p.index += 2; - p.token = dotDotDotString; - return; - } - fallthrough; // shouldn't happen but let the parser figure it out - case special(uint8(c)): - p.token = string(c); - return; - case isdigit(uint8(c)): - for p.index < len(p.str) && isdigit(p.str[p.index]) { - p.index++ - } - p.token = p.str[start : p.index]; - return; - case c == '"': // double-quoted string for struct field annotation - backslash := false; - for p.index < len(p.str) && p.str[p.index] != '"' { - if p.str[p.index] == '\\' { - if p.index+1 == len(p.str) { // bad final backslash - break; - } - p.index++; // skip (and accept) backslash - backslash = true; - } - p.index++ - } - p.token = unescape(p.str[start : p.index], backslash); - if p.index < len(p.str) { // properly terminated string - p.index++; // skip the terminating double-quote - } - return; - } - for p.index < len(p.str) && p.str[p.index] != ' ' && !special(p.str[p.index]) { - p.index++ - } - p.token = p.str[start : p.index]; -} - -func (p *typeParser) Type(name string) *stubType - -func (p *typeParser) Array(name string, tokstart int) *stubType { - size := 0; - open := true; - if p.token != "]" { - if len(p.token) == 0 || !isdigit(p.token[0]) { - return missingStub - } - // write our own (trivial and simpleminded) atoi to avoid dependency - size = 0; - for i := 0; i < len(p.token); i++ { - size = size * 10 + int(p.token[i]) - '0' - } - p.Next(); - open = false; - } - if p.token != "]" { - return missingStub - } - p.Next(); - elemtype := p.Type(""); - return newStubType(name, newArrayTypeStruct(name, p.TypeString(tokstart), open, size, elemtype)); -} - -func (p *typeParser) Map(name string, tokstart int) *stubType { - if p.token != "[" { - return missingStub - } - p.Next(); - keytype := p.Type(""); - if p.token != "]" { - return missingStub - } - p.Next(); - elemtype := p.Type(""); - return newStubType(name, newMapTypeStruct(name, p.TypeString(tokstart), keytype, elemtype)); -} - -func (p *typeParser) Chan(name string, tokstart, dir int) *stubType { - if p.token == "<-" { - if dir != BothDir { - return missingStub - } - p.Next(); - dir = SendDir; - } - elemtype := p.Type(""); - return newStubType(name, newChanTypeStruct(name, p.TypeString(tokstart), dir, elemtype)); -} - -// Parse array of fields for struct, interface, and func arguments -func (p *typeParser) Fields(sep, term string) []structField { - a := make([]structField, 10); - nf := 0; - for p.token != "" && p.token != term { - if nf == len(a) { - a1 := make([]structField, 2*nf); - for i := 0; i < nf; i++ { - a1[i] = a[i]; - } - a = a1; - } - name := p.token; - if name == "?" { // used to represent a missing name - name = "" - } - a[nf].name = name; - p.Next(); - a[nf].typ = p.Type(""); - if p.token != "" && p.token[0] == '"' { - a[nf].tag = p.token[1:len(p.token)]; - p.Next(); - } - nf++; - if p.token != sep { - break; - } - p.Next(); // skip separator - } - return a[0:nf]; -} - -// A single type packaged as a field for a function return -func (p *typeParser) OneField() []structField { - a := make([]structField, 1); - a[0].name = ""; - a[0].typ = p.Type(""); - return a; -} - -func (p *typeParser) Struct(name string, tokstart int) *stubType { - f := p.Fields(";", "}"); - if p.token != "}" { - return missingStub; - } - p.Next(); - return newStubType(name, newStructTypeStruct(name, p.TypeString(tokstart), f)); -} - -func (p *typeParser) Interface(name string, tokstart int) *stubType { - f := p.Fields(";", "}"); - if p.token != "}" { - return missingStub; - } - p.Next(); - return newStubType(name, newInterfaceTypeStruct(name, p.TypeString(tokstart), f)); -} - -func (p *typeParser) Func(name string, tokstart int) *stubType { - // may be 1 or 2 parenthesized lists - f1 := newStructTypeStruct("", "", p.Fields(",", ")")); - if p.token != ")" { - return missingStub; - } - p.Next(); - if p.token != "(" { - // 1 list: the in parameters are a list. Is there a single out parameter? - switch p.token { - case "", "}", ")", ",", ";": - return newStubType(name, newFuncTypeStruct(name, p.TypeString(tokstart), f1, nil)); - } - // A single out parameter. - f2 := newStructTypeStruct("", "", p.OneField()); - return newStubType(name, newFuncTypeStruct(name, p.TypeString(tokstart), f1, f2)); - } else { - p.Next(); - } - f2 := newStructTypeStruct("", "", p.Fields(",", ")")); - if p.token != ")" { - return missingStub; - } - p.Next(); - // 2 lists: the in and out parameters are present - return newStubType(name, newFuncTypeStruct(name, p.TypeString(tokstart), f1, f2)); -} - -func (p *typeParser) Type(name string) *stubType { - dir := BothDir; - tokstart := p.tokstart; - switch { - case p.token == "": - return nil; - case p.token == "*": - p.Next(); - sub := p.Type(""); - return newStubType(name, newPtrTypeStruct(name, p.TypeString(tokstart), sub)); - case p.token == "[": - p.Next(); - return p.Array(name, tokstart); - case p.token == "map": - p.Next(); - return p.Map(name, tokstart); - case p.token == "<-": - p.Next(); - dir = RecvDir; - if p.token != "chan" { - return missingStub; - } - fallthrough; - case p.token == "chan": - p.Next(); - return p.Chan(name, tokstart, dir); - case p.token == "struct": - p.Next(); - if p.token != "{" { - return missingStub - } - p.Next(); - return p.Struct(name, tokstart); - case p.token == "interface": - p.Next(); - if p.token != "{" { - return missingStub - } - p.Next(); - return p.Interface(name, tokstart); - case p.token == "func": - p.Next(); - if p.token != "(" { - return missingStub - } - p.Next(); - return p.Func(name, tokstart); - case p.token == "(": - p.Next(); - return p.Func(name, tokstart); - case isdigit(p.token[0]): - p.Next(); - return missingStub; - case special(p.token[0]): - p.Next(); - return missingStub; - } - // must be an identifier. is it basic? if so, we have a stub - if s, ok := basicstub[p.token]; ok { - p.Next(); - if name != "" { - // Need to make a copy because we are renaming a basic type - b := s.Get(); - s = newStubType(name, newBasicType(name, b.Kind(), b.Size(), b.FieldAlign())); - } - return s - } - // not a basic - must be of the form "P.T" - ndot := 0; - for i := 0; i < len(p.token); i++ { - if p.token[i] == '.' { - ndot++ - } - } - if ndot != 1 { - p.Next(); - return missingStub; - } - s := newStubType(p.token, nil); - p.Next(); - return s; -} - -// ParseTypeString takes a type name and type string (such as "[]int") and -// returns the Type structure representing a type name specifying the corresponding -// type. An empty typestring represents (the type of) a nil interface value. -func ParseTypeString(name, typestring string) Type { - if typestring == "" { - // If the typestring is empty, it represents (the type of) a nil interface value - return nilInterface - } - p := new(typeParser); - p.str = typestring; - p.Next(); - return p.Type(name).Get(); -} - -// Create typestring map from reflect.typestrings() data. Lock is held. -func initializeTypeStrings() { - if initialized { - return - } - initialized = true; - s := typestrings(); - slen := len(s); - for i := 0; i < slen; { - // "reflect.PtrType interface { Sub () (? reflect.Type) }\n" - // find the identifier - idstart := i; - for ; i < slen && s[i] != ' '; i++ { - } - if i == slen { - print("reflect.InitializeTypeStrings: bad identifier\n"); - return; - } - idend := i; - i++; - // find the end of the line, terminating the type - typestart := i; - for ; i < slen && s[i] != '\n'; i++ { - } - if i == slen { - print("reflect.InitializeTypeStrings: bad type string\n"); - return; - } - typeend := i; - i++; //skip newline - typestring[s[idstart:idend]] = s[typestart:typeend]; - } -} - -// Look up type string associated with name. Lock is held. -func typeNameToTypeString(name string) string { - s, ok := typestring[name]; - if !ok { - initializeTypeStrings(); - s, ok = typestring[name]; - if !ok { - s = missingString; - typestring[name] = s; - } - } - return s -} - -// ExpandType takes the name of a type and returns its Type structure, -// unpacking the associated type string if necessary. -func ExpandType(name string) Type { - lock(); - t, ok := types[name]; - if ok { - unlock(); - return t - } - types[name] = Missing; // prevent recursion; will overwrite - t1 := ParseTypeString(name, typeNameToTypeString(name)); - types[name] = t1; - unlock(); - return t1; -} diff --git a/src/lib/reflect/typestring.c b/src/lib/reflect/typestring.c deleted file mode 100644 index 667037bb1..000000000 --- a/src/lib/reflect/typestring.c +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - - -extern char gotypestrings[]; // 4-byte count followed by byte[count] - -void FLUSH(void*); - -typedef struct String String; -struct String -{ - char* str; - char len[4]; - char cap[4]; -}; - -void -reflect·typestrings(String str) -{ - char *s; - int i; - - s = gotypestrings; - - // repeat the count twice - // once for len, once for cap - for(i=0; i<4; i++) { - str.len[i] = s[i]; - str.cap[i] = s[i]; - } - - // and the pointer - str.str = s+4; - - FLUSH(&str); -} diff --git a/src/lib/reflect/value.go b/src/lib/reflect/value.go deleted file mode 100644 index d4783d546..000000000 --- a/src/lib/reflect/value.go +++ /dev/null @@ -1,996 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Reflection library. -// Handling values. - -package reflect - -import ( - "reflect"; - "unsafe"; -) - -// Addr is shorthand for unsafe.Pointer and is used to represent the address of Values. -type Addr unsafe.Pointer - -func equalType(a, b Type) bool { - return a.String() == b.String() -} - -// Value is the generic interface to reflection values. Once its Kind is known, -// such as BoolKind, the Value can be narrowed to the appropriate, more -// specific interface, such as BoolValue. Such narrowed values still implement -// the Value interface. -type Value interface { - // The kind of thing described: ArrayKind, BoolKind, etc. - Kind() int; - // The reflection Type of the value. - Type() Type; - // The address of the value. - Addr() Addr; - // The value itself is the dynamic value of an empty interface. - Interface() interface {}; -} - -func NewValue(e interface{}) Value; - -// commonValue fields and functionality for all values - -type commonValue struct { - kind int; - typ Type; - addr Addr; -} - -func (c *commonValue) Kind() int { - return c.kind -} - -func (c *commonValue) Type() Type { - return c.typ -} - -func (c *commonValue) Addr() Addr { - return c.addr -} - -func (c *commonValue) Interface() interface {} { - var i interface {}; - switch { - case c.typ.Kind() == InterfaceKind: - panic("not reached"); // InterfaceValue overrides this method - case c.typ.Size() > unsafe.Sizeof(uintptr(0)): - i = unsafe.Unreflect(uint64(uintptr(c.addr)), c.typ.String(), true); - default: - if uintptr(c.addr) == 0 { - panicln("reflect: address 0 for", c.typ.String()); - } - i = unsafe.Unreflect(uint64(uintptr(*(*Addr)(c.addr))), c.typ.String(), false); - } - return i; -} - -func newValueAddr(typ Type, addr Addr) Value - -type creatorFn func(typ Type, addr Addr) Value - - -// -- Missing - -// MissingValue represents a value whose type is not known. It usually -// indicates an error. -type MissingValue interface { - Value; -} - -type missingValueStruct struct { - commonValue -} - -func missingCreator(typ Type, addr Addr) Value { - return &missingValueStruct{ commonValue{MissingKind, typ, addr} } -} - -// -- Int - -// IntValue represents an int value. -type IntValue interface { - Value; - Get() int; // Get the underlying int. - Set(int); // Set the underlying int. -} - -type intValueStruct struct { - commonValue -} - -func intCreator(typ Type, addr Addr) Value { - return &intValueStruct{ commonValue{IntKind, typ, addr} } -} - -func (v *intValueStruct) Get() int { - return *(*int)(v.addr) -} - -func (v *intValueStruct) Set(i int) { - *(*int)(v.addr) = i -} - -// -- Int8 - -// Int8Value represents an int8 value. -type Int8Value interface { - Value; - Get() int8; // Get the underlying int8. - Set(int8); // Set the underlying int8. -} - -type int8ValueStruct struct { - commonValue -} - -func int8Creator(typ Type, addr Addr) Value { - return &int8ValueStruct{ commonValue{Int8Kind, typ, addr} } -} - -func (v *int8ValueStruct) Get() int8 { - return *(*int8)(v.addr) -} - -func (v *int8ValueStruct) Set(i int8) { - *(*int8)(v.addr) = i -} - -// -- Int16 - -// Int16Value represents an int16 value. -type Int16Value interface { - Value; - Get() int16; // Get the underlying int16. - Set(int16); // Set the underlying int16. -} - -type int16ValueStruct struct { - commonValue -} - -func int16Creator(typ Type, addr Addr) Value { - return &int16ValueStruct{ commonValue{Int16Kind, typ, addr} } -} - -func (v *int16ValueStruct) Get() int16 { - return *(*int16)(v.addr) -} - -func (v *int16ValueStruct) Set(i int16) { - *(*int16)(v.addr) = i -} - -// -- Int32 - -// Int32Value represents an int32 value. -type Int32Value interface { - Value; - Get() int32; // Get the underlying int32. - Set(int32); // Set the underlying int32. -} - -type int32ValueStruct struct { - commonValue -} - -func int32Creator(typ Type, addr Addr) Value { - return &int32ValueStruct{ commonValue{Int32Kind, typ, addr} } -} - -func (v *int32ValueStruct) Get() int32 { - return *(*int32)(v.addr) -} - -func (v *int32ValueStruct) Set(i int32) { - *(*int32)(v.addr) = i -} - -// -- Int64 - -// Int64Value represents an int64 value. -type Int64Value interface { - Value; - Get() int64; // Get the underlying int64. - Set(int64); // Set the underlying int64. -} - -type int64ValueStruct struct { - commonValue -} - -func int64Creator(typ Type, addr Addr) Value { - return &int64ValueStruct{ commonValue{Int64Kind, typ, addr} } -} - -func (v *int64ValueStruct) Get() int64 { - return *(*int64)(v.addr) -} - -func (v *int64ValueStruct) Set(i int64) { - *(*int64)(v.addr) = i -} - -// -- Uint - -// UintValue represents a uint value. -type UintValue interface { - Value; - Get() uint; // Get the underlying uint. - Set(uint); // Set the underlying uint. -} - -type uintValueStruct struct { - commonValue -} - -func uintCreator(typ Type, addr Addr) Value { - return &uintValueStruct{ commonValue{UintKind, typ, addr} } -} - -func (v *uintValueStruct) Get() uint { - return *(*uint)(v.addr) -} - -func (v *uintValueStruct) Set(i uint) { - *(*uint)(v.addr) = i -} - -// -- Uint8 - -// Uint8Value represents a uint8 value. -type Uint8Value interface { - Value; - Get() uint8; // Get the underlying uint8. - Set(uint8); // Set the underlying uint8. -} - -type uint8ValueStruct struct { - commonValue -} - -func uint8Creator(typ Type, addr Addr) Value { - return &uint8ValueStruct{ commonValue{Uint8Kind, typ, addr} } -} - -func (v *uint8ValueStruct) Get() uint8 { - return *(*uint8)(v.addr) -} - -func (v *uint8ValueStruct) Set(i uint8) { - *(*uint8)(v.addr) = i -} - -// -- Uint16 - -// Uint16Value represents a uint16 value. -type Uint16Value interface { - Value; - Get() uint16; // Get the underlying uint16. - Set(uint16); // Set the underlying uint16. -} - -type uint16ValueStruct struct { - commonValue -} - -func uint16Creator(typ Type, addr Addr) Value { - return &uint16ValueStruct{ commonValue{Uint16Kind, typ, addr} } -} - -func (v *uint16ValueStruct) Get() uint16 { - return *(*uint16)(v.addr) -} - -func (v *uint16ValueStruct) Set(i uint16) { - *(*uint16)(v.addr) = i -} - -// -- Uint32 - -// Uint32Value represents a uint32 value. -type Uint32Value interface { - Value; - Get() uint32; // Get the underlying uint32. - Set(uint32); // Set the underlying uint32. -} - -type uint32ValueStruct struct { - commonValue -} - -func uint32Creator(typ Type, addr Addr) Value { - return &uint32ValueStruct{ commonValue{Uint32Kind, typ, addr} } -} - -func (v *uint32ValueStruct) Get() uint32 { - return *(*uint32)(v.addr) -} - -func (v *uint32ValueStruct) Set(i uint32) { - *(*uint32)(v.addr) = i -} - -// -- Uint64 - -// Uint64Value represents a uint64 value. -type Uint64Value interface { - Value; - Get() uint64; // Get the underlying uint64. - Set(uint64); // Set the underlying uint64. -} - -type uint64ValueStruct struct { - commonValue -} - -func uint64Creator(typ Type, addr Addr) Value { - return &uint64ValueStruct{ commonValue{Uint64Kind, typ, addr} } -} - -func (v *uint64ValueStruct) Get() uint64 { - return *(*uint64)(v.addr) -} - -func (v *uint64ValueStruct) Set(i uint64) { - *(*uint64)(v.addr) = i -} - -// -- Uintptr - -// UintptrValue represents a uintptr value. -type UintptrValue interface { - Value; - Get() uintptr; // Get the underlying uintptr. - Set(uintptr); // Set the underlying uintptr. -} - -type uintptrValueStruct struct { - commonValue -} - -func uintptrCreator(typ Type, addr Addr) Value { - return &uintptrValueStruct{ commonValue{UintptrKind, typ, addr} } -} - -func (v *uintptrValueStruct) Get() uintptr { - return *(*uintptr)(v.addr) -} - -func (v *uintptrValueStruct) Set(i uintptr) { - *(*uintptr)(v.addr) = i -} - -// -- Float - -// FloatValue represents a float value. -type FloatValue interface { - Value; - Get() float; // Get the underlying float. - Set(float); // Get the underlying float. -} - -type floatValueStruct struct { - commonValue -} - -func floatCreator(typ Type, addr Addr) Value { - return &floatValueStruct{ commonValue{FloatKind, typ, addr} } -} - -func (v *floatValueStruct) Get() float { - return *(*float)(v.addr) -} - -func (v *floatValueStruct) Set(f float) { - *(*float)(v.addr) = f -} - -// -- Float32 - -// Float32Value represents a float32 value. -type Float32Value interface { - Value; - Get() float32; // Get the underlying float32. - Set(float32); // Get the underlying float32. -} - -type float32ValueStruct struct { - commonValue -} - -func float32Creator(typ Type, addr Addr) Value { - return &float32ValueStruct{ commonValue{Float32Kind, typ, addr} } -} - -func (v *float32ValueStruct) Get() float32 { - return *(*float32)(v.addr) -} - -func (v *float32ValueStruct) Set(f float32) { - *(*float32)(v.addr) = f -} - -// -- Float64 - -// Float64Value represents a float64 value. -type Float64Value interface { - Value; - Get() float64; // Get the underlying float64. - Set(float64); // Get the underlying float64. -} - -type float64ValueStruct struct { - commonValue -} - -func float64Creator(typ Type, addr Addr) Value { - return &float64ValueStruct{ commonValue{Float64Kind, typ, addr} } -} - -func (v *float64ValueStruct) Get() float64 { - return *(*float64)(v.addr) -} - -func (v *float64ValueStruct) Set(f float64) { - *(*float64)(v.addr) = f -} - -// -- String - -// StringValue represents a string value. -type StringValue interface { - Value; - Get() string; // Get the underlying string value. - Set(string); // Set the underlying string value. -} - -type stringValueStruct struct { - commonValue -} - -func stringCreator(typ Type, addr Addr) Value { - return &stringValueStruct{ commonValue{StringKind, typ, addr} } -} - -func (v *stringValueStruct) Get() string { - return *(*string)(v.addr) -} - -func (v *stringValueStruct) Set(s string) { - *(*string)(v.addr) = s -} - -// -- Bool - -// BoolValue represents a bool value. -type BoolValue interface { - Value; - Get() bool; // Get the underlying bool value. - Set(bool); // Set the underlying bool value. -} - -type boolValueStruct struct { - commonValue -} - -func boolCreator(typ Type, addr Addr) Value { - return &boolValueStruct{ commonValue{BoolKind, typ, addr} } -} - -func (v *boolValueStruct) Get() bool { - return *(*bool)(v.addr) -} - -func (v *boolValueStruct) Set(b bool) { - *(*bool)(v.addr) = b -} - -// -- Pointer - -// PtrValue represents a pointer value. -type PtrValue interface { - Value; - Sub() Value; // The Value pointed to. - Get() Addr; // Get the address stored in the pointer. - SetSub(Value); // Set the the pointed-to Value. - IsNil() bool; -} - -type ptrValueStruct struct { - commonValue -} - -func (v *ptrValueStruct) Get() Addr { - return *(*Addr)(v.addr) -} - -func (v *ptrValueStruct) Sub() Value { - return newValueAddr(v.typ.(PtrType).Sub(), v.Get()); -} - -func (v *ptrValueStruct) SetSub(subv Value) { - a := v.typ.(PtrType).Sub(); - b := subv.Type(); - if !equalType(a, b) { - panicln("reflect: incompatible types in PtrValue.SetSub:", - a.String(), b.String()); - } - *(*Addr)(v.addr) = subv.Addr(); -} - -func (v *ptrValueStruct) IsNil() bool { - return uintptr(*(*Addr)(v.addr)) == 0 -} - -func ptrCreator(typ Type, addr Addr) Value { - return &ptrValueStruct{ commonValue{PtrKind, typ, addr} }; -} - -// -- Array -// Slices and arrays are represented by the same interface. - -// ArrayValue represents an array or slice value. -type ArrayValue interface { - Value; - IsSlice() bool; // Is this a slice (true) or array (false)? - Len() int; // The length of the array/slice. - Cap() int; // The capacity of the array/slice (==Len() for arrays). - Elem(i int) Value; // The Value of the i'th element. - SetLen(len int); // Set the length; slice only. - Set(src ArrayValue); // Set the underlying Value; slice only for src and dest both. - CopyFrom(src ArrayValue, n int); // Copy the elements from src; lengths must match. - IsNil() bool; -} - -func copyArray(dst ArrayValue, src ArrayValue, n int); - -/* - Run-time representation of slices looks like this: - struct Slice { - byte* array; // actual data - uint32 nel; // number of elements - uint32 cap; - }; -*/ -type runtimeSlice struct { - data Addr; - len uint32; - cap uint32; -} - -type sliceValueStruct struct { - commonValue; - elemtype Type; - elemsize int; - slice *runtimeSlice; -} - -func (v *sliceValueStruct) IsSlice() bool { - return true -} - -func (v *sliceValueStruct) Len() int { - return int(v.slice.len); -} - -func (v *sliceValueStruct) Cap() int { - return int(v.slice.cap); -} - -func (v *sliceValueStruct) SetLen(len int) { - if len > v.Cap() { - panicln("reflect: sliceValueStruct.SetLen", len, v.Cap()); - } - v.slice.len = uint32(len); -} - -func (v *sliceValueStruct) Set(src ArrayValue) { - if !src.IsSlice() { - panic("can't set slice from array"); - } - s := src.(*sliceValueStruct); - if !equalType(v.typ, s.typ) { - panicln("incompatible types in ArrayValue.Set()"); - } - *v.slice = *s.slice; -} - -func (v *sliceValueStruct) Elem(i int) Value { - data_uint := uintptr(v.slice.data) + uintptr(i * v.elemsize); - return newValueAddr(v.elemtype, Addr(data_uint)); -} - -func (v *sliceValueStruct) CopyFrom(src ArrayValue, n int) { - copyArray(v, src, n); -} - -func (v *sliceValueStruct) IsNil() bool { - return uintptr(v.slice.data) == 0 -} - -type arrayValueStruct struct { - commonValue; - elemtype Type; - elemsize int; - len int; -} - -func (v *arrayValueStruct) IsSlice() bool { - return false -} - -func (v *arrayValueStruct) Len() int { - return v.len -} - -func (v *arrayValueStruct) Cap() int { - return v.len -} - -func (v *arrayValueStruct) SetLen(len int) { - panicln("can't set len of array"); -} - -func (v *arrayValueStruct) Set(src ArrayValue) { - panicln("can't set array"); -} - -func (v *arrayValueStruct) Elem(i int) Value { - data_uint := uintptr(v.addr) + uintptr(i * v.elemsize); - return newValueAddr(v.elemtype, Addr(data_uint)); -} - -func (v *arrayValueStruct) CopyFrom(src ArrayValue, n int) { - copyArray(v, src, n); -} - -func (v *arrayValueStruct) IsNil() bool { - return false -} - -func arrayCreator(typ Type, addr Addr) Value { - arraytype := typ.(ArrayType); - if arraytype.IsSlice() { - v := new(sliceValueStruct); - v.kind = ArrayKind; - v.addr = addr; - v.typ = typ; - v.elemtype = arraytype.Elem(); - v.elemsize = v.elemtype.Size(); - v.slice = (*runtimeSlice)(addr); - return v; - } - v := new(arrayValueStruct); - v.kind = ArrayKind; - v.addr = addr; - v.typ = typ; - v.elemtype = arraytype.Elem(); - v.elemsize = v.elemtype.Size(); - v.len = arraytype.Len(); - return v; -} - -// -- Map TODO: finish and test - -// MapValue represents a map value. -// Its implementation is incomplete. -type MapValue interface { - Value; - Len() int; // The number of elements; currently always returns 0. - Elem(key Value) Value; // The value indexed by key; unimplemented. - IsNil() bool; -} - -type mapValueStruct struct { - commonValue -} - -func mapCreator(typ Type, addr Addr) Value { - return &mapValueStruct{ commonValue{MapKind, typ, addr} } -} - -func (v *mapValueStruct) Len() int { - return 0 // TODO: probably want this to be dynamic -} - -func (v *mapValueStruct) IsNil() bool { - return false // TODO: implement this properly -} - -func (v *mapValueStruct) Elem(key Value) Value { - panic("map value element"); - return nil -} - -// -- Chan - -// ChanValue represents a chan value. -// Its implementation is incomplete. -type ChanValue interface { - Value; - IsNil() bool; -} - -type chanValueStruct struct { - commonValue -} - -func (v *chanValueStruct) IsNil() bool { - return false // TODO: implement this properly -} - -func chanCreator(typ Type, addr Addr) Value { - return &chanValueStruct{ commonValue{ChanKind, typ, addr} } -} - -// -- Struct - -// StructValue represents a struct value. -type StructValue interface { - Value; - Len() int; // The number of fields. - Field(i int) Value; // The Value of field i. -} - -type structValueStruct struct { - commonValue; - field []Value; -} - -func (v *structValueStruct) Len() int { - return len(v.field) -} - -func (v *structValueStruct) Field(i int) Value { - return v.field[i] -} - -func structCreator(typ Type, addr Addr) Value { - t := typ.(StructType); - nfield := t.Len(); - v := &structValueStruct{ commonValue{StructKind, typ, addr}, make([]Value, nfield) }; - for i := 0; i < nfield; i++ { - name, ftype, str, offset := t.Field(i); - addr_uint := uintptr(addr) + uintptr(offset); - v.field[i] = newValueAddr(ftype, Addr(addr_uint)); - } - v.typ = typ; - return v; -} - -// -- Interface - -// InterfaceValue represents an interface value. -type InterfaceValue interface { - Value; - Get() interface {}; // Get the underlying interface{} value. - Value() Value; - IsNil() bool; -} - -type interfaceValueStruct struct { - commonValue -} - -func (v *interfaceValueStruct) Get() interface{} { - // There are two different representations of interface values, - // one if the interface type has methods and one if it doesn't. - // These two representations require different expressions - // to extract correctly. - if v.Type().(InterfaceType).Len() == 0 { - // Extract as interface value without methods. - return *(*interface{})(v.addr) - } - // Extract from v.addr as interface value with methods. - return *(*interface{ m() })(v.addr) -} - -func (v *interfaceValueStruct) Interface() interface{} { - return v.Get(); -} - -func (v *interfaceValueStruct) Value() Value { - i := v.Get(); - if i == nil { - return nil; - } - return NewValue(i); -} - -func (v *interfaceValueStruct) IsNil() bool { - return *(*interface{})(v.addr) == nil -} - -func interfaceCreator(typ Type, addr Addr) Value { - return &interfaceValueStruct{ commonValue{InterfaceKind, typ, addr} } -} - -// -- Func - - -// FuncValue represents a func value. -// Its implementation is incomplete. -type FuncValue interface { - Value; - Get() Addr; // The address of the function. - IsNil() bool; -} - -type funcValueStruct struct { - commonValue -} - -func (v *funcValueStruct) Get() Addr { - return *(*Addr)(v.addr) -} - -func (v *funcValueStruct) IsNil() bool { - return *(*Addr)(v.addr) == nil -} - -func funcCreator(typ Type, addr Addr) Value { - return &funcValueStruct{ commonValue{FuncKind, typ, addr} } -} - -var creator = map[int] creatorFn { - MissingKind : missingCreator, - IntKind : intCreator, - Int8Kind : int8Creator, - Int16Kind : int16Creator, - Int32Kind : int32Creator, - Int64Kind : int64Creator, - UintKind : uintCreator, - Uint8Kind : uint8Creator, - Uint16Kind : uint16Creator, - Uint32Kind : uint32Creator, - Uint64Kind : uint64Creator, - UintptrKind : uintptrCreator, - FloatKind : floatCreator, - Float32Kind : float32Creator, - Float64Kind : float64Creator, - StringKind : stringCreator, - BoolKind : boolCreator, - PtrKind : ptrCreator, - ArrayKind : arrayCreator, - MapKind : mapCreator, - ChanKind : chanCreator, - StructKind : structCreator, - InterfaceKind : interfaceCreator, - FuncKind : funcCreator, -} - -var typecache = make(map[string] Type); - -func newValueAddr(typ Type, addr Addr) Value { - c, ok := creator[typ.Kind()]; - if !ok { - panicln("no creator for type" , typ.String()); - } - return c(typ, addr); -} - -// NewZeroValue creates a new, zero-initialized Value for the specified Type. -func NewZeroValue(typ Type) Value { - size := typ.Size(); - if size == 0 { - size = 1; - } - data := make([]uint8, size); - return newValueAddr(typ, Addr(&data[0])); -} - -// NewSliceValue creates a new, zero-initialized slice value (ArrayValue) for the specified -// slice type (ArrayType), length, and capacity. -func NewSliceValue(typ ArrayType, len, cap int) ArrayValue { - if !typ.IsSlice() { - return nil - } - - array := new(runtimeSlice); - size := typ.Elem().Size() * cap; - if size == 0 { - size = 1; - } - data := make([]uint8, size); - array.data = Addr(&data[0]); - array.len = uint32(len); - array.cap = uint32(cap); - - return newValueAddr(typ, Addr(array)).(ArrayValue); -} - -// Works on both slices and arrays -func copyArray(dst ArrayValue, src ArrayValue, n int) { - if n == 0 { - return - } - dt := dst.Type().(ArrayType).Elem(); - st := src.Type().(ArrayType).Elem(); - if !equalType(dt, st) { - panicln("reflect: incompatible types in CopyArray:", - dt.String(), st.String()); - } - if n < 0 || n > dst.Len() || n > src.Len() { - panicln("reflect: CopyArray: invalid count", n); - } - dstp := uintptr(dst.Elem(0).Addr()); - srcp := uintptr(src.Elem(0).Addr()); - end := uintptr(n)*uintptr(dt.Size()); - if end % 8 == 0 { - for i := uintptr(0); i < end; i += 8{ - di := Addr(dstp + i); - si := Addr(srcp + i); - *(*uint64)(di) = *(*uint64)(si); - } - } else { - for i := uintptr(0); i < end; i++ { - di := Addr(dstp + i); - si := Addr(srcp + i); - *(*byte)(di) = *(*byte)(si); - } - } -} - -// NewValue creates a new Value from the interface{} object provided. -func NewValue(e interface {}) Value { - value, typestring, indir := unsafe.Reflect(e); - typ, ok := typecache[typestring]; - if !ok { - typ = ParseTypeString("", typestring); - if typ.Kind() == MissingKind { - // This can not happen: unsafe.Reflect should only - // ever tell us the names of types that exist. - // Of course it does happen, and when it does - // it is more helpful to catch it in action here than - // to see $missing$ in a later print. - panicln("missing type for", typestring); - } - typecache[typestring] = typ; - } - var ap Addr; - if indir { - // Content of interface is large and didn't - // fit, so it's a pointer to the actual content. - // We have an address, but we need to - // make a copy to avoid letting the caller - // edit the content inside the interface. - n := uintptr(typ.Size()); - data := make([]byte, n); - p1 := uintptr(Addr(&data[0])); - p2 := uintptr(value); - for i := uintptr(0); i < n; i++ { - *(*byte)(Addr(p1+i)) = *(*byte)(Addr(p2+i)); - } - ap = Addr(&data[0]); - } else { - // Content of interface is small and stored - // inside the interface. Make a copy so we - // can take its address. - x := new(uint64); - *x = value; - ap = Addr(x); - } - return newValueAddr(typ, ap); -} - -// Indirect indirects one level through a value, if it is a pointer. -// If not a pointer, the value is returned unchanged. -// Useful when walking arbitrary data structures. -func Indirect(v Value) Value { - if v.Kind() == PtrKind { - p := v.(PtrValue); - if p.Get() == nil { - return nil - } - v = p.Sub() - } - return v -} diff --git a/src/lib/regexp/Makefile b/src/lib/regexp/Makefile deleted file mode 100644 index 0312d510e..000000000 --- a/src/lib/regexp/Makefile +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m >Makefile - -D= - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - regexp.$O\ - - -phases: a1 -_obj$D/regexp.a: phases - -a1: $(O1) - $(AR) grc _obj$D/regexp.a regexp.$O - rm -f $(O1) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/regexp.a - -$(O1): newpkg -$(O2): a1 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/regexp.a - -packages: _obj$D/regexp.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/regexp.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/regexp.a diff --git a/src/lib/regexp/all_test.go b/src/lib/regexp/all_test.go deleted file mode 100644 index a9f275893..000000000 --- a/src/lib/regexp/all_test.go +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright 2009 The Go Authors. 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"; - "regexp"; - "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]`, -} - -// TODO: nice to do this with a map -type stringError struct { - re string; - err os.Error; -} -var bad_re = []stringError{ - stringError{ `*`, regexp.ErrBareClosure }, - stringError{ `(abc`, regexp.ErrUnmatchedLpar }, - stringError{ `abc)`, regexp.ErrUnmatchedRpar }, - stringError{ `x[a-z`, regexp.ErrUnmatchedLbkt }, - stringError{ `abc]`, regexp.ErrUnmatchedRbkt }, - stringError{ `[z-a]`, regexp.ErrBadRange }, - stringError{ `abc\`, regexp.ErrExtraneousBackslash }, - stringError{ `a**`, regexp.ErrBadClosure }, - stringError{ `a*+`, regexp.ErrBadClosure }, - stringError{ `a??`, regexp.ErrBadClosure }, - stringError{ `*`, regexp.ErrBareClosure }, - stringError{ `\x`, regexp.ErrBadBackslash }, -} - -type vec []int; - -type tester struct { - re string; - text string; - match vec; -} - -var matches = []tester { - tester{ ``, "", vec{0,0} }, - tester{ `a`, "a", vec{0,1} }, - tester{ `x`, "y", vec{} }, - tester{ `b`, "abc", vec{1,2} }, - tester{ `.`, "a", vec{0,1} }, - tester{ `.*`, "abcdef", vec{0,6} }, - tester{ `^abcd$`, "abcd", vec{0,4} }, - tester{ `^bcd'`, "abcdef", vec{} }, - tester{ `^abcd$`, "abcde", vec{} }, - tester{ `a+`, "baaab", vec{1,4} }, - tester{ `a*`, "baaab", vec{0,0} }, - tester{ `[a-z]+`, "abcd", vec{0,4} }, - tester{ `[^a-z]+`, "ab1234cd", vec{2,6} }, - tester{ `[a\-\]z]+`, "az]-bcz", vec{0,4} }, - tester{ `[日本語]+`, "日本語日本語", vec{0,18} }, - tester{ `()`, "", vec{0,0, 0,0} }, - tester{ `(a)`, "a", vec{0,1, 0,1} }, - tester{ `(.)(.)`, "日a", vec{0,4, 0,3, 3,4} }, - tester{ `(.*)`, "", vec{0,0, 0,0} }, - tester{ `(.*)`, "abcd", vec{0,4, 0,4} }, - tester{ `(..)(..)`, "abcd", vec{0,4, 0,2, 2,4} }, - tester{ `(([^xyz]*)(d))`, "abcd", vec{0,4, 0,4, 0,3, 3,4} }, - tester{ `((a|b|c)*(d))`, "abcd", vec{0,4, 0,4, 2,3, 3,4} }, - tester{ `(((a|b|c)*)(d))`, "abcd", vec{0,4, 0,4, 0,3, 2,3, 3,4} }, - tester{ `a*(|(b))c*`, "aacc", vec{0,4, 2,2, -1,-1} }, -} - -func compileTest(t *testing.T, expr string, error os.Error) *regexp.Regexp { - re, err := regexp.Compile(expr); - if err != error { - t.Error("compiling `", expr, "`; unexpected error: ", err.String()); - } - return re -} - -func printVec(t *testing.T, m []int) { - l := len(m); - if l == 0 { - t.Log("\t"); - } else { - for i := 0; i < l; i = i+2 { - t.Log("\t", m[i], ",", m[i+1]) - } - } -} - -func printStrings(t *testing.T, m []string) { - l := len(m); - if l == 0 { - t.Log("\t"); - } else { - for i := 0; i < l; i = i+2 { - t.Logf("\t%q", m[i]) - } - } -} - -func equal(m1, m2 []int) bool { - l := len(m1); - if l != len(m2) { - return false - } - for i := 0; i < l; i++ { - if m1[i] != m2[i] { - return false - } - } - return true -} - -func equalStrings(m1, m2 []string) bool { - l := len(m1); - if l != len(m2) { - return false - } - for i := 0; i < l; i++ { - if m1[i] != m2[i] { - return false - } - } - return true -} - -func executeTest(t *testing.T, expr string, str string, match []int) { - re := compileTest(t, expr, nil); - if re == nil { - return - } - m := re.Execute(str); - if !equal(m, match) { - t.Error("Execute failure on `", expr, "` matching `", str, "`:"); - printVec(t, m); - t.Log("should be:"); - printVec(t, match); - } -} - -func TestGoodCompile(t *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 TestExecute(t *testing.T) { - for i := 0; i < len(matches); i++ { - test := &matches[i]; - executeTest(t, test.re, test.text, test.match) - } -} - -func matchTest(t *testing.T, expr string, str string, match []int) { - re := compileTest(t, expr, nil); - if re == nil { - return - } - m := re.Match(str); - if m != (len(match) > 0) { - t.Error("Match failure on `", expr, "` matching `", str, "`:", m, "should be", len(match) > 0); - } -} - -func TestMatch(t *testing.T) { - for i := 0; i < len(matches); i++ { - test := &matches[i]; - matchTest(t, test.re, test.text, test.match) - } -} - -func matchStringsTest(t *testing.T, expr string, str string, match []int) { - re := compileTest(t, expr, nil); - if re == nil { - return - } - strs := make([]string, len(match)/2); - for i := 0; i < len(match); i++ { - strs[i/2] = str[match[i] : match[i+1]] - } - m := re.MatchStrings(str); - if !equalStrings(m, strs) { - t.Error("MatchStrings failure on `", expr, "` matching `", str, "`:"); - printStrings(t, m); - t.Log("should be:"); - printStrings(t, strs); - } -} - -func TestMatchStrings(t *testing.T) { - for i := 0; i < len(matches); i++ { - test := &matches[i]; - matchTest(t, test.re, test.text, test.match) - } -} - -func matchFunctionTest(t *testing.T, expr string, str string, match []int) { - m, err := Match(expr, str); - if err == nil { - return - } - if m != (len(match) > 0) { - t.Error("function Match failure on `", expr, "` matching `", str, "`:", m, "should be", len(match) > 0); - } -} - -func TestMatchFunction(t *testing.T) { - for i := 0; i < len(matches); i++ { - test := &matches[i]; - matchFunctionTest(t, test.re, test.text, test.match) - } -} diff --git a/src/lib/regexp/regexp.go b/src/lib/regexp/regexp.go deleted file mode 100644 index b79800dd9..000000000 --- a/src/lib/regexp/regexp.go +++ /dev/null @@ -1,764 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package regexp implements a simple regular expression library. -// -// The syntax of the regular expressions accepted is: -// -// regexp: -// concatenation { '|' concatenation } -// concatenation: -// { closure } -// closure: -// term [ '*' | '+' | '?' ] -// term: -// '^' -// '$' -// '.' -// character -// '[' [ '^' ] character-ranges ']' -// '(' regexp ')' -// -package regexp - -import ( - "container/vector"; - "os"; - "runtime"; - "utf8"; -) - -var debug = false; - -// Error codes returned by failures to parse an expression. -var ( - ErrInternal = os.NewError("internal error"); - ErrUnmatchedLpar = os.NewError("unmatched '('"); - ErrUnmatchedRpar = os.NewError("unmatched ')'"); - ErrUnmatchedLbkt = os.NewError("unmatched '['"); - ErrUnmatchedRbkt = os.NewError("unmatched ']'"); - ErrBadRange = os.NewError("bad range in character class"); - ErrExtraneousBackslash = os.NewError("extraneous backslash"); - ErrBadClosure = os.NewError("repeated closure (**, ++, etc.)"); - ErrBareClosure = os.NewError("closure applies to nothing"); - ErrBadBackslash = os.NewError("illegal backslash escape"); -) - -// An instruction executed by the NFA -type instr interface { - kind() int; // the type of this instruction: _CHAR, _ANY, etc. - next() instr; // the instruction to execute after this one - setNext(i instr); - index() int; - setIndex(i int); - print(); -} - -// Fields and methods common to all instructions -type common struct { - _next instr; - _index int; -} - -func (c *common) next() instr { return c._next } -func (c *common) setNext(i instr) { c._next = i } -func (c *common) index() int { return c._index } -func (c *common) setIndex(i int) { c._index = i } - -// The representation of a compiled regular expression. -// The public interface is entirely through methods. -type Regexp struct { - expr string; // the original expression - ch chan<- *Regexp; // reply channel when we're done - error os.Error; // compile- or run-time error; nil if OK - inst *vector.Vector; - start instr; - nbra int; // number of brackets in expression, for subexpressions -} - -const ( - _START // beginning of program - = iota; - _END; // end of program: success - _BOT; // '^' beginning of text - _EOT; // '$' end of text - _CHAR; // 'a' regular character - _CHARCLASS; // [a-z] character class - _ANY; // '.' any character - _BRA; // '(' parenthesized expression - _EBRA; // ')'; end of '(' parenthesized expression - _ALT; // '|' alternation - _NOP; // do nothing; makes it easy to link without patching -) - -// --- START start of program -type _Start struct { - common -} - -func (start *_Start) kind() int { return _START } -func (start *_Start) print() { print("start") } - -// --- END end of program -type _End struct { - common -} - -func (end *_End) kind() int { return _END } -func (end *_End) print() { print("end") } - -// --- BOT beginning of text -type _Bot struct { - common -} - -func (bot *_Bot) kind() int { return _BOT } -func (bot *_Bot) print() { print("bot") } - -// --- EOT end of text -type _Eot struct { - common -} - -func (eot *_Eot) kind() int { return _EOT } -func (eot *_Eot) print() { print("eot") } - -// --- CHAR a regular character -type _Char struct { - common; - char int; -} - -func (char *_Char) kind() int { return _CHAR } -func (char *_Char) print() { print("char ", string(char.char)) } - -func newChar(char int) *_Char { - c := new(_Char); - c.char = char; - return c; -} - -// --- CHARCLASS [a-z] - -type _CharClass struct { - common; - char int; - negate bool; // is character class negated? ([^a-z]) - // vector of int, stored pairwise: [a-z] is (a,z); x is (x,x): - ranges *vector.IntVector; -} - -func (cclass *_CharClass) kind() int { return _CHARCLASS } - -func (cclass *_CharClass) print() { - print("charclass"); - if cclass.negate { - print(" (negated)"); - } - for i := 0; i < cclass.ranges.Len(); i += 2 { - l := cclass.ranges.At(i); - r := cclass.ranges.At(i+1); - 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.Push(a); - cclass.ranges.Push(b); -} - -func (cclass *_CharClass) matches(c int) bool { - for i := 0; i < cclass.ranges.Len(); i = i+2 { - min := cclass.ranges.At(i); - max := cclass.ranges.At(i+1); - if min <= c && c <= max { - return !cclass.negate - } - } - return cclass.negate -} - -func newCharClass() *_CharClass { - c := new(_CharClass); - c.ranges = vector.NewIntVector(0); - return c; -} - -// --- ANY any character -type _Any struct { - common -} - -func (any *_Any) kind() int { return _ANY } -func (any *_Any) print() { print("any") } - -// --- BRA parenthesized expression -type _Bra struct { - common; - n int; // subexpression number -} - -func (bra *_Bra) kind() int { return _BRA } -func (bra *_Bra) print() { print("bra", bra.n); } - -// --- EBRA end of parenthesized expression -type _Ebra struct { - common; - n int; // subexpression number -} - -func (ebra *_Ebra) kind() int { return _EBRA } -func (ebra *_Ebra) print() { print("ebra ", ebra.n); } - -// --- ALT alternation -type _Alt struct { - common; - left instr; // other branch -} - -func (alt *_Alt) kind() int { return _ALT } -func (alt *_Alt) print() { print("alt(", alt.left.index(), ")"); } - -// --- NOP no operation -type _Nop struct { - common -} - -func (nop *_Nop) kind() int { return _NOP } -func (nop *_Nop) print() { print("nop") } - -// report error and exit compiling/executing goroutine -func (re *Regexp) setError(err os.Error) { - re.error = err; - re.ch <- re; - runtime.Goexit(); -} - -func (re *Regexp) add(i instr) instr { - i.setIndex(re.inst.Len()); - re.inst.Push(i); - return i; -} - -type parser struct { - re *Regexp; - nlpar int; // number of unclosed lpars - pos int; - ch int; -} - -const endOfFile = -1 - -func (p *parser) c() int { - return p.ch; -} - -func (p *parser) nextc() int { - if p.pos >= len(p.re.expr) { - p.ch = endOfFile - } else { - c, w := utf8.DecodeRuneInString(p.re.expr[p.pos:len(p.re.expr)]); - 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 (p *parser) regexp() (start, end instr) - -var iNULL instr - -func special(c int) bool { - s := `\.+*?()|[]`; - for i := 0; i < len(s); i++ { - if c == int(s[i]) { - return true - } - } - return false -} - -func specialcclass(c int) bool { - s := `\-[]`; - for i := 0; i < len(s); i++ { - if c == int(s[i]) { - return true - } - } - return false -} - -func (p *parser) charClass() instr { - cc := newCharClass(); - p.re.add(cc); - if p.c() == '^' { - cc.negate = true; - p.nextc(); - } - left := -1; - for { - switch c := p.c(); c { - case ']', endOfFile: - if left >= 0 { - p.re.setError(ErrBadRange); - } - return cc; - case '-': // do this before backslash processing - p.re.setError(ErrBadRange); - case '\\': - c = p.nextc(); - switch { - case c == endOfFile: - p.re.setError(ErrExtraneousBackslash); - case c == 'n': - c = '\n'; - case specialcclass(c): - // c is as delivered - default: - p.re.setError(ErrBadBackslash); - } - fallthrough; - default: - p.nextc(); - switch { - case left < 0: // first of pair - if p.c() == '-' { // range - p.nextc(); - left = c; - } else { // single char - cc.addRange(c, c); - } - case left <= c: // second of pair - cc.addRange(left, c); - left = -1; - default: - p.re.setError(ErrBadRange); - } - } - } - return iNULL -} - -func (p *parser) term() (start, end instr) { - switch c := p.c(); c { - case '|', endOfFile: - return iNULL, iNULL; - case '*', '+': - p.re.setError(ErrBareClosure); - case ')': - if p.nlpar == 0 { - p.re.setError(ErrUnmatchedRpar); - } - return iNULL, iNULL; - case ']': - p.re.setError(ErrUnmatchedRbkt); - case '^': - p.nextc(); - start = p.re.add(new(_Bot)); - return start, start; - case '$': - p.nextc(); - start = p.re.add(new(_Eot)); - return start, start; - case '.': - p.nextc(); - start = p.re.add(new(_Any)); - return start, start; - case '[': - p.nextc(); - start = p.charClass(); - if p.c() != ']' { - p.re.setError(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.re.setError(ErrUnmatchedLpar); - } - p.nlpar--; - p.nextc(); - bra := new(_Bra); - p.re.add(bra); - ebra := new(_Ebra); - p.re.add(ebra); - bra.n = nbra; - ebra.n = nbra; - if start == iNULL { - if end == iNULL { - p.re.setError(ErrInternal) - } - start = ebra - } else { - end.setNext(ebra); - } - bra.setNext(start); - return bra, ebra; - case '\\': - c = p.nextc(); - switch { - case c == endOfFile: - p.re.setError(ErrExtraneousBackslash); - case c == 'n': - c = '\n'; - case special(c): - // c is as delivered - default: - p.re.setError(ErrBadBackslash); - } - fallthrough; - default: - p.nextc(); - start = newChar(c); - p.re.add(start); - return start, start - } - panic("unreachable"); -} - -func (p *parser) closure() (start, end instr) { - start, end = p.term(); - if start == iNULL { - return - } - switch p.c() { - case '*': - // (start,end)*: - alt := new(_Alt); - p.re.add(alt); - end.setNext(alt); // after end, do alt - alt.left = start; // alternate brach: return to start - start = alt; // alt becomes new (start, end) - end = alt; - case '+': - // (start,end)+: - alt := new(_Alt); - p.re.add(alt); - end.setNext(alt); // after end, do alt - alt.left = start; // alternate brach: return to start - end = alt; // start is unchanged; end is alt - case '?': - // (start,end)?: - alt := new(_Alt); - p.re.add(alt); - nop := new(_Nop); - p.re.add(nop); - alt.left = start; // alternate branch is start - alt.setNext(nop); // follow on to nop - end.setNext(nop); // after end, go to nop - start = alt; // start is now alt - end = nop; // end is nop pointed to by both branches - default: - return - } - switch p.nextc() { - case '*', '+', '?': - p.re.setError(ErrBadClosure); - } - return -} - -func (p *parser) concatenation() (start, end instr) { - start, end = iNULL, iNULL; - for { - nstart, nend := p.closure(); - switch { - case nstart == iNULL: // end of this concatenation - if start == iNULL { // this is the empty string - nop := p.re.add(new(_Nop)); - return nop, nop; - } - return; - case start == iNULL: // this is first element of concatenation - start, end = nstart, nend; - default: - end.setNext(nstart); - end = nend; - } - } - panic("unreachable"); -} - -func (p *parser) regexp() (start, end instr) { - start, end = p.concatenation(); - for { - switch p.c() { - default: - return; - case '|': - p.nextc(); - nstart, nend := p.concatenation(); - alt := new(_Alt); - p.re.add(alt); - alt.left = start; - alt.setNext(nstart); - nop := new(_Nop); - p.re.add(nop); - end.setNext(nop); - nend.setNext(nop); - start, end = alt, nop; - } - } - panic("unreachable"); -} - -func unNop(i instr) instr { - for i.kind() == _NOP { - i = i.next() - } - return i -} - -func (re *Regexp) eliminateNops() { - for i := 0; i < re.inst.Len(); i++ { - inst := re.inst.At(i).(instr); - if inst.kind() == _END { - continue - } - inst.setNext(unNop(inst.next())); - if inst.kind() == _ALT { - alt := inst.(*_Alt); - alt.left = unNop(alt.left); - } - } -} - -func (re *Regexp) dump() { - for i := 0; i < re.inst.Len(); i++ { - inst := re.inst.At(i).(instr); - print(inst.index(), ": "); - inst.print(); - if inst.kind() != _END { - print(" -> ", inst.next().index()) - } - print("\n"); - } -} - -func (re *Regexp) doParse() { - p := newParser(re); - start := new(_Start); - re.add(start); - s, e := p.regexp(); - start.setNext(s); - re.start = start; - e.setNext(re.add(new(_End))); - - if debug { - re.dump(); - println(); - } - - re.eliminateNops(); - - if debug { - re.dump(); - println(); - } -} - - -func compiler(str string, ch chan *Regexp) { - re := new(Regexp); - re.expr = str; - re.inst = vector.New(0); - re.ch = ch; - re.doParse(); - ch <- re; -} - -// 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) { - // Compile in a separate goroutine and wait for the result. - ch := make(chan *Regexp); - go compiler(str, ch); - re := <-ch; - return re, re.error -} - -type state struct { - inst instr; // next instruction to execute - match []int; // pairs of bracketing submatches. 0th is start,end -} - -// Append new state to to-do list. Leftmost-longest wins so avoid -// adding a state that's already active. -func addState(s []state, inst instr, match []int) []state { - index := inst.index(); - l := len(s); - pos := match[0]; - // TODO: Once the state is a vector and we can do insert, have inputs always - // go in order correctly and this "earlier" test is never necessary, - for i := 0; i < l; i++ { - if s[i].inst.index() == index && // same instruction - s[i].match[0] < pos { // earlier match already going; lefmost wins - return s - } - } - if l == cap(s) { - s1 := make([]state, 2*l)[0:l]; - for i := 0; i < l; i++ { - s1[i] = s[i]; - } - s = s1; - } - s = s[0:l+1]; - s[l].inst = inst; - s[l].match = match; - return s; -} - -func (re *Regexp) doExecute(str string, pos int) []int { - var s [2][]state; // TODO: use a vector when state values (not ptrs) can be vector elements - s[0] = make([]state, 10)[0:0]; - s[1] = make([]state, 10)[0:0]; - in, out := 0, 1; - var final state; - found := false; - for pos <= len(str) { - if !found { - // prime the pump if we haven't seen a match yet - match := make([]int, 2*(re.nbra+1)); - for i := 0; i < len(match); i++ { - match[i] = -1; // no match seen; catches cases like "a(b)?c" on "ac" - } - match[0] = pos; - s[out] = addState(s[out], re.start.next(), match); - } - in, out = out, in; // old out state is new in state - s[out] = s[out][0:0]; // clear out state - if len(s[in]) == 0 { - // machine has completed - break; - } - charwidth := 1; - c := endOfFile; - if pos < len(str) { - c, charwidth = utf8.DecodeRuneInString(str[pos:len(str)]); - } - for i := 0; i < len(s[in]); i++ { - st := s[in][i]; - switch s[in][i].inst.kind() { - case _BOT: - if pos == 0 { - s[in] = addState(s[in], st.inst.next(), st.match) - } - case _EOT: - if pos == len(str) { - s[in] = addState(s[in], st.inst.next(), st.match) - } - case _CHAR: - if c == st.inst.(*_Char).char { - s[out] = addState(s[out], st.inst.next(), st.match) - } - case _CHARCLASS: - if st.inst.(*_CharClass).matches(c) { - s[out] = addState(s[out], st.inst.next(), st.match) - } - case _ANY: - if c != endOfFile { - s[out] = addState(s[out], st.inst.next(), st.match) - } - case _BRA: - n := st.inst.(*_Bra).n; - st.match[2*n] = pos; - s[in] = addState(s[in], st.inst.next(), st.match); - case _EBRA: - n := st.inst.(*_Ebra).n; - st.match[2*n+1] = pos; - s[in] = addState(s[in], st.inst.next(), st.match); - case _ALT: - s[in] = addState(s[in], st.inst.(*_Alt).left, st.match); - // give other branch a copy of this match vector - s1 := make([]int, 2*(re.nbra+1)); - for i := 0; i < len(s1); i++ { - s1[i] = st.match[i] - } - s[in] = addState(s[in], st.inst.next(), s1); - case _END: - // choose leftmost longest - if !found || // first - st.match[0] < final.match[0] || // leftmost - (st.match[0] == final.match[0] && pos > final.match[1]) { // longest - final = st; - final.match[1] = pos; - } - found = true; - default: - st.inst.print(); - panic("unknown instruction in execute"); - } - } - pos += charwidth; - } - return final.match; -} - - -// Execute matches the Regexp against the string s. -// The return value is an array of integers, in pairs, identifying the positions of -// substrings matched by the expression. -// s[a[0]:a[1]] is the substring matched by the entire expression. -// s[a[2*i]:a[2*i+1]] for i > 0 is the substring matched by the ith parenthesized subexpression. -// A negative value means the subexpression did not match any element of the string. -// An empty array means "no match". -func (re *Regexp) Execute(s string) (a []int) { - return re.doExecute(s, 0) -} - - -// Match returns whether the Regexp matches the string s. -// The return value is a boolean: true for match, false for no match. -func (re *Regexp) Match(s string) bool { - return len(re.doExecute(s, 0)) > 0 -} - - -// MatchStrings matches the Regexp against the string s. -// The return value is an array of strings matched by the expression. -// a[0] is the substring matched by the entire expression. -// a[i] for i > 0 is the substring matched by the ith parenthesized subexpression. -// An empty array means ``no match''. -func (re *Regexp) MatchStrings(s string) (a []string) { - r := re.doExecute(s, 0); - if r == nil { - return nil - } - a = make([]string, len(r)/2); - for i := 0; i < len(r); i += 2 { - if r[i] != -1 { // -1 means no match for this subexpression - a[i/2] = s[r[i] : r[i+1]] - } - } - return -} - -// Match checks whether a textual regular expression -// matches a substring. More complicated queries need -// to use Compile and the full Regexp interface. -func Match(pattern string, s string) (matched bool, error os.Error) { - re, err := Compile(pattern); - if err != nil { - return false, err - } - return re.Match(s), nil -} diff --git a/src/lib/runtime/386/asm.s b/src/lib/runtime/386/asm.s deleted file mode 100644 index 5d3c4261a..000000000 --- a/src/lib/runtime/386/asm.s +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright 2009 The Go 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(SB),7,$0 - // copy arguments forward on an even stack - MOVL 0(SP), AX // argc - LEAL 4(SP), BX // argv - SUBL $128, SP // plenty of scratch - ANDL $~7, SP - MOVL AX, 120(SP) // save argc, argv away - MOVL BX, 124(SP) - -/* - // write "go386\n" - PUSHL $6 - PUSHL $hello(SB) - PUSHL $1 - CALL sys·write(SB) - POPL AX - POPL AX - POPL AX -*/ - - CALL ldt0setup(SB) - - // set up %fs to refer to that ldt entry - MOVL $(7*8+7), AX - MOVW AX, FS - - // store through it, to make sure it works - MOVL $0x123, 0(FS) - MOVL tls0(SB), AX - CMPL AX, $0x123 - JEQ ok - MOVL AX, 0 -ok: - - // set up m and g "registers" - // g is 0(FS), m is 4(FS) - LEAL g0(SB), CX - MOVL CX, 0(FS) - LEAL m0(SB), AX - MOVL AX, 4(FS) - - // save m->g0 = g0 - MOVL CX, 0(AX) - - // create istack out of the OS stack - LEAL (-8192+104)(SP), AX // TODO: 104? - MOVL AX, 0(CX) // 8(g) is stack limit (w 104b guard) - MOVL SP, 4(CX) // 12(g) is base - CALL emptyfunc(SB) // fault if stack check is wrong - - // convention is D is always cleared - CLD - - CALL check(SB) - - // saved argc, argv - MOVL 120(SP), AX - MOVL AX, 0(SP) - MOVL 124(SP), AX - MOVL AX, 4(SP) - CALL args(SB) - CALL osinit(SB) - CALL schedinit(SB) - - // create a new goroutine to start program - PUSHL $mainstart(SB) // entry - PUSHL $8 // arg size - CALL sys·newproc(SB) - POPL AX - POPL AX - - // start this M - CALL mstart(SB) - - INT $3 - RET - -TEXT mainstart(SB),7,$0 - CALL main·init(SB) - CALL initdone(SB) - CALL main·main(SB) - PUSHL $0 - CALL exit(SB) - POPL AX - INT $3 - RET - -TEXT breakpoint(SB),7,$0 - BYTE $0xcc - RET - -// go-routine -TEXT gogo(SB), 7, $0 - MOVL 4(SP), AX // gobuf - MOVL 0(AX), SP // restore SP - MOVL 4(AX), AX - MOVL AX, 0(SP) // put PC on the stack - MOVL $1, AX - RET - -TEXT gosave(SB), 7, $0 - MOVL 4(SP), AX // gobuf - MOVL SP, 0(AX) // save SP - MOVL 0(SP), BX - MOVL BX, 4(AX) // save PC - MOVL $0, AX // return 0 - RET - -// support for morestack - -// return point when leaving new stack. -// save AX, jmp to lesstack to switch back -TEXT retfromnewstack(SB),7,$0 - MOVL 4(FS), BX // m - MOVL AX, 12(BX) // save AX in m->cret - JMP lessstack(SB) - -// gogo, returning 2nd arg instead of 1 -TEXT gogoret(SB), 7, $0 - MOVL 8(SP), AX // return 2nd arg - MOVL 4(SP), BX // gobuf - MOVL 0(BX), SP // restore SP - MOVL 4(BX), BX - MOVL BX, 0(SP) // put PC on the stack - RET - -TEXT setspgoto(SB), 7, $0 - MOVL 4(SP), AX // SP - MOVL 8(SP), BX // fn to call - MOVL 12(SP), CX // fn to return - MOVL AX, SP - PUSHL CX - JMP BX - POPL AX // not reached - RET - -// bool cas(int32 *val, int32 old, int32 new) -// Atomically: -// if(*val == old){ -// *val = new; -// return 1; -// }else -// return 0; -TEXT 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 - -// 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 jmpdefer(SB), 7, $0 - MOVL 4(SP), AX // fn - MOVL 8(SP), BX // caller sp - LEAL -4(BX), SP // caller sp after CALL - SUBL $5, (SP) // return to CALL again - JMP AX // but first run the deferred function - -TEXT sys·memclr(SB),7,$0 - MOVL 4(SP), DI // arg 1 addr - MOVL 8(SP), CX // arg 2 count - ADDL $3, CX - SHRL $2, CX - MOVL $0, AX - CLD - REP - STOSL - RET - -TEXT sys·getcallerpc+0(SB),7,$0 - MOVL x+0(FP),AX // addr of first arg - MOVL -4(AX),AX // get calling pc - RET - -TEXT sys·setcallerpc+0(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 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. - MOVL $7, 0(SP) - LEAL tls0(SB), AX - MOVL AX, 4(SP) - MOVL $32, 8(SP) // sizeof(tls array) - CALL setldt(SB) - RET - -GLOBL m0+0(SB), $1024 -GLOBL g0+0(SB), $1024 - -GLOBL tls0+0(SB), $32 - -TEXT emptyfunc(SB),0,$0 - RET - -TEXT abort(SB),7,$0 - INT $0x3 - -DATA hello+0(SB)/8, $"go386\n\z\z" -GLOBL hello+0(SB), $8 - diff --git a/src/lib/runtime/386/closure.c b/src/lib/runtime/386/closure.c deleted file mode 100644 index 6ccbe3b8b..000000000 --- a/src/lib/runtime/386/closure.c +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "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 -sys·closure(int32 siz, byte *fn, byte *arg0) -{ - byte *p, *q, **ret; - int32 i, n; - int32 pcrel; - - if(siz < 0 || siz%4 != 0) - throw("bad closure size"); - - ret = (byte**)((byte*)&arg0 + siz); - - if(siz > 100) { - // TODO(rsc): implement stack growth preamble? - throw("closure too big"); - } - - // 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 = mal(n); - *ret = p; - q = p + n - siz; - mcpy(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 q) - throw("bad math in sys.closure"); -} - - diff --git a/src/lib/runtime/386/traceback.c b/src/lib/runtime/386/traceback.c deleted file mode 100644 index 05724d9ac..000000000 --- a/src/lib/runtime/386/traceback.c +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2009 The Go Authors. 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" - -// TODO(rsc): Move this into portable code, with calls to a -// machine-dependent isclosure() function. - -void -traceback(byte *pc0, byte *sp, G *g) -{ - Stktop *stk; - uintptr pc; - int32 i, n; - Func *f; - byte *p; - - pc = (uintptr)pc0; - - // 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); - } - - stk = (Stktop*)g->stackbase; - for(n=0; n<100; n++) { - while(pc == (uintptr)retfromnewstack) { - // pop to earlier stack block - sp = stk->oldsp; - stk = (Stktop*)stk->oldbase; - pc = *(uintptr*)(sp+sizeof(uintptr)); - sp += 2*sizeof(uintptr); // two irrelevant calls on stack: morestack plus its call - } - f = findfunc(pc); - if(f == nil) { - // dangerous, but poke around to see if it is a closure - p = (byte*)pc; - // ADDL $xxx, SP; RET - if(p[0] == 0x81 && p[1] == 0xc4 && p[6] == 0xc3) { - sp += *(uint32*)(p+2) + 8; - pc = *(uintptr*)(sp - 8); - if(pc <= 0x1000) - return; - continue; - } - printf("%p unknown pc\n", pc); - return; - } - if(f->frame < sizeof(uintptr)) // assembly funcs say 0 but lie - sp += sizeof(uintptr); - else - sp += f->frame; - - // print this frame - // main+0xf /home/rsc/go/src/runtime/x.go:23 - // main(0x1, 0x2, 0x3) - printf("%S", f->name); - if(pc > f->entry) - printf("+%p", (uintptr)(pc - f->entry)); - printf(" %S:%d\n", f->src, funcline(f, pc-1)); // -1 to get to CALL instr. - printf("\t%S(", f->name); - for(i = 0; i < f->args; i++) { - if(i != 0) - prints(", "); - sys·printhex(((uint32*)sp)[i]); - if(i >= 4) { - prints(", ..."); - break; - } - } - prints(")\n"); - - pc = *(uintptr*)(sp-sizeof(uintptr)); - if(pc <= 0x1000) - return; - } - prints("...\n"); -} - -// func caller(n int) (pc uintptr, file string, line int, ok bool) -void -runtime·Caller(int32 n, uintptr retpc, String retfile, int32 retline, bool retbool) -{ - uintptr pc; - byte *sp; - byte *p; - Stktop *stk; - Func *f; - - // our caller's pc, sp. - sp = (byte*)&n; - pc = *((uintptr*)sp - 1); - if((f = findfunc(pc)) == nil) { - error: - retpc = 0; - retline = 0; - retfile = emptystring; - retbool = false; - FLUSH(&retpc); - FLUSH(&retfile); - FLUSH(&retline); - FLUSH(&retbool); - return; - } - - // now unwind n levels - stk = (Stktop*)g->stackbase; - while(n-- > 0) { - while(pc == (uintptr)retfromnewstack) { - sp = stk->oldsp; - stk = (Stktop*)stk->oldbase; - pc = *((uintptr*)sp + 1); - sp += 2*sizeof(uintptr); - } - - if(f->frame < sizeof(uintptr)) // assembly functions lie - sp += sizeof(uintptr); - else - sp += f->frame; - - loop: - pc = *((uintptr*)sp - 1); - if(pc <= 0x1000 || (f = findfunc(pc)) == nil) { - // dangerous, but let's try this. - // see if it is a closure. - p = (byte*)pc; - // ADDL $xxx, SP; RET - if(p[0] == 0x81 && p[1] == 0xc4 && p[6] == 0xc3) { - sp += *(uint32*)(p+2) + sizeof(uintptr); - goto loop; - } - goto error; - } - } - - retpc = pc; - retfile = f->src; - retline = funcline(f, pc-1); - retbool = true; - FLUSH(&retpc); - FLUSH(&retfile); - FLUSH(&retline); - FLUSH(&retbool); -} - diff --git a/src/lib/runtime/386/vlop.s b/src/lib/runtime/386/vlop.s deleted file mode 100755 index 803276ce2..000000000 --- a/src/lib/runtime/386/vlop.s +++ /dev/null @@ -1,48 +0,0 @@ -// 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/lib/runtime/386/vlrt.c b/src/lib/runtime/386/vlrt.c deleted file mode 100755 index 093cca70d..000000000 --- a/src/lib/runtime/386/vlrt.c +++ /dev/null @@ -1,815 +0,0 @@ -// 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 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 -sys·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 -sys·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 -sys·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 -sys·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: - 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/lib/runtime/Makefile b/src/lib/runtime/Makefile deleted file mode 100644 index 5a5ace9c5..000000000 --- a/src/lib/runtime/Makefile +++ /dev/null @@ -1,125 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# Set SIZE to 32 or 64. -SIZE_386=32 -SIZE_amd64=64 -SIZE_arm=32 -SIZE=$(SIZE_$(GOARCH)) - -# Setup CFLAGS. Add -D_64BIT on 64-bit platforms (sorry). -CFLAGS_64=-D_64BIT -CFLAGS=-I$(GOOS) -I$(GOOS)/$(GOARCH) -wF $(CFLAGS_$(SIZE)) - -# Set O to right letter. -O_386=8 -O_amd64=6 -O_arm=5 -O=$(O_$(GOARCH)) - -# Tools -CC=$(O)c -GC=$(O)g -AS=$(O)a -AR=gopack - -LIB=runtime.a - -# 386-specific object files -OFILES_386=\ - vlop.$O\ - vlrt.$O\ - -OFILES=\ - array.$O\ - asm.$O\ - chan.$O\ - closure.$O\ - extern.$O\ - float.$O\ - float_go.$O\ - hashmap.$O\ - iface.$O\ - malloc.$O\ - malloc_go.$O\ - mcache.$O\ - mcentral.$O\ - mem.$O\ - mfixalloc.$O\ - mgc0.$O\ - mheap.$O\ - mheapmap$(SIZE).$O\ - msize.$O\ - print.$O\ - proc.$O\ - rune.$O\ - runtime.$O\ - rt0.$O\ - sema.$O\ - sema_go.$O\ - signal.$O\ - string.$O\ - symtab.$O\ - sys.$O\ - thread.$O\ - traceback.$O\ - $(OFILES_$(GOARCH))\ - -HFILES=\ - runtime.h\ - hashmap.h\ - malloc.h\ - $(GOOS)/os.h\ - $(GOOS)/$(GOARCH)/defs.h\ - -install: $(LIB) runtime.acid - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH) - cp $(LIB) $(GOROOT)/pkg/$(GOOS)_$(GOARCH)/$(LIB) - cp runtime.acid $(GOROOT)/acid/runtime.acid - -$(LIB): $(OFILES) - $(AR) grc $(LIB) $(OFILES) - -$(OFILES): $(HFILES) - -nuke: - rm -f *.[568] *.a $(GOROOT)/lib/$(LIB) - -clean: - rm -f *.[568] *.a runtime.acid cgo2c - -%.$O: %.go - $(GC) $< - -%.$O: %.c - $(CC) $(CFLAGS) $< - -%.$O: $(GOARCH)/%.c - $(CC) $(CFLAGS) $< - -%.$O: $(GOOS)/%.c - $(CC) $(CFLAGS) $< - -%.$O: $(GOOS)/$(GOARCH)/%.c - $(CC) $(CFLAGS) $< - -%.$O: $(GOARCH)/%.s - $(AS) $< - -%.$O: $(GOOS)/$(GOARCH)/%.s - $(AS) $< - -cgo2c: cgo2c.c - quietgcc -o $@ $< - -%.c: %.cgo cgo2c - ./cgo2c $< > $@.tmp - mv -f $@.tmp $@ - -runtime.acid: runtime.h proc.c - $(CC) -a proc.c >runtime.acid - -chan.acid: runtime.h chan.c - $(CC) -a chan.c >chan.acid - diff --git a/src/lib/runtime/amd64/asm.s b/src/lib/runtime/amd64/asm.s deleted file mode 100644 index 6fc01bbc9..000000000 --- a/src/lib/runtime/amd64/asm.s +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - - -TEXT _rt0_amd64(SB),7,$-8 - - // copy arguments forward on an even stack - - MOVQ 0(SP), AX // argc - LEAQ 8(SP), BX // argv - SUBQ $(4*8+7), SP // 2args 2auto - ANDQ $~7, SP - MOVQ AX, 16(SP) - MOVQ BX, 24(SP) - - // set the per-goroutine and per-mach registers - - LEAQ m0(SB), R14 // dedicated m. register - LEAQ g0(SB), R15 // dedicated g. register - MOVQ R15, 0(R14) // m has pointer to its g0 - - // create istack out of the given (operating system) stack - - LEAQ (-8192+104)(SP), AX - MOVQ AX, 0(R15) // 0(R15) is stack limit (w 104b guard) - MOVQ SP, 8(R15) // 8(R15) is base - - CLD // convention is D is always left cleared - CALL check(SB) - - MOVL 16(SP), AX // copy argc - MOVL AX, 0(SP) - MOVQ 24(SP), AX // copy argv - MOVQ AX, 8(SP) - CALL args(SB) - CALL osinit(SB) - CALL schedinit(SB) - - // create a new goroutine to start program - PUSHQ $mainstart(SB) // entry - PUSHQ $16 // arg size - CALL sys·newproc(SB) - POPQ AX - POPQ AX - - // start this M - CALL mstart(SB) - - CALL notok(SB) // never returns - RET - -TEXT mainstart(SB),7,$0 - CALL main·init(SB) - CALL initdone(SB) - CALL main·main(SB) - PUSHQ $0 - CALL exit(SB) - POPQ AX - CALL notok(SB) - RET - -TEXT breakpoint(SB),7,$0 - BYTE $0xcc - RET - -/* - * go-routine - */ -TEXT gogo(SB), 7, $0 - MOVQ 8(SP), AX // gobuf - MOVQ 0(AX), SP // restore SP - MOVQ 8(AX), AX - MOVQ AX, 0(SP) // put PC on the stack - MOVL $1, AX // return 1 - RET - -TEXT gosave(SB), 7, $0 - MOVQ 8(SP), AX // gobuf - MOVQ SP, 0(AX) // save SP - MOVQ 0(SP), BX - MOVQ BX, 8(AX) // save PC - MOVL $0, AX // return 0 - RET - -/* - * support for morestack - */ - -// morestack trampolines -TEXT sys·morestack00+0(SB),7,$0 - MOVQ $0, AX - MOVQ AX, 8(R14) - MOVQ $sys·morestack+0(SB), AX - JMP AX - -TEXT sys·morestack01+0(SB),7,$0 - SHLQ $32, AX - MOVQ AX, 8(R14) - MOVQ $sys·morestack+0(SB), AX - JMP AX - -TEXT sys·morestack10+0(SB),7,$0 - MOVLQZX AX, AX - MOVQ AX, 8(R14) - MOVQ $sys·morestack+0(SB), AX - JMP AX - -TEXT sys·morestack11+0(SB),7,$0 - MOVQ AX, 8(R14) - MOVQ $sys·morestack+0(SB), AX - JMP AX - -TEXT sys·morestackx(SB),7,$0 - POPQ AX - SHLQ $35, AX - MOVQ AX, 8(R14) - MOVQ $sys·morestack(SB), AX - JMP AX - -// subcases of morestack01 -// with const of 8,16,...48 -TEXT sys·morestack8(SB),7,$0 - PUSHQ $1 - MOVQ $sys·morestackx(SB), AX - JMP AX - -TEXT sys·morestack16(SB),7,$0 - PUSHQ $2 - MOVQ $sys·morestackx(SB), AX - JMP AX - -TEXT sys·morestack24(SB),7,$0 - PUSHQ $3 - MOVQ $sys·morestackx(SB), AX - JMP AX - -TEXT sys·morestack32(SB),7,$0 - PUSHQ $4 - MOVQ $sys·morestackx(SB), AX - JMP AX - -TEXT sys·morestack40(SB),7,$0 - PUSHQ $5 - MOVQ $sys·morestackx(SB), AX - JMP AX - -TEXT sys·morestack48(SB),7,$0 - PUSHQ $6 - MOVQ $sys·morestackx(SB), AX - JMP AX - -// return point when leaving new stack. save AX, jmp to lessstack to switch back -TEXT retfromnewstack(SB), 7, $0 - MOVQ AX, 16(R14) // save AX in m->cret - MOVQ $lessstack(SB), AX - JMP AX - -// gogo, returning 2nd arg instead of 1 -TEXT gogoret(SB), 7, $0 - MOVQ 16(SP), AX // return 2nd arg - MOVQ 8(SP), BX // gobuf - MOVQ 0(BX), SP // restore SP - MOVQ 8(BX), BX - MOVQ BX, 0(SP) // put PC on the stack - RET - -TEXT setspgoto(SB), 7, $0 - MOVQ 8(SP), AX // SP - MOVQ 16(SP), BX // fn to call - MOVQ 24(SP), CX // fn to return - MOVQ AX, SP - PUSHQ CX - JMP BX - POPQ AX // not reached - RET - -// bool cas(int32 *val, int32 old, int32 new) -// Atomically: -// if(*val == old){ -// *val = new; -// return 1; -// } else -// return 0; -TEXT 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 - -// 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 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 diff --git a/src/lib/runtime/amd64/closure.c b/src/lib/runtime/amd64/closure.c deleted file mode 100644 index 5717d3c5e..000000000 --- a/src/lib/runtime/amd64/closure.c +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#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 -sys·closure(int32 siz, byte *fn, byte *arg0) -{ - byte *p, *q, **ret; - int32 i, n; - int64 pcrel; - - if(siz < 0 || siz%8 != 0) - throw("bad closure size"); - - ret = (byte**)((byte*)&arg0 + siz); - - if(siz > 100) { - // TODO(rsc): implement stack growth preamble? - 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 = mal(n); - *ret = p; - q = p + n - siz; - mcpy(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 q) - throw("bad math in sys.closure"); -} - - diff --git a/src/lib/runtime/amd64/traceback.c b/src/lib/runtime/amd64/traceback.c deleted file mode 100644 index 16d7bed72..000000000 --- a/src/lib/runtime/amd64/traceback.c +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright 2009 The Go Authors. 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 -traceback(byte *pc0, byte *sp, G *g) -{ - Stktop *stk; - uint64 pc; - int32 i, n; - Func *f; - byte *p; - - pc = (uint64)pc0; - - // If the PC is zero, it's likely a nil function call. - // Start in the caller's frame. - if(pc == 0) { - pc = *(uint64*)sp; - sp += 8; - } - - stk = (Stktop*)g->stackbase; - for(n=0; n<100; n++) { - while(pc == (uint64)retfromnewstack) { - // pop to earlier stack block - sp = stk->oldsp; - stk = (Stktop*)stk->oldbase; - pc = *(uint64*)(sp+8); - sp += 16; // two irrelevant calls on stack: morestack plus its call - } - f = findfunc(pc); - if(f == nil) { - // dangerous, but poke around to see if it is a closure - p = (byte*)pc; - // ADDQ $xxx, SP; RET - if(p[0] == 0x48 && p[1] == 0x81 && p[2] == 0xc4 && p[7] == 0xc3) { - sp += *(uint32*)(p+3) + 8; - pc = *(uint64*)(sp - 8); - if(pc <= 0x1000) - return; - continue; - } - printf("%p unknown pc\n", pc); - return; - } - if(f->frame < 8) // assembly funcs say 0 but lie - sp += 8; - else - sp += f->frame; - - // print this frame - // main+0xf /home/rsc/go/src/runtime/x.go:23 - // main(0x1, 0x2, 0x3) - printf("%S", f->name); - if(pc > f->entry) - printf("+%X", pc - f->entry); - printf(" %S:%d\n", f->src, funcline(f, pc-1)); // -1 to get to CALL instr. - printf("\t%S(", f->name); - for(i = 0; i < f->args; i++) { - if(i != 0) - prints(", "); - sys·printhex(((uint32*)sp)[i]); - if(i >= 4) { - prints(", ..."); - break; - } - } - prints(")\n"); - - pc = *(uint64*)(sp-8); - if(pc <= 0x1000) - return; - } - prints("...\n"); -} - -// func caller(n int) (pc uint64, file string, line int, ok bool) -void -runtime·Caller(int32 n, uint64 retpc, String retfile, int32 retline, bool retbool) -{ - uint64 pc; - byte *sp; - byte *p; - Stktop *stk; - Func *f; - - // our caller's pc, sp. - sp = (byte*)&n; - pc = *(uint64*)(sp-8); - if((f = findfunc(pc)) == nil) { - error: - retpc = 0; - retline = 0; - retfile = emptystring; - retbool = false; - FLUSH(&retpc); - FLUSH(&retfile); - FLUSH(&retline); - FLUSH(&retbool); - return; - } - - // now unwind n levels - stk = (Stktop*)g->stackbase; - while(n-- > 0) { - while(pc == (uint64)retfromnewstack) { - sp = stk->oldsp; - stk = (Stktop*)stk->oldbase; - pc = *(uint64*)(sp+8); - sp += 16; - } - - if(f->frame < 8) // assembly functions lie - sp += 8; - else - sp += f->frame; - - loop: - pc = *(uint64*)(sp-8); - if(pc <= 0x1000 || (f = findfunc(pc)) == nil) { - // dangerous, but let's try this. - // see if it is a closure. - p = (byte*)pc; - // ADDQ $xxx, SP; RET - if(p[0] == 0x48 && p[1] == 0x81 && p[2] == 0xc4 && p[7] == 0xc3) { - sp += *(uint32*)(p+3) + 8; - goto loop; - } - goto error; - } - } - - retpc = pc; - retfile = f->src; - retline = funcline(f, pc-1); - retbool = true; - FLUSH(&retpc); - FLUSH(&retfile); - FLUSH(&retline); - FLUSH(&retbool); -} - - diff --git a/src/lib/runtime/arm/asm.s b/src/lib/runtime/arm/asm.s deleted file mode 100644 index 232ab4ddf..000000000 --- a/src/lib/runtime/arm/asm.s +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2009 The Go 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(SB),7,$0 - // copy arguments forward on an even stack - // MOVW $0(SP), R0 - // MOVL 0(SP), R1 // argc -// LEAL 4(SP), R1 // argv -// SUBL $128, SP // plenty of scratch -// ANDL $~7, SP -// MOVL AX, 120(SP) // save argc, argv away -// MOVL BX, 124(SP) - - -// // write "go386\n" -// PUSHL $6 -// PUSHL $hello(SB) -// PUSHL $1 -// CALL sys·write(SB) -// POPL AX -// POPL AX -// POPL AX - - -// CALL ldt0setup(SB) - - // set up %fs to refer to that ldt entry -// MOVL $(7*8+7), AX -// MOVW AX, FS - -// // store through it, to make sure it works -// MOVL $0x123, 0(FS) -// MOVL tls0(SB), AX -// CMPL AX, $0x123 -// JEQ ok -// MOVL AX, 0 -// ok: - -// // set up m and g "registers" -// // g is 0(FS), m is 4(FS) -// LEAL g0(SB), CX -// MOVL CX, 0(FS) -// LEAL m0(SB), AX -// MOVL AX, 4(FS) - -// // save m->g0 = g0 -// MOVL CX, 0(AX) - -// // create istack out of the OS stack -// LEAL (-8192+104)(SP), AX // TODO: 104? -// MOVL AX, 0(CX) // 8(g) is stack limit (w 104b guard) -// MOVL SP, 4(CX) // 12(g) is base -// CALL emptyfunc(SB) // fault if stack check is wrong - -// // convention is D is always cleared -// CLD - -// CALL check(SB) - -// // saved argc, argv -// MOVL 120(SP), AX -// MOVL AX, 0(SP) -// MOVL 124(SP), AX -// MOVL AX, 4(SP) -// CALL args(SB) -// CALL osinit(SB) -// CALL schedinit(SB) - -// // create a new goroutine to start program -// PUSHL $mainstart(SB) // entry -// PUSHL $8 // arg size -// CALL sys·newproc(SB) -// POPL AX -// POPL AX - -// // start this M -// CALL mstart(SB) - - BL main�main(SB) - MOVW $99, R0 - SWI $0x00900001 - diff --git a/src/lib/runtime/arm/closure.c b/src/lib/runtime/arm/closure.c deleted file mode 100644 index 024018d5a..000000000 --- a/src/lib/runtime/arm/closure.c +++ /dev/null @@ -1,4 +0,0 @@ -// Copyright 2009 The Go 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/lib/runtime/arm/traceback.s b/src/lib/runtime/arm/traceback.s deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/lib/runtime/array.c b/src/lib/runtime/array.c deleted file mode 100644 index bbd57b03e..000000000 --- a/src/lib/runtime/array.c +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright 2009 The Go Authors. 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 int32 debug = 0; - -// newarray(nel int, cap int, width int) (ary []any); -void -sys·newarray(uint32 nel, uint32 cap, uint32 width, Array ret) -{ - uint64 size; - - if(cap < nel) - cap = nel; - size = cap*width; - - ret.nel = nel; - ret.cap = cap; - ret.array = mal(size); - - FLUSH(&ret); - - if(debug) { - prints("newarray: nel="); - sys·printint(nel); - prints("; cap="); - sys·printint(cap); - prints("; width="); - sys·printint(width); - prints("; ret="); - sys·printarray(ret); - prints("\n"); - } -} - -static void -throwslice(uint32 lb, uint32 hb, uint32 n) -{ - prints("slice["); - sys·printint(lb); - prints(":"); - sys·printint(hb); - prints("] of ["); - sys·printint(n); - prints("] array\n"); - throw("array slice"); -} - -// arraysliced(old []any, lb int, hb int, width int) (ary []any); -void -sys·arraysliced(Array old, uint32 lb, uint32 hb, uint32 width, Array ret) -{ - - if(hb > old.cap || lb > hb) { - if(debug) { - prints("sys·arraysliced: old="); - sys·printarray(old); - prints("; lb="); - sys·printint(lb); - prints("; hb="); - sys·printint(hb); - prints("; width="); - sys·printint(width); - prints("\n"); - - prints("oldarray: nel="); - sys·printint(old.nel); - prints("; cap="); - sys·printint(old.cap); - prints("\n"); - } - throwslice(lb, hb, old.cap); - } - - // new array is inside old array - ret.nel = hb-lb; - ret.cap = old.cap - lb; - ret.array = old.array + lb*width; - - FLUSH(&ret); - - if(debug) { - prints("sys·arraysliced: old="); - sys·printarray(old); - prints("; lb="); - sys·printint(lb); - prints("; hb="); - sys·printint(hb); - prints("; width="); - sys·printint(width); - prints("; ret="); - sys·printarray(ret); - prints("\n"); - } -} - -// arrayslices(old *any, nel int, lb int, hb int, width int) (ary []any); -void -sys·arrayslices(byte* old, uint32 nel, uint32 lb, uint32 hb, uint32 width, Array ret) -{ - - if(hb > nel || lb > hb) { - if(debug) { - prints("sys·arrayslices: old="); - sys·printpointer(old); - prints("; nel="); - sys·printint(nel); - prints("; lb="); - sys·printint(lb); - prints("; hb="); - sys·printint(hb); - prints("; width="); - sys·printint(width); - prints("\n"); - } - throwslice(lb, hb, nel); - } - - // new array is inside old array - ret.nel = hb-lb; - ret.cap = nel-lb; - ret.array = old + lb*width; - - FLUSH(&ret); - - if(debug) { - prints("sys·arrayslices: old="); - sys·printpointer(old); - prints("; nel="); - sys·printint(nel); - prints("; lb="); - sys·printint(lb); - prints("; hb="); - sys·printint(hb); - prints("; width="); - sys·printint(width); - prints("; ret="); - sys·printarray(ret); - prints("\n"); - } -} - -// arrays2d(old *any, nel int) (ary []any) -void -sys·arrays2d(byte* old, uint32 nel, Array ret) -{ - - // new dope to old array - ret.nel = nel; - ret.cap = nel; - ret.array = old; - - FLUSH(&ret); - - if(debug) { - prints("sys·arrays2d: old="); - sys·printpointer(old); - prints("; ret="); - sys·printarray(ret); - prints("\n"); - } -} - -void -sys·printarray(Array a) -{ - prints("["); - sys·printint(a.nel); - prints("/"); - sys·printint(a.cap); - prints("]"); - sys·printpointer(a.array); -} diff --git a/src/lib/runtime/cgo2c.c b/src/lib/runtime/cgo2c.c deleted file mode 100644 index 3905f7e6d..000000000 --- a/src/lib/runtime/cgo2c.c +++ /dev/null @@ -1,602 +0,0 @@ -// Copyright 2009 The Go 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 .cgo file into a .c file. A .cgo 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 -#include -#include -#include -#include -#include - -/* Whether we're emitting for gcc */ -static int gcc; - -/* File and line number */ -static const char *file; -static unsigned int lineno; - -/* List of names and types. */ -struct params { - struct params *next; - char *name; - char *type; -}; - -/* Unexpected EOF. */ -static void -bad_eof(void) -{ - fprintf(stderr, "%s:%u: unexpected EOF\n", file, lineno); - exit(1); -} - -/* Out of memory. */ -static void -bad_mem(void) -{ - fprintf(stderr, "%s:%u: out of memory\n", file, lineno); - exit(1); -} - -/* Allocate memory without fail. */ -static void * -xmalloc(unsigned int size) -{ - void *ret = malloc(size); - if (ret == NULL) - bad_mem(); - return ret; -} - -/* Reallocate memory without fail. */ -static void* -xrealloc(void *buf, unsigned int size) -{ - void *ret = realloc(buf, size); - if (ret == NULL) - bad_mem(); - return ret; -} - -/* Free a list of parameters. */ -static void -free_params(struct params *p) -{ - while (p != NULL) { - struct params *next; - - next = p->next; - free(p->name); - free(p->type); - free(p); - p = next; - } -} - -/* Read a character, tracking lineno. */ -static int -getchar_update_lineno(void) -{ - int c; - - c = getchar(); - if (c == '\n') - ++lineno; - return c; -} - -/* Read a character, giving an error on EOF, tracking lineno. */ -static int -getchar_no_eof(void) -{ - int c; - - c = getchar_update_lineno(); - if (c == EOF) - bad_eof(); - return c; -} - -/* Read a character, skipping comments. */ -static int -getchar_skipping_comments(void) -{ - int c; - - while (1) { - c = getchar_update_lineno(); - if (c != '/') - return c; - - c = getchar(); - if (c == '/') { - do { - c = getchar_update_lineno(); - } while (c != EOF && c != '\n'); - return c; - } else if (c == '*') { - while (1) { - c = getchar_update_lineno(); - if (c == EOF) - return EOF; - if (c == '*') { - do { - c = getchar_update_lineno(); - } while (c == '*'); - if (c == '/') - break; - } - } - } else { - ungetc(c, stdin); - return '/'; - } - } -} - -/* Read and return a token. Tokens are delimited by whitespace or by - [(),{}]. The latter are all returned as single characters. */ -static char * -read_token(void) -{ - int c; - char *buf; - unsigned int alc, off; - const char* delims = "(),{}"; - - while (1) { - c = getchar_skipping_comments(); - if (c == EOF) - return NULL; - if (!isspace(c)) - break; - } - alc = 16; - buf = xmalloc(alc + 1); - off = 0; - if (strchr(delims, c) != NULL) { - buf[off] = c; - ++off; - } else { - while (1) { - if (off >= alc) { - alc *= 2; - buf = xrealloc(buf, alc + 1); - } - buf[off] = c; - ++off; - c = getchar_skipping_comments(); - if (c == EOF) - break; - if (isspace(c) || strchr(delims, c) != NULL) { - ungetc(c, stdin); - break; - } - } - } - buf[off] = '\0'; - return buf; -} - -/* Read a token, giving an error on EOF. */ -static char * -read_token_no_eof(void) -{ - char *token = read_token(); - if (token == NULL) - bad_eof(); - return token; -} - -/* Read the package clause, and return the package name. */ -static char * -read_package(void) -{ - char *token; - - token = read_token_no_eof(); - if (strcmp(token, "package") != 0) { - fprintf(stderr, - "%s:%u: expected \"package\", got \"%s\"\n", - file, lineno, token); - exit(1); - } - return read_token_no_eof(); -} - -/* Read and copy preprocessor lines. */ -static void -read_preprocessor_lines(void) -{ - while (1) { - int c; - - do { - c = getchar_skipping_comments(); - } while (isspace(c)); - if (c != '#') { - ungetc(c, stdin); - return; - } - 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; -} - -/* 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(void) -{ - char *token; - struct params *ret, **pp; - - ret = NULL; - pp = &ret; - token = read_token_no_eof(); - if (strcmp(token, ")") != 0) { - while (1) { - *pp = xmalloc(sizeof(struct params)); - (*pp)->name = token; - (*pp)->type = read_type(); - pp = &(*pp)->next; - *pp = NULL; - - token = read_token_no_eof(); - if (strcmp(token, ",") != 0) - break; - token = read_token_no_eof(); - } - } - if (strcmp(token, ")") != 0) { - fprintf(stderr, "%s:%u: expected '('\n", - file, lineno); - exit(1); - } - 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, struct params **rets) -{ - char *token; - - token = read_token(); - if (token == NULL) - return 0; - if (strcmp(token, "func") != 0) { - fprintf(stderr, "%s:%u: expected \"func\"\n", - file, lineno); - exit(1); - } - *name = read_token_no_eof(); - - token = read_token(); - if (token == NULL || strcmp(token, "(") != 0) { - fprintf(stderr, "%s:%u: expected \"(\"\n", - file, lineno); - exit(1); - } - *params = read_params(); - - token = read_token(); - if (token == NULL || strcmp(token, "(") != 0) - *rets = NULL; - else { - *rets = read_params(); - token = read_token(); - } - if (token == NULL || strcmp(token, "{") != 0) { - fprintf(stderr, "%s:%u: expected \"{\"\n", - file, lineno); - exit(1); - } - return 1; -} - -/* Write out parameters. */ -static void -write_params(struct params *params, int *first) -{ - struct params *p; - - for (p = params; p != NULL; p = p->next) { - if (*first) - *first = 0; - else - printf(", "); - printf("%s %s", p->type, p->name); - } -} - -/* Write a 6g function header. */ -static void -write_6g_func_header(char *package, char *name, struct params *params, - struct params *rets) -{ - int first; - - printf("void\n%s·%s(", package, name); - first = 1; - write_params(params, &first); - 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, struct params *rets) -{ - if (gcc) - write_gcc_func_header(package, name, params, rets); - else - write_6g_func_header(package, name, params, 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; - - package = read_package(); - read_preprocessor_lines(); - while (read_func_header(&name, ¶ms, &rets)) { - write_func_header(package, name, params, rets); - copy_body(); - write_func_trailer(package, name, rets); - free(name); - free_params(params); - free_params(rets); - } - free(package); -} - -static void -usage(void) -{ - fprintf(stderr, "Usage: cgo2c [--6g | --gc] [file]\n"); - exit(1); -} - -int -main(int argc, char **argv) -{ - 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 = ""; - process_file(); - return 0; - } - - if(argc > 2) - usage(); - - file = argv[1]; - if(freopen(file, "r", stdin) == 0) { - fprintf(stderr, "open %s: %s\n", file, strerror(errno)); - exit(1); - } - process_file(); - return 0; -} diff --git a/src/lib/runtime/chan.c b/src/lib/runtime/chan.c deleted file mode 100644 index be65bcbc1..000000000 --- a/src/lib/runtime/chan.c +++ /dev/null @@ -1,1024 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "runtime.h" - -static int32 debug = 0; -static Lock chanlock; - -enum -{ - Wclosed = 0x0001, // writer has closed - Rclosed = 0x0002, // reader has seen close - Eincr = 0x0004, // increment errors - Emax = 0x0800, // error limit before throw -}; - -typedef struct Hchan Hchan; -typedef struct Link Link; -typedef struct WaitQ WaitQ; -typedef struct SudoG SudoG; -typedef struct Select Select; -typedef struct Scase Scase; - -struct SudoG -{ - G* g; // g and selgen constitute - int32 selgen; // a weak pointer to g - int16 offset; // offset of case number - int8 isfree; // offset of case number - SudoG* link; - byte elem[8]; // synch data element (+ more) -}; - -struct WaitQ -{ - SudoG* first; - SudoG* last; -}; - -struct Hchan -{ - uint16 elemsize; - uint16 closed; // Wclosed Rclosed errorcount - uint32 dataqsiz; // size of the circular q - uint32 qcount; // total data in the q - Alg* elemalg; // interface for element type - Link* senddataq; // pointer for sender - Link* recvdataq; // pointer for receiver - WaitQ recvq; // list of recv waiters - WaitQ sendq; // list of send waiters - SudoG* free; // freelist -}; - -struct Link -{ - Link* link; // asynch queue circular linked list - byte elem[8]; // asynch queue data element (+ more) -}; - -struct Scase -{ - Hchan* chan; // chan - byte* pc; // return pc - uint16 send; // 0-recv 1-send 2-default - uint16 so; // vararg of selected bool - union { - byte elem[8]; // element (send) - byte* elemp; // pointer to element (recv) - } u; -}; - -struct Select -{ - uint16 tcase; // total count of scase[] - uint16 ncase; // currently filled scase[] - Select* link; // for freelist - Scase* scase[1]; // one per case -}; - -static Select* selfree[20]; - -static SudoG* dequeue(WaitQ*, Hchan*); -static void enqueue(WaitQ*, SudoG*); -static SudoG* allocsg(Hchan*); -static void freesg(Hchan*, SudoG*); -static uint32 gcd(uint32, uint32); -static uint32 fastrand1(void); -static uint32 fastrand2(void); - -// newchan(elemsize uint32, elemalg uint32, hint uint32) (hchan *chan any); -void -sys·newchan(uint32 elemsize, uint32 elemalg, uint32 hint, - Hchan* ret) -{ - Hchan *c; - int32 i; - - if(elemalg >= nelem(algarray)) { - printf("chan(alg=%d)\n", elemalg); - throw("sys·newchan: unsupported elem type"); - } - - c = mal(sizeof(*c)); - - c->elemsize = elemsize; - c->elemalg = &algarray[elemalg]; - - if(hint > 0) { - Link *d, *b, *e; - - // make a circular q - b = nil; - e = nil; - for(i=0; ielemsize - sizeof(d->elem)); - if(e == nil) - e = d; - d->link = b; - b = d; - } - e->link = b; - c->recvdataq = b; - c->senddataq = b; - c->qcount = 0; - c->dataqsiz = hint; - } - - ret = c; - FLUSH(&ret); - - if(debug) { - prints("newchan: chan="); - sys·printpointer(c); - prints("; elemsize="); - sys·printint(elemsize); - prints("; elemalg="); - sys·printint(elemalg); - prints("; dataqsiz="); - sys·printint(c->dataqsiz); - prints("\n"); - } -} - -static void -incerr(Hchan* c) -{ - c->closed += Eincr; - if(c->closed & Emax) { - unlock(&chanlock); - throw("too many operations on a closed channel"); - } -} - -/* - * 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 - */ -void -sendchan(Hchan *c, byte *ep, bool *pres) -{ - SudoG *sg; - G* gp; - - if(debug) { - prints("chansend: chan="); - sys·printpointer(c); - prints("; elem="); - c->elemalg->print(c->elemsize, ep); - prints("\n"); - } - - lock(&chanlock); -loop: - if(c->closed & Wclosed) - goto closed; - - if(c->dataqsiz > 0) - goto asynch; - - sg = dequeue(&c->recvq, c); - if(sg != nil) { - if(ep != nil) - c->elemalg->copy(c->elemsize, sg->elem, ep); - - gp = sg->g; - gp->param = sg; - unlock(&chanlock); - ready(gp); - - if(pres != nil) - *pres = true; - return; - } - - if(pres != nil) { - unlock(&chanlock); - *pres = false; - return; - } - - sg = allocsg(c); - if(ep != nil) - c->elemalg->copy(c->elemsize, sg->elem, ep); - g->param = nil; - g->status = Gwaiting; - enqueue(&c->sendq, sg); - unlock(&chanlock); - gosched(); - - lock(&chanlock); - sg = g->param; - if(sg == nil) - goto loop; - freesg(c, sg); - unlock(&chanlock); - if(pres != nil) - *pres = true; - return; - -asynch: - if(c->closed & Wclosed) - goto closed; - - if(c->qcount >= c->dataqsiz) { - if(pres != nil) { - unlock(&chanlock); - *pres = false; - return; - } - sg = allocsg(c); - g->status = Gwaiting; - enqueue(&c->sendq, sg); - unlock(&chanlock); - gosched(); - - lock(&chanlock); - goto asynch; - } - if(ep != nil) - c->elemalg->copy(c->elemsize, c->senddataq->elem, ep); - c->senddataq = c->senddataq->link; - c->qcount++; - - sg = dequeue(&c->recvq, c); - if(sg != nil) { - gp = sg->g; - freesg(c, sg); - unlock(&chanlock); - ready(gp); - } else - unlock(&chanlock); - if(pres != nil) - *pres = true; - return; - -closed: - incerr(c); - if(pres != nil) - *pres = true; - unlock(&chanlock); -} - -static void -chanrecv(Hchan* c, byte *ep, bool* pres) -{ - SudoG *sg; - G *gp; - - if(debug) { - prints("chanrecv: chan="); - sys·printpointer(c); - prints("\n"); - } - - lock(&chanlock); -loop: - if(c->dataqsiz > 0) - goto asynch; - - if(c->closed & Wclosed) - goto closed; - - sg = dequeue(&c->sendq, c); - if(sg != nil) { - c->elemalg->copy(c->elemsize, ep, sg->elem); - - gp = sg->g; - gp->param = sg; - unlock(&chanlock); - ready(gp); - - if(pres != nil) - *pres = true; - return; - } - - if(pres != nil) { - unlock(&chanlock); - *pres = false; - return; - } - - sg = allocsg(c); - g->param = nil; - g->status = Gwaiting; - enqueue(&c->recvq, sg); - unlock(&chanlock); - gosched(); - - lock(&chanlock); - sg = g->param; - if(sg == nil) - goto loop; - - c->elemalg->copy(c->elemsize, ep, sg->elem); - freesg(c, sg); - unlock(&chanlock); - if(pres != nil) - *pres = true; - return; - -asynch: - if(c->qcount <= 0) { - if(c->closed & Wclosed) - goto closed; - - if(pres != nil) { - unlock(&chanlock); - *pres = false; - return; - } - sg = allocsg(c); - g->status = Gwaiting; - enqueue(&c->recvq, sg); - unlock(&chanlock); - gosched(); - - lock(&chanlock); - goto asynch; - } - c->elemalg->copy(c->elemsize, ep, c->recvdataq->elem); - c->recvdataq = c->recvdataq->link; - c->qcount--; - sg = dequeue(&c->sendq, c); - if(sg != nil) { - gp = sg->g; - freesg(c, sg); - unlock(&chanlock); - ready(gp); - if(pres != nil) - *pres = true; - return; - } - - unlock(&chanlock); - if(pres != nil) - *pres = true; - return; - -closed: - c->elemalg->copy(c->elemsize, ep, nil); - c->closed |= Rclosed; - incerr(c); - if(pres != nil) - *pres = true; - unlock(&chanlock); -} - -// chansend1(hchan *chan any, elem any); -void -sys·chansend1(Hchan* c, ...) -{ - int32 o; - byte *ae; - - o = rnd(sizeof(c), c->elemsize); - ae = (byte*)&c + o; - sendchan(c, ae, nil); -} - -// chansend2(hchan *chan any, elem any) (pres bool); -void -sys·chansend2(Hchan* c, ...) -{ - int32 o; - byte *ae, *ap; - - o = rnd(sizeof(c), c->elemsize); - ae = (byte*)&c + o; - o = rnd(o+c->elemsize, 1); - ap = (byte*)&c + o; - - sendchan(c, ae, ap); -} - -// chanrecv1(hchan *chan any) (elem any); -void -sys·chanrecv1(Hchan* c, ...) -{ - int32 o; - byte *ae; - - o = rnd(sizeof(c), c->elemsize); - ae = (byte*)&c + o; - - chanrecv(c, ae, nil); -} - -// chanrecv2(hchan *chan any) (elem any, pres bool); -void -sys·chanrecv2(Hchan* c, ...) -{ - int32 o; - byte *ae, *ap; - - o = rnd(sizeof(c), c->elemsize); - ae = (byte*)&c + o; - o = rnd(o+c->elemsize, 1); - ap = (byte*)&c + o; - - chanrecv(c, ae, ap); -} - -// chanrecv3(hchan *chan any, elem *any) (pres bool); -void -sys·chanrecv3(Hchan* c, byte* ep, byte pres) -{ - chanrecv(c, ep, &pres); -} - -// newselect(size uint32) (sel *byte); -void -sys·newselect(int32 size, Select *sel) -{ - int32 n; - - n = 0; - if(size > 1) - n = size-1; - - lock(&chanlock); - sel = nil; - if(size >= 1 && size < nelem(selfree)) { - sel = selfree[size]; - if(sel != nil) - selfree[size] = sel->link; - } - unlock(&chanlock); - if(sel == nil) - sel = mal(sizeof(*sel) + n*sizeof(sel->scase[0])); - - sel->tcase = size; - sel->ncase = 0; - FLUSH(&sel); - if(debug) { - prints("newselect s="); - sys·printpointer(sel); - prints(" size="); - sys·printint(size); - prints("\n"); - } -} - -// selectsend(sel *byte, hchan *chan any, elem any) (selected bool); -void -sys·selectsend(Select *sel, Hchan *c, ...) -{ - int32 i, eo; - Scase *cas; - byte *ae; - - // nil cases do not compete - if(c == nil) - return; - - i = sel->ncase; - if(i >= sel->tcase) - throw("selectsend: too many cases"); - sel->ncase = i+1; - cas = sel->scase[i]; - if(cas == nil) { - cas = mal(sizeof *cas + c->elemsize - sizeof(cas->u.elem)); - sel->scase[i] = cas; - } - - cas->pc = sys·getcallerpc(&sel); - cas->chan = c; - - eo = rnd(sizeof(sel), sizeof(c)); - eo = rnd(eo+sizeof(c), c->elemsize); - cas->so = rnd(eo+c->elemsize, 1); - cas->send = 1; - - ae = (byte*)&sel + eo; - c->elemalg->copy(c->elemsize, cas->u.elem, ae); - - if(debug) { - prints("selectsend s="); - sys·printpointer(sel); - prints(" pc="); - sys·printpointer(cas->pc); - prints(" chan="); - sys·printpointer(cas->chan); - prints(" po="); - sys·printint(cas->so); - prints(" send="); - sys·printint(cas->send); - prints("\n"); - } -} - -// selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool); -void -sys·selectrecv(Select *sel, Hchan *c, ...) -{ - int32 i, eo; - Scase *cas; - - // nil cases do not compete - if(c == nil) - return; - - i = sel->ncase; - if(i >= sel->tcase) - throw("selectrecv: too many cases"); - sel->ncase = i+1; - cas = sel->scase[i]; - if(cas == nil) { - cas = mal(sizeof *cas); - sel->scase[i] = cas; - } - cas->pc = sys·getcallerpc(&sel); - cas->chan = c; - - eo = rnd(sizeof(sel), sizeof(c)); - eo = rnd(eo+sizeof(c), sizeof(byte*)); - cas->so = rnd(eo+sizeof(byte*), 1); - cas->send = 0; - cas->u.elemp = *(byte**)((byte*)&sel + eo); - - if(debug) { - prints("selectrecv s="); - sys·printpointer(sel); - prints(" pc="); - sys·printpointer(cas->pc); - prints(" chan="); - sys·printpointer(cas->chan); - prints(" so="); - sys·printint(cas->so); - prints(" send="); - sys·printint(cas->send); - prints("\n"); - } -} - - -// selectdefaul(sel *byte) (selected bool); -void -sys·selectdefault(Select *sel, ...) -{ - int32 i; - Scase *cas; - - i = sel->ncase; - if(i >= sel->tcase) - throw("selectdefault: too many cases"); - sel->ncase = i+1; - cas = sel->scase[i]; - if(cas == nil) { - cas = mal(sizeof *cas); - sel->scase[i] = cas; - } - cas->pc = sys·getcallerpc(&sel); - cas->chan = nil; - - cas->so = rnd(sizeof(sel), 1); - cas->send = 2; - cas->u.elemp = nil; - - if(debug) { - prints("selectdefault s="); - sys·printpointer(sel); - prints(" pc="); - sys·printpointer(cas->pc); - prints(" so="); - sys·printint(cas->so); - prints(" send="); - sys·printint(cas->send); - prints("\n"); - } -} - -// selectgo(sel *byte); -void -sys·selectgo(Select *sel) -{ - uint32 p, o, i; - Scase *cas, *dfl; - Hchan *c; - SudoG *sg; - G *gp; - byte *as; - - if(debug) { - prints("selectgo: sel="); - sys·printpointer(sel); - prints("\n"); - } - - if(sel->ncase < 2) { - if(sel->ncase < 1) - throw("selectgo: no cases"); - // make special case of one. - } - - // select a (relative) prime - for(i=0;; i++) { - p = fastrand1(); - if(gcd(p, sel->ncase) == 1) - break; - if(i > 1000) { - throw("selectgo: failed to select prime"); - } - } - - // select an initial offset - o = fastrand2(); - - p %= sel->ncase; - o %= sel->ncase; - - lock(&chanlock); - -loop: - // pass 1 - look for something already waiting - dfl = nil; - for(i=0; incase; i++) { - cas = sel->scase[o]; - - if(cas->send == 2) { // default - dfl = cas; - goto next1; - } - - c = cas->chan; - if(c->dataqsiz > 0) { - if(cas->send) { - if(c->closed & Wclosed) - goto sclose; - if(c->qcount < c->dataqsiz) - goto asyns; - goto next1; - } - if(c->qcount > 0) - goto asynr; - if(c->closed & Wclosed) - goto rclose; - goto next1; - } - - if(cas->send) { - if(c->closed & Wclosed) - goto sclose; - sg = dequeue(&c->recvq, c); - if(sg != nil) - goto gots; - goto next1; - } - sg = dequeue(&c->sendq, c); - if(sg != nil) - goto gotr; - if(c->closed & Wclosed) - goto rclose; - - next1: - o += p; - if(o >= sel->ncase) - o -= sel->ncase; - } - - if(dfl != nil) { - cas = dfl; - goto retc; - } - - - // pass 2 - enqueue on all chans - for(i=0; incase; i++) { - cas = sel->scase[o]; - c = cas->chan; - - if(c->dataqsiz > 0) { - if(cas->send) { - if(c->qcount < c->dataqsiz) { - prints("selectgo: pass 2 async send\n"); - goto asyns; - } - sg = allocsg(c); - sg->offset = o; - enqueue(&c->sendq, sg); - goto next2; - } - if(c->qcount > 0) { - prints("selectgo: pass 2 async recv\n"); - goto asynr; - } - sg = allocsg(c); - sg->offset = o; - enqueue(&c->recvq, sg); - goto next2; - } - - if(cas->send) { - sg = dequeue(&c->recvq, c); - if(sg != nil) { - prints("selectgo: pass 2 sync send\n"); - g->selgen++; - goto gots; - } - sg = allocsg(c); - sg->offset = o; - c->elemalg->copy(c->elemsize, sg->elem, cas->u.elem); - enqueue(&c->sendq, sg); - goto next2; - } - sg = dequeue(&c->sendq, c); - if(sg != nil) { - prints("selectgo: pass 2 sync recv\n"); - g->selgen++; - goto gotr; - } - sg = allocsg(c); - sg->offset = o; - enqueue(&c->recvq, sg); - - next2: - o += p; - if(o >= sel->ncase) - o -= sel->ncase; - } - - g->param = nil; - g->status = Gwaiting; - unlock(&chanlock); - gosched(); - - lock(&chanlock); - sg = g->param; - if(sg == nil) - goto loop; - - o = sg->offset; - cas = sel->scase[o]; - c = cas->chan; - - if(c->dataqsiz > 0) { -// prints("shouldnt happen\n"); - goto loop; - } - - if(debug) { - prints("wait-return: sel="); - sys·printpointer(sel); - prints(" c="); - sys·printpointer(c); - prints(" cas="); - sys·printpointer(cas); - prints(" send="); - sys·printint(cas->send); - prints(" o="); - sys·printint(o); - prints("\n"); - } - - if(!cas->send) { - if(cas->u.elemp != nil) - c->elemalg->copy(c->elemsize, cas->u.elemp, sg->elem); - } - - freesg(c, sg); - goto retc; - -asynr: - if(cas->u.elemp != nil) - c->elemalg->copy(c->elemsize, cas->u.elemp, c->recvdataq->elem); - c->recvdataq = c->recvdataq->link; - c->qcount--; - sg = dequeue(&c->sendq, c); - if(sg != nil) { - gp = sg->g; - freesg(c, sg); - ready(gp); - } - goto retc; - -asyns: - if(cas->u.elem != nil) - c->elemalg->copy(c->elemsize, c->senddataq->elem, cas->u.elem); - c->senddataq = c->senddataq->link; - c->qcount++; - sg = dequeue(&c->recvq, c); - if(sg != nil) { - gp = sg->g; - freesg(c, sg); - ready(gp); - } - goto retc; - -gotr: - // recv path to wakeup the sender (sg) - if(debug) { - prints("gotr: sel="); - sys·printpointer(sel); - prints(" c="); - sys·printpointer(c); - prints(" o="); - sys·printint(o); - prints("\n"); - } - if(cas->u.elemp != nil) - c->elemalg->copy(c->elemsize, cas->u.elemp, sg->elem); - gp = sg->g; - gp->param = sg; - ready(gp); - goto retc; - -rclose: - if(cas->u.elemp != nil) - c->elemalg->copy(c->elemsize, cas->u.elemp, nil); - c->closed |= Rclosed; - incerr(c); - goto retc; - -gots: - // send path to wakeup the receiver (sg) - if(debug) { - prints("gots: sel="); - sys·printpointer(sel); - prints(" c="); - sys·printpointer(c); - prints(" o="); - sys·printint(o); - prints("\n"); - } - if(c->closed & Wclosed) - goto sclose; - c->elemalg->copy(c->elemsize, sg->elem, cas->u.elem); - gp = sg->g; - gp->param = sg; - ready(gp); - goto retc; - -sclose: - incerr(c); - goto retc; - -retc: - if(sel->ncase >= 1 && sel->ncase < nelem(selfree)) { - sel->link = selfree[sel->ncase]; - selfree[sel->ncase] = sel; - } - unlock(&chanlock); - - sys·setcallerpc(&sel, cas->pc); - as = (byte*)&sel + cas->so; - *as = true; -} - -// closechan(sel *byte); -void -sys·closechan(Hchan *c) -{ - SudoG *sg; - G* gp; - - lock(&chanlock); - incerr(c); - c->closed |= Wclosed; - - // release all readers - for(;;) { - sg = dequeue(&c->recvq, c); - if(sg == nil) - break; - gp = sg->g; - gp->param = nil; - freesg(c, sg); - ready(gp); - } - - // release all writers - for(;;) { - sg = dequeue(&c->sendq, c); - if(sg == nil) - break; - gp = sg->g; - gp->param = nil; - freesg(c, sg); - ready(gp); - } - - unlock(&chanlock); -} - -// closedchan(sel *byte) bool; -void -sys·closedchan(Hchan *c, bool closed) -{ - // test Rclosed - closed = 0; - if(c->closed & Rclosed) - closed = 1; - FLUSH(&closed); -} - -static SudoG* -dequeue(WaitQ *q, Hchan *c) -{ - SudoG *sgp; - -loop: - sgp = q->first; - if(sgp == nil) - return nil; - q->first = sgp->link; - - // if sgp is stale, ignore it - if(sgp->selgen != sgp->g->selgen) { - //prints("INVALID PSEUDOG POINTER\n"); - freesg(c, sgp); - goto loop; - } - - // invalidate any others - sgp->g->selgen++; - return sgp; -} - -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; -} - -static SudoG* -allocsg(Hchan *c) -{ - SudoG* sg; - - sg = c->free; - if(sg != nil) { - c->free = sg->link; - } else - sg = mal(sizeof(*sg) + c->elemsize - sizeof(sg->elem)); - sg->selgen = g->selgen; - sg->g = g; - sg->offset = 0; - sg->isfree = 0; - - return sg; -} - -static void -freesg(Hchan *c, SudoG *sg) -{ - if(sg != nil) { - if(sg->isfree) - throw("chan.freesg: already free"); - sg->isfree = 1; - sg->link = c->free; - c->free = sg; - } -} - -static uint32 -gcd(uint32 u, uint32 v) -{ - for(;;) { - if(u > v) { - if(v == 0) - return u; - u = u%v; - continue; - } - if(u == 0) - return v; - v = v%u; - } -} - -static uint32 -fastrand1(void) -{ - static uint32 x = 0x49f6428aUL; - - x += x; - if(x & 0x80000000L) - x ^= 0x88888eefUL; - return x; -} - -static uint32 -fastrand2(void) -{ - static uint32 x = 0x49f6428aUL; - - x += x; - if(x & 0x80000000L) - x ^= 0xfafd871bUL; - return x; -} diff --git a/src/lib/runtime/darwin/386/defs.h b/src/lib/runtime/darwin/386/defs.h deleted file mode 100644 index b66a5d8b4..000000000 --- a/src/lib/runtime/darwin/386/defs.h +++ /dev/null @@ -1,229 +0,0 @@ -// godefs -f -m32 defs.c - -// MACHINE GENERATED - DO NOT EDIT. - -// Constants -enum { - PROT_NONE = 0, - PROT_READ = 0x1, - PROT_WRITE = 0x2, - PROT_EXEC = 0x4, - MAP_ANON = 0x1000, - MAP_PRIVATE = 0x2, - 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, -}; - -// 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 { - void *__sa_handler; - void *__sa_sigaction; -}; - -typedef struct Sigaction Sigaction; -struct Sigaction { - Sighandler __sigaction_u; - void *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 FPControl FPControl; -struct FPControl { - byte pad0[2]; -}; - -typedef struct FPStatus FPStatus; -struct FPStatus { - byte pad0[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 { - int32 fpu_reserved[2]; - FPControl fpu_fcw; - FPStatus fpu_fsw; - uint8 fpu_ftw; - uint8 fpu_rsrv1; - uint16 fpu_fop; - uint32 fpu_ip; - uint16 fpu_cs; - uint16 fpu_rsrv2; - uint32 fpu_dp; - uint16 fpu_ds; - uint16 fpu_rsrv3; - uint32 fpu_mxcsr; - uint32 fpu_mxcsrmask; - RegMMST fpu_stmm0; - RegMMST fpu_stmm1; - RegMMST fpu_stmm2; - RegMMST fpu_stmm3; - RegMMST fpu_stmm4; - RegMMST fpu_stmm5; - RegMMST fpu_stmm6; - RegMMST fpu_stmm7; - RegXMM fpu_xmm0; - RegXMM fpu_xmm1; - RegXMM fpu_xmm2; - RegXMM fpu_xmm3; - RegXMM fpu_xmm4; - RegXMM fpu_xmm5; - RegXMM fpu_xmm6; - RegXMM fpu_xmm7; - int8 fpu_rsrv4[224]; - int32 fpu_reserved1; -}; - -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; - Ucontext *uc_link; - uint32 uc_mcsize; - Mcontext *uc_mcontext; -}; -#pragma pack off diff --git a/src/lib/runtime/darwin/386/rt0.s b/src/lib/runtime/darwin/386/rt0.s deleted file mode 100755 index 5b52e912c..000000000 --- a/src/lib/runtime/darwin/386/rt0.s +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Darwin and Linux use the same linkage to main - -TEXT _rt0_386_darwin(SB),7,$0 - JMP _rt0_386(SB) diff --git a/src/lib/runtime/darwin/386/signal.c b/src/lib/runtime/darwin/386/signal.c deleted file mode 100644 index 3a63c4b38..000000000 --- a/src/lib/runtime/darwin/386/signal.c +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "runtime.h" -#include "defs.h" -#include "os.h" -#include "signals.h" - -void -dumpregs(Regs *r) -{ - printf("eax %x\n", r->eax); - printf("ebx %x\n", r->ebx); - printf("ecx %x\n", r->ecx); - printf("edx %x\n", r->edx); - printf("edi %x\n", r->edi); - printf("esi %x\n", r->esi); - printf("ebp %x\n", r->ebp); - printf("esp %x\n", r->esp); - printf("eip %x\n", r->eip); - printf("eflags %x\n", r->eflags); - printf("cs %x\n", r->cs); - printf("fs %x\n", r->fs); - printf("gs %x\n", r->gs); -} - -void -sighandler(int32 sig, Siginfo *info, void *context) -{ - Ucontext *uc; - Mcontext *mc; - Regs *r; - - if(panicking) // traceback already printed - exit(2); - panicking = 1; - - if(sig < 0 || sig >= NSIG){ - printf("Signal %d\n", sig); - }else{ - printf("%s\n", sigtab[sig].name); - } - - uc = context; - mc = uc->uc_mcontext; - r = &mc->ss; - - printf("Faulting address: %p\n", info->si_addr); - printf("pc: %x\n", r->eip); - printf("\n"); - - if(gotraceback()){ - traceback((void*)r->eip, (void*)r->esp, m->curg); - tracebackothers(m->curg); - dumpregs(r); - } - - breakpoint(); - exit(2); -} - -void -sigignore(int32, Siginfo*, void*) -{ -} - -void -signalstack(byte *p, int32 n) -{ - StackT st; - - st.ss_sp = p; - st.ss_size = n; - st.ss_flags = 0; - sigaltstack(&st, nil); -} - -void -initsig(void) -{ - int32 i; - static Sigaction sa; - - sa.sa_flags |= SA_SIGINFO|SA_ONSTACK; - sa.sa_mask = 0; // 0xFFFFFFFFU; - sa.sa_tramp = sigtramp; // sigtramp's job is to call into real handler - for(i = 0; igsignal - MOVL BP, 0(FS) // g = m->gsignal - - MOVL handler+4(FP), DI - MOVL signo+12(FP), AX - MOVL siginfo+16(FP), BX - MOVL context+20(FP), CX - - MOVL AX, 0(SP) - MOVL BX, 4(SP) - MOVL CX, 8(SP) - CALL DI - - MOVL context+20(FP), CX - MOVL style+8(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 notok(SB) - RET - -TEXT sigaltstack(SB),7,$0 - MOVL $53, AX - INT $0x80 - JAE 2(PC) - CALL notok(SB) - RET - -// void bsdthread_create(void *stk, M *m, G *g, void (*fn)(void)) -// System call args are: func arg stack pthread flags. -TEXT bsdthread_create(SB),7,$32 - 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 m+4(FP), BX - MOVL BX, 8(SP) // arg - MOVL stk+0(FP), BX - MOVL BX, 12(SP) // stack - MOVL g+8(FP), BX - MOVL BX, 16(SP) // pthread - MOVL $0x1000000, 20(SP) // flags = PTHREAD_START_CUSTOM - INT $0x80 - JAE 2(PC) - CALL notok(SB) - 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 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 40(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 setldt(SB) - POPL AX - POPL AX - POPL AX - POPAL - SHLL $3, DI // segment# is ldt*8 + 7. - ADDL $7, DI - MOVW DI, FS - - // Now segment is established. Initialize m, g. - MOVL AX, 0(FS) // g - MOVL DX, 4(FS) // m - MOVL BX, 20(DX) // m->procid = thread port (for debuggers) - CALL CX // fn() - CALL exit1(SB) - RET - -// void bsdthread_register(void) -// registers callbacks for threadstart (see bsdthread_create above -// and wqthread and pthsize (not used). returns 0 on success. -TEXT bsdthread_register(SB),7,$40 - MOVL $366, AX - // 0(SP) is where kernel expects caller PC; ignored - MOVL $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) // paranoia - MOVL $0, 20(SP) - MOVL $0, 24(SP) - INT $0x80 - JAE 2(PC) - CALL 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 sysenter(SB),7,$0 - POPL DX - MOVL SP, CX - BYTE $0x0F; BYTE $0x34; // SYSENTER - // returns to DX with SP set to CX - -TEXT mach_msg_trap(SB),7,$0 - MOVL $-31, AX - CALL sysenter(SB) - RET - -TEXT mach_reply_port(SB),7,$0 - MOVL $-26, AX - CALL sysenter(SB) - RET - -TEXT mach_task_self(SB),7,$0 - MOVL $-28, AX - CALL sysenter(SB) - RET - -// Mach provides trap versions of the semaphore ops, -// instead of requiring the use of RPC. - -// uint32 mach_semaphore_wait(uint32) -TEXT mach_semaphore_wait(SB),7,$0 - MOVL $-36, AX - CALL sysenter(SB) - RET - -// uint32 mach_semaphore_timedwait(uint32, uint32, uint32) -TEXT mach_semaphore_timedwait(SB),7,$0 - MOVL $-38, AX - CALL sysenter(SB) - RET - -// uint32 mach_semaphore_signal(uint32) -TEXT mach_semaphore_signal(SB),7,$0 - MOVL $-33, AX - CALL sysenter(SB) - RET - -// uint32 mach_semaphore_signal_all(uint32) -TEXT mach_semaphore_signal_all(SB),7,$0 - MOVL $-34, AX - CALL sysenter(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 setldt(SB),7,$32 - // set up data_desc - LEAL 16(SP), AX // struct data_desc - MOVL $0, 0(AX) - MOVL $0, 4(AX) - - MOVL address+4(FP), BX // aka base - MOVW BX, 2(AX) - SHRL $16, BX - MOVB BX, 4(AX) - SHRL $8, BX - MOVB BX, 7(AX) - - MOVL limit+8(FP), BX - MOVW BX, 0(AX) - SHRL $16, BX - ANDL $0x0F, BX - ORL $0x40, BX // 32-bit operand size - MOVB BX, 6(AX) - - MOVL $0xF2, 5(AX) // r/w data descriptor, dpl=3, present - - // call i386_set_ldt(entry, desc, 1) - MOVL entry+0(FP), BX - MOVL BX, 0(SP) - MOVL AX, 4(SP) - MOVL $1, 8(SP) - CALL i386_set_ldt(SB) - RET - -TEXT i386_set_ldt(SB),7,$0 - MOVL $5, AX - INT $0x82 // sic - JAE 2(PC) - CALL notok(SB) - RET - diff --git a/src/lib/runtime/darwin/amd64/defs.h b/src/lib/runtime/darwin/amd64/defs.h deleted file mode 100644 index 1076e4c10..000000000 --- a/src/lib/runtime/darwin/amd64/defs.h +++ /dev/null @@ -1,244 +0,0 @@ -// godefs -f -m64 defs.c - -// MACHINE GENERATED - DO NOT EDIT. - -// Constants -enum { - PROT_NONE = 0, - PROT_READ = 0x1, - PROT_WRITE = 0x2, - PROT_EXEC = 0x4, - MAP_ANON = 0x1000, - MAP_PRIVATE = 0x2, - 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, -}; - -// 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 pad0[4]; -}; - -typedef union Sighandler Sighandler; -union Sighandler { - void *__sa_handler; - void *__sa_sigaction; -}; - -typedef struct Sigaction Sigaction; -struct Sigaction { - Sighandler __sigaction_u; - void *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 FPControl FPControl; -struct FPControl { - byte pad0[2]; -}; - -typedef struct FPStatus FPStatus; -struct FPStatus { - byte pad0[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 { - int32 fpu_reserved[2]; - FPControl fpu_fcw; - FPStatus fpu_fsw; - uint8 fpu_ftw; - uint8 fpu_rsrv1; - uint16 fpu_fop; - uint32 fpu_ip; - uint16 fpu_cs; - uint16 fpu_rsrv2; - uint32 fpu_dp; - uint16 fpu_ds; - uint16 fpu_rsrv3; - uint32 fpu_mxcsr; - uint32 fpu_mxcsrmask; - RegMMST fpu_stmm0; - RegMMST fpu_stmm1; - RegMMST fpu_stmm2; - RegMMST fpu_stmm3; - RegMMST fpu_stmm4; - RegMMST fpu_stmm5; - RegMMST fpu_stmm6; - RegMMST fpu_stmm7; - RegXMM fpu_xmm0; - RegXMM fpu_xmm1; - RegXMM fpu_xmm2; - RegXMM fpu_xmm3; - RegXMM fpu_xmm4; - RegXMM fpu_xmm5; - RegXMM fpu_xmm6; - RegXMM fpu_xmm7; - RegXMM fpu_xmm8; - RegXMM fpu_xmm9; - RegXMM fpu_xmm10; - RegXMM fpu_xmm11; - RegXMM fpu_xmm12; - RegXMM fpu_xmm13; - RegXMM fpu_xmm14; - RegXMM fpu_xmm15; - int8 fpu_rsrv4[96]; - int32 fpu_reserved1; -}; - -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 pad0[4]; -}; - -typedef struct Ucontext Ucontext; -struct Ucontext { - int32 uc_onstack; - uint32 uc_sigmask; - StackT uc_stack; - Ucontext *uc_link; - uint64 uc_mcsize; - Mcontext *uc_mcontext; -}; -#pragma pack off diff --git a/src/lib/runtime/darwin/amd64/rt0.s b/src/lib/runtime/darwin/amd64/rt0.s deleted file mode 100644 index 0a0011781..000000000 --- a/src/lib/runtime/darwin/amd64/rt0.s +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Darwin and Linux use the same linkage to main - -TEXT _rt0_amd64_darwin(SB),7,$-8 - MOVQ $_rt0_amd64(SB), AX - JMP AX diff --git a/src/lib/runtime/darwin/amd64/signal.c b/src/lib/runtime/darwin/amd64/signal.c deleted file mode 100644 index 45e5e8d47..000000000 --- a/src/lib/runtime/darwin/amd64/signal.c +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright 2009 The Go Authors. 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 -dumpregs(Regs *r) -{ - printf("rax %X\n", r->rax); - printf("rbx %X\n", r->rbx); - printf("rcx %X\n", r->rcx); - printf("rdx %X\n", r->rdx); - printf("rdi %X\n", r->rdi); - printf("rsi %X\n", r->rsi); - printf("rbp %X\n", r->rbp); - printf("rsp %X\n", r->rsp); - printf("r8 %X\n", r->r8 ); - printf("r9 %X\n", r->r9 ); - printf("r10 %X\n", r->r10); - printf("r11 %X\n", r->r11); - printf("r12 %X\n", r->r12); - printf("r13 %X\n", r->r13); - printf("r14 %X\n", r->r14); - printf("r15 %X\n", r->r15); - printf("rip %X\n", r->rip); - printf("rflags %X\n", r->rflags); - printf("cs %X\n", r->cs); - printf("fs %X\n", r->fs); - printf("gs %X\n", r->gs); -} - -void -sighandler(int32 sig, Siginfo *info, void *context) -{ - Ucontext *uc; - Mcontext *mc; - Regs *r; - - if(panicking) // traceback already printed - exit(2); - panicking = 1; - - if(sig < 0 || sig >= NSIG){ - printf("Signal %d\n", sig); - }else{ - printf("%s\n", sigtab[sig].name); - } - - uc = context; - mc = uc->uc_mcontext; - r = &mc->ss; - - printf("Faulting address: %p\n", info->si_addr); - printf("pc: %X\n", r->rip); - printf("\n"); - - if(gotraceback()){ - traceback((void*)r->rip, (void*)r->rsp, (void*)r->r15); - tracebackothers((void*)r->r15); - dumpregs(r); - } - - breakpoint(); - exit(2); -} - -void -sigignore(int32, Siginfo*, void*) -{ -} - -void -signalstack(byte *p, int32 n) -{ - StackT st; - - st.ss_sp = p; - st.ss_size = n; - st.ss_flags = 0; - sigaltstack(&st, nil); -} - -void -initsig(void) -{ - int32 i; - static Sigaction sa; - - sa.sa_flags |= SA_SIGINFO|SA_ONSTACK; - sa.sa_mask = 0; // 0xFFFFFFFFU; - sa.sa_tramp = sigtramp; // sigtramp's job is to call into real handler - for(i = 0; igsignal - MOVL DX,0(SP) - MOVQ CX,8(SP) - MOVQ R8,16(SP) - MOVQ R8, 24(SP) // save ucontext - MOVQ SI, 32(SP) // save infostyle - CALL DI - MOVL $(0x2000000+184), AX // sigreturn(ucontext, infostyle) - MOVQ 24(SP), DI // saved ucontext - MOVQ 32(SP), SI // saved infostyle - SYSCALL - INT $3 // not reached - -TEXT sys·mmap(SB),7,$-8 - MOVQ 8(SP), DI // arg 1 addr - MOVL 16(SP), SI // arg 2 len - MOVL 20(SP), DX // arg 3 prot - MOVL 24(SP), R10 // arg 4 flags - MOVL 28(SP), R8 // arg 5 fid - MOVL 32(SP), R9 // arg 6 offset - MOVL $(0x2000000+197), AX // syscall entry - SYSCALL - JCC 2(PC) - CALL notok(SB) - RET - -TEXT notok(SB),7,$-8 - MOVL $0xf1, BP - MOVQ BP, (BP) - RET - -TEXT sys·memclr(SB),7,$-8 - MOVQ 8(SP), DI // arg 1 addr - MOVL 16(SP), CX // arg 2 count - ADDL $7, CX - SHRL $3, CX - MOVQ $0, AX - CLD - REP - STOSQ - RET - -TEXT sys·getcallerpc+0(SB),7,$0 - MOVQ x+0(FP),AX // addr of first arg - MOVQ -8(AX),AX // get calling pc - RET - -TEXT sys·setcallerpc+0(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 sigaltstack(SB),7,$-8 - MOVQ new+8(SP), DI - MOVQ old+16(SP), SI - MOVQ $(0x2000000+53), AX - SYSCALL - JCC 2(PC) - CALL notok(SB) - RET - -// void bsdthread_create(void *stk, M *m, G *g, void (*fn)(void)) -TEXT bsdthread_create(SB),7,$-8 - // 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 m+16(SP), SI // "arg" - MOVQ stk+8(SP), DX // stack - MOVQ g+24(SP), R10 // "pthread" -// TODO(rsc): why do we get away with 0 flags here but not on 386? - MOVQ $0, R8 // flags - MOVQ $(0x2000000+360), AX // bsdthread_create - SYSCALL - JCC 2(PC) - CALL notok(SB) - RET - -// The thread that bsdthread_create creates starts executing here, -// because we registered this function using bsdthread_register -// at startup. -// DI = "pthread" (= g) -// SI = mach thread port -// DX = "func" (= fn) -// CX = "arg" (= m) -// R8 = stack -// R9 = flags (= 0) -// SP = stack - C_64_REDZONE_LEN (= stack - 128) -TEXT bsdthread_start(SB),7,$-8 - MOVQ CX, R14 // m - MOVQ DI, R15 // g - MOVQ SI, 24(R14) // thread port is m->procid - CALL DX // fn - CALL exit1(SB) - RET - -// void bsdthread_register(void) -// registers callbacks for threadstart (see bsdthread_create above -// and wqthread and pthsize (not used). returns 0 on success. -TEXT bsdthread_register(SB),7,$-8 - MOVQ $bsdthread_start(SB), DI // threadstart - MOVQ $0, SI // wqthread, not used by us - MOVQ $0, DX // pthsize, not used by us - MOVQ $(0x2000000+366), AX // bsdthread_register - SYSCALL - JCC 2(PC) - CALL notok(SB) - RET - -// Mach system calls use 0x1000000 instead of the BSD's 0x2000000. - -// uint32 mach_msg_trap(void*, uint32, uint32, uint32, uint32, uint32, uint32) -TEXT mach_msg_trap(SB),7,$0 - 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 mach_task_self(SB),7,$0 - MOVL $(0x1000000+28), AX // task_self_trap - SYSCALL - RET - -TEXT mach_thread_self(SB),7,$0 - MOVL $(0x1000000+27), AX // thread_self_trap - SYSCALL - RET - -TEXT 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 mach_semaphore_wait(SB),7,$0 - MOVL 8(SP), DI - MOVL $(0x1000000+36), AX // semaphore_wait_trap - SYSCALL - RET - -// uint32 mach_semaphore_timedwait(uint32, uint32, uint32) -TEXT mach_semaphore_timedwait(SB),7,$0 - 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 mach_semaphore_signal(SB),7,$0 - MOVL 8(SP), DI - MOVL $(0x1000000+33), AX // semaphore_signal_trap - SYSCALL - RET - -// uint32 mach_semaphore_signal_all(uint32) -TEXT mach_semaphore_signal_all(SB),7,$0 - MOVL 8(SP), DI - MOVL $(0x1000000+34), AX // semaphore_signal_all_trap - SYSCALL - RET - diff --git a/src/lib/runtime/darwin/defs.c b/src/lib/runtime/darwin/defs.c deleted file mode 100644 index 1ed662957..000000000 --- a/src/lib/runtime/darwin/defs.c +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* - * Input to godefs. - * - godefs -f -m64 defs.c >amd64/defs.h - godefs defs.c >386/defs.h - */ - -#define __DARWIN_UNIX03 0 - -#include -#include -#include -#include -#include -#include - -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, - - $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, -}; - -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 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/lib/runtime/darwin/os.h b/src/lib/runtime/darwin/os.h deleted file mode 100644 index 2a3ca87bd..000000000 --- a/src/lib/runtime/darwin/os.h +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -void bsdthread_create(void*, M*, G*, void(*)(void)); -void bsdthread_register(void); -int32 mach_msg_trap(MachHeader*, int32, uint32, uint32, uint32, uint32, uint32); -uint32 mach_reply_port(void); -void mach_semacquire(uint32); -uint32 mach_semcreate(void); -void mach_semdestroy(uint32); -void mach_semrelease(uint32); -void mach_semreset(uint32); -uint32 mach_task_self(void); -uint32 mach_task_self(void); -uint32 mach_thread_self(void); -uint32 mach_thread_self(void); - -struct Sigaction; -void sigaction(int64, struct Sigaction*, struct Sigaction*); - -struct StackT; -void sigaltstack(struct StackT*, struct StackT*); -void sigtramp(void); diff --git a/src/lib/runtime/darwin/signals.h b/src/lib/runtime/darwin/signals.h deleted file mode 100644 index 4051dc4dc..000000000 --- a/src/lib/runtime/darwin/signals.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - - -#define C SigCatch -#define I SigIgnore -#define R SigRestart - -static SigTab sigtab[] = { - /* 0 */ 0, "SIGNONE: no trap", - /* 1 */ 0, "SIGHUP: terminal line hangup", - /* 2 */ 0, "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, "SIGFPE: floating-point exception", - /* 9 */ 0, "SIGKILL: kill", - /* 10 */ C, "SIGBUS: bus error", - /* 11 */ C, "SIGSEGV: segmentation violation", - /* 12 */ C, "SIGSYS: bad system call", - /* 13 */ I, "SIGPIPE: write to broken pipe", - /* 14 */ 0, "SIGALRM: alarm clock", - /* 15 */ 0, "SIGTERM: termination", - /* 16 */ 0, "SIGURG: urgent condition on socket", - /* 17 */ 0, "SIGSTOP: stop", - /* 18 */ 0, "SIGTSTP: keyboard stop", - /* 19 */ 0, "SIGCONT: continue after stop", - /* 20 */ I+R, "SIGCHLD: child status has changed", - /* 21 */ 0, "SIGTTIN: background read from tty", - /* 22 */ 0, "SIGTTOU: background write to tty", - /* 23 */ 0, "SIGIO: i/o now possible", - /* 24 */ 0, "SIGXCPU: cpu limit exceeded", - /* 25 */ 0, "SIGXFSZ: file size limit exceeded", - /* 26 */ 0, "SIGVTALRM: virtual alarm clock", - /* 27 */ 0, "SIGPROF: profiling alarm clock", - /* 28 */ I+R, "SIGWINCH: window size change", - /* 29 */ 0, "SIGINFO: status request from keyboard", - /* 30 */ 0, "SIGUSR1: user-defined signal 1", - /* 31 */ 0, "SIGUSR2: user-defined signal 2", -}; -#undef C -#undef I -#undef R - -#define NSIG 32 diff --git a/src/lib/runtime/darwin/thread.c b/src/lib/runtime/darwin/thread.c deleted file mode 100644 index 3a982471a..000000000 --- a/src/lib/runtime/darwin/thread.c +++ /dev/null @@ -1,441 +0,0 @@ -// Copyright 2009 The Go Authors. 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" - -static void -unimplemented(int8 *name) -{ - prints(name); - 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 = mach_semcreate(); - if(!cas(psema, 0, sema)){ - // Someone else filled it in. Use theirs. - mach_semdestroy(sema); - return; - } -} - - -// Atomic add and return new value. -static uint32 -xadd(uint32 volatile *val, int32 delta) -{ - uint32 oval, nval; - - for(;;){ - oval = *val; - nval = oval + delta; - if(cas(val, oval, nval)) - return nval; - } -} - - -// 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. -// -// Note that semaphores are never destroyed (the kernel -// will clean up when the process exits). We assume for now -// that Locks are only used for long-lived structures like M and G. - -void -lock(Lock *l) -{ - if(m->locks < 0) - throw("lock count"); - m->locks++; - - // Allocate semaphore if needed. - if(l->sema == 0) - initsema(&l->sema); - - if(xadd(&l->key, 1) > 1) // someone else has it; wait - mach_semacquire(l->sema); -} - -void -unlock(Lock *l) -{ - m->locks--; - if(m->locks < 0) - throw("lock count"); - - if(xadd(&l->key, -1) > 0) // someone else is waiting - mach_semrelease(l->sema); -} - - -// 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 -usemacquire(Usema *s) -{ - if((int32)xadd(&s->u, -1) < 0) - mach_semacquire(s->k); -} - -void -usemrelease(Usema *s) -{ - if((int32)xadd(&s->u, 1) <= 0) - mach_semrelease(s->k); -} - - -// Event notifications. -void -noteclear(Note *n) -{ - n->wakeup = 0; -} - -void -notesleep(Note *n) -{ - if(n->sema.k == 0) - initsema(&n->sema.k); - while(!n->wakeup) - usemacquire(&n->sema); -} - -void -notewakeup(Note *n) -{ - if(n->sema.k == 0) - initsema(&n->sema.k); - n->wakeup = 1; - usemrelease(&n->sema); -} - - -// BSD interface for threading. -void -osinit(void) -{ - // Register our thread-creation callback (see {amd64,386}/sys.s). - bsdthread_register(); -} - -void -newosproc(M *m, G *g, void *stk, void (*fn)(void)) -{ - // printf("newosproc m=%p g=%p stk=%p fn=%p\n", m, g, stk, fn); - m->tls[0] = m->id; // so 386 asm can find it - bsdthread_create(stk, m, g, fn); -} - -// Called to initialize a new m (including the bootstrap m). -void -minit(void) -{ - // Initialize signal handling. - m->gsignal = malg(32*1024); // OS X wants >=8K, Linux >=2K - signalstack(m->gsignal->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) -{ - printf("mach error %s: %d\n", fn, r); - 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 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 = 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; - prints("send:\t"); - for(i=0; imsgh_size/sizeof(p[0]); i++){ - prints(" "); - sys·printpointer((void*)p[i]); - if(i%8 == 7) - prints("\n\t"); - } - if(i%8) - prints("\n"); - } - - ret = mach_msg(h, MACH_SEND_MSG|MACH_RCV_MSG, - h->msgh_size, maxsize, port, 0, 0); - if(ret != 0){ - if(DebugMach){ - prints("mach_msg error "); - sys·printint(ret); - prints("\n"); - } - return ret; - } - - if(DebugMach){ - p = (uint32*)h; - prints("recv:\t"); - for(i=0; imsgh_size/sizeof(p[0]); i++){ - prints(" "); - sys·printpointer((void*)p[i]); - if(i%8 == 7) - prints("\n\t"); - } - if(i%8) - prints("\n"); - } - - if(h->msgh_id != id+Reply){ - if(DebugMach){ - prints("mach_msg reply id mismatch "); - sys·printint(h->msgh_id); - prints(" != "); - sys·printint(id+Reply); - 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){ - prints("mig result "); - sys·printint(c->code); - prints("\n"); - } - return c->code; - } - - if(h->msgh_size != rxsize){ - if(DebugMach){ - prints("mach_msg reply size mismatch "); - sys·printint(h->msgh_size); - prints(" != "); - sys·printint(rxsize); - 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 -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 = 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 -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 = 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){ - macherror(r, "semaphore_destroy"); - } -} - -// The other calls have simple system call traps in sys.s -int32 mach_semaphore_wait(uint32 sema); -int32 mach_semaphore_timedwait(uint32 sema, uint32 sec, uint32 nsec); -int32 mach_semaphore_signal(uint32 sema); -int32 mach_semaphore_signal_all(uint32 sema); - -void -mach_semacquire(uint32 sem) -{ - int32 r; - - while((r = mach_semaphore_wait(sem)) != 0) { - if(r == KERN_ABORTED) // interrupted - continue; - macherror(r, "semaphore_wait"); - } -} - -void -mach_semrelease(uint32 sem) -{ - int32 r; - - while((r = mach_semaphore_signal(sem)) != 0) { - if(r == KERN_ABORTED) // interrupted - continue; - macherror(r, "semaphore_signal"); - } -} - diff --git a/src/lib/runtime/extern.go b/src/lib/runtime/extern.go deleted file mode 100644 index 6fb5756d6..000000000 --- a/src/lib/runtime/extern.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* - The runtime package contains operations that interact with Go's runtime system, - such as functions to control goroutines. - */ -package runtime - -// These functions are implemented in the base runtime library, ../../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. -func Goexit() - -// Breakpoint() executes a breakpoint trap. -func Breakpoint() - -// Caller reports file and line number information about function invocations on -// the calling goroutine's stack. The argument is the number of stack frames to -// ascend, with 1 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(n int) (pc uintptr, file string, line int, ok bool) diff --git a/src/lib/runtime/float.c b/src/lib/runtime/float.c deleted file mode 100644 index 5122f359a..000000000 --- a/src/lib/runtime/float.c +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright 2009 The Go Authors. 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 -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 -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 -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 -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 -isInf(float64 f, int32 sign) -{ - uint64 x; - - x = float64tobits(f); - if(sign == 0) - return x == uvinf || x == uvneginf; - if(sign > 0) - return x == uvinf; - return x == uvneginf; -} - -float64 -NaN(void) -{ - return float64frombits(uvnan); -} - -bool -isNaN(float64 f) -{ - uint64 x; - - x = float64tobits(f); - return ((uint32)(x>>52) & 0x7FF) == 0x7FF && !isInf(f, 0); -} - -float64 -Inf(int32 sign) -{ - if(sign >= 0) - return float64frombits(uvinf); - else - return float64frombits(uvneginf); -} - -enum -{ - MASK = 0x7ffL, - SHIFT = 64-11-1, - BIAS = 1022L, -}; - -float64 -frexp(float64 d, int32 *ep) -{ - uint64 x; - - if(d == 0) { - *ep = 0; - return 0; - } - x = float64tobits(d); - *ep = (int32)((x >> SHIFT) & MASK) - BIAS; - x &= ~((uint64)MASK << SHIFT); - x |= (uint64)BIAS << SHIFT; - return float64frombits(x); -} - -float64 -ldexp(float64 d, int32 e) -{ - uint64 x; - - if(d == 0) - return 0; - x = float64tobits(d); - e += (int32)(x >> SHIFT) & MASK; - if(e <= 0) - return 0; /* underflow */ - if(e >= MASK){ /* overflow */ - if(d < 0) - return Inf(-1); - return Inf(1); - } - x &= ~((uint64)MASK << SHIFT); - x |= (uint64)e << SHIFT; - return float64frombits(x); -} - -float64 -modf(float64 d, float64 *ip) -{ - float64 dd; - uint64 x; - int32 e; - - if(d < 1) { - if(d < 0) { - d = modf(-d, ip); - *ip = -*ip; - return -d; - } - *ip = 0; - return d; - } - - x = 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 = float64frombits(x); - *ip = dd; - return d - dd; -} - diff --git a/src/lib/runtime/float_go.cgo b/src/lib/runtime/float_go.cgo deleted file mode 100644 index 518d55950..000000000 --- a/src/lib/runtime/float_go.cgo +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package math - -#include "runtime.h" - -func Frexp(f float64) (frac float64, exp int32) { - frac = frexp(f, &exp); -} - -func Ldexp(frac float64, exp int32) (f float64) { - f = ldexp(frac, exp); -} - -func Modf(f float64) (integer float64, frac float64) { - frac = modf(f, &integer); -} - -func IsInf(f float64, sign int32) (is bool) { - is = isInf(f, sign); -} - -func IsNaN(f float64) (is bool) { - is = isNaN(f); -} - -func Inf(sign int32) (f float64) { - f = Inf(sign); -} - -func NaN() (f float64) { - f = NaN(); -} - -func Float32bits(f float32) (b uint32) { - b = float32tobits(f); -} - -func Float64bits(f float64) (b uint64) { - b = float64tobits(f); -} - -func Float32frombits(b uint32) (f float32) { - f = float32frombits(b); -} - -func Float64frombits(b uint64) (f float64) { - f = float64frombits(b); -} - diff --git a/src/lib/runtime/hashmap.c b/src/lib/runtime/hashmap.c deleted file mode 100644 index b3022ca14..000000000 --- a/src/lib/runtime/hashmap.c +++ /dev/null @@ -1,954 +0,0 @@ -// Copyright 2009 The Go Authors. 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" - -/* Return a pointer to the struct/union of type "type" - whose "field" field is addressed by pointer "p". */ - - -struct hash { /* 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 */ - 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; - uint32 ko; - uint32 vo; - uint32 po; - 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 (struct hash *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 (struct hash *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 = 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, - struct hash *h, void *data, void **pres); - -static void -hash_conv (struct hash *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 (struct hash *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); -} - -int32 -hash_lookup (struct hash *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); -} - -int32 -hash_remove (struct hash *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->keysize, 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, - struct hash *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); - } - } -} - -int32 -hash_insert (struct hash *h, void *data, void **pres) -{ - int32 rc = hash_insert_internal (&h->st, 0, (*h->data_hash) (h->keysize, data), h, data, pres); - - h->count += (rc == 0); /* increment count if element didn't previously exist */ - return (rc); -} - -uint32 -hash_count (struct hash *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; -} - -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; - } - } -} - -void -hash_iter_init (struct hash *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; -} - -void -hash_destroy (struct hash *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++; - } -} - -void -hash_visit (struct hash *h, void (*data_visit) (void *arg, int32 level, void *data), void *arg) -{ - hash_visit_internal (h->st, 0, 0, data_visit, arg); -} - -// -/// interfaces to go runtime -// - -static void -donothing(uint32 s, void *a, void *b) -{ - USED(s); - USED(a); - USED(b); -} - -typedef struct hash Hmap; -static int32 debug = 0; - -// newmap(keysize uint32, valsize uint32, -// keyalg uint32, valalg uint32, -// hint uint32) (hmap *map[any]any); -void -sys·newmap(uint32 keysize, uint32 valsize, - uint32 keyalg, uint32 valalg, uint32 hint, - Hmap* ret) -{ - Hmap *h; - - if(keyalg >= nelem(algarray) || algarray[keyalg].hash == nohash) { - printf("map(keyalg=%d)\n", keyalg); - throw("sys·newmap: unsupported map key type"); - } - - if(valalg >= nelem(algarray)) { - printf("map(valalg=%d)\n", valalg); - throw("sys·newmap: unsupported map value type"); - } - - h = mal(sizeof(*h)); - - // 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 >= sizeof(void*)) - h->datavo = rnd(keysize, sizeof(void*)); - - hash_init(h, h->datavo+valsize, - algarray[keyalg].hash, - algarray[keyalg].equal, - donothing, - hint); - - h->keysize = keysize; - h->valsize = valsize; - h->keyalg = &algarray[keyalg]; - h->valalg = &algarray[valalg]; - - // these calculations are compiler dependent. - // figure out offsets of map call arguments. - h->ko = rnd(sizeof(h), keysize); - h->vo = rnd(h->ko+keysize, valsize); - h->po = rnd(h->vo+valsize, 1); - - ret = h; - FLUSH(&ret); - - if(debug) { - prints("newmap: map="); - sys·printpointer(h); - prints("; keysize="); - sys·printint(keysize); - prints("; valsize="); - sys·printint(valsize); - prints("; keyalg="); - sys·printint(keyalg); - prints("; valalg="); - sys·printint(valalg); - prints("; ko="); - sys·printint(h->ko); - prints("; vo="); - sys·printint(h->vo); - prints("; po="); - sys·printint(h->po); - prints("\n"); - } -} - -// mapaccess1(hmap *map[any]any, key any) (val any); -void -sys·mapaccess1(Hmap *h, ...) -{ - byte *ak, *av; - byte *res; - int32 hit; - - ak = (byte*)&h + h->ko; - av = (byte*)&h + h->vo; - - res = nil; - hit = hash_lookup(h, ak, (void**)&res); - if(!hit) - throw("sys·mapaccess1: key not in map"); - h->valalg->copy(h->valsize, av, res+h->datavo); - - if(debug) { - prints("sys·mapaccess1: map="); - sys·printpointer(h); - prints("; key="); - h->keyalg->print(h->keysize, ak); - prints("; val="); - h->valalg->print(h->valsize, av); - prints("; hit="); - sys·printint(hit); - prints("; res="); - sys·printpointer(res); - prints("\n"); - } -} - -// mapaccess2(hmap *map[any]any, key any) (val any, pres bool); -void -sys·mapaccess2(Hmap *h, ...) -{ - byte *ak, *av, *ap; - byte *res; - int32 hit; - - ak = (byte*)&h + h->ko; - av = (byte*)&h + h->vo; - ap = (byte*)&h + h->po; - - res = nil; - hit = hash_lookup(h, ak, (void**)&res); - if(!hit) { - *ap = false; - h->valalg->copy(h->valsize, av, nil); - } else { - *ap = true; - h->valalg->copy(h->valsize, av, res+h->datavo); - } - - if(debug) { - prints("sys·mapaccess2: map="); - sys·printpointer(h); - prints("; key="); - h->keyalg->print(h->keysize, ak); - prints("; val="); - h->valalg->print(h->valsize, av); - prints("; hit="); - sys·printint(hit); - prints("; res="); - sys·printpointer(res); - prints("; pres="); - sys·printbool(*ap); - prints("\n"); - } -} - -static void -mapassign(Hmap *h, byte *ak, byte *av) -{ - byte *res; - int32 hit; - - res = nil; - hit = hash_insert(h, ak, (void**)&res); - h->keyalg->copy(h->keysize, res, ak); - h->valalg->copy(h->valsize, res+h->datavo, av); - - if(debug) { - prints("mapassign: map="); - sys·printpointer(h); - prints("; key="); - h->keyalg->print(h->keysize, ak); - prints("; val="); - h->valalg->print(h->valsize, av); - prints("; hit="); - sys·printint(hit); - prints("; res="); - sys·printpointer(res); - prints("\n"); - } -} - -// mapassign1(hmap *map[any]any, key any, val any); -void -sys·mapassign1(Hmap *h, ...) -{ - byte *ak, *av; - - ak = (byte*)&h + h->ko; - av = (byte*)&h + h->vo; - - mapassign(h, ak, av); -} - -// mapassign2(hmap *map[any]any, key any, val any, pres bool); -void -sys·mapassign2(Hmap *h, ...) -{ - byte *ak, *av, *ap; - byte *res; - int32 hit; - - ak = (byte*)&h + h->ko; - av = (byte*)&h + h->vo; - ap = (byte*)&h + h->po; - - if(*ap == true) { - // assign - mapassign(h, ak, av); - return; - } - - // delete - hit = hash_remove(h, ak, (void**)&res); - - if(debug) { - prints("mapassign2: map="); - sys·printpointer(h); - prints("; key="); - h->keyalg->print(h->keysize, ak); - prints("; hit="); - sys·printint(hit); - prints("; res="); - sys·printpointer(res); - prints("\n"); - } -} - -// mapiterinit(hmap *map[any]any, hiter *any); -void -sys·mapiterinit(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) { - prints("sys·mapiterinit: map="); - sys·printpointer(h); - prints("; iter="); - sys·printpointer(it); - prints("; data="); - sys·printpointer(it->data); - prints("\n"); - } -} - -// mapiternext(hiter *any); -void -sys·mapiternext(struct hash_iter *it) -{ - it->data = hash_next(it); - if(debug) { - prints("sys·mapiternext: iter="); - sys·printpointer(it); - prints("; data="); - sys·printpointer(it->data); - prints("\n"); - } -} - -// mapiter1(hiter *any) (key any); -void -sys·mapiter1(struct hash_iter *it, ...) -{ - Hmap *h; - byte *ak, *res; - - h = it->h; - ak = (byte*)&it + h->ko; - - res = it->data; - if(res == nil) - throw("sys·mapiter2: key:val nil pointer"); - - h->keyalg->copy(h->keysize, ak, res); - - if(debug) { - prints("mapiter2: iter="); - sys·printpointer(it); - prints("; map="); - sys·printpointer(h); - prints("\n"); - } -} - -// mapiter2(hiter *any) (key any, val any); -void -sys·mapiter2(struct hash_iter *it, ...) -{ - Hmap *h; - byte *ak, *av, *res; - - h = it->h; - ak = (byte*)&it + h->ko; - av = (byte*)&it + h->vo; - - res = it->data; - if(res == nil) - throw("sys·mapiter2: key:val nil pointer"); - - h->keyalg->copy(h->keysize, ak, res); - h->valalg->copy(h->valsize, av, res+h->datavo); - - if(debug) { - prints("mapiter2: iter="); - sys·printpointer(it); - prints("; map="); - sys·printpointer(h); - prints("\n"); - } -} diff --git a/src/lib/runtime/hashmap.h b/src/lib/runtime/hashmap.h deleted file mode 100644 index ff93e9ee3..000000000 --- a/src/lib/runtime/hashmap.h +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2009 The Go 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 mal -#define free(a) USED(a) -#define offsetof(s,m) (uint32)(&(((s*)0)->m)) -#define memset(a,b,c) sys·memclr((byte*)(a), (uint32)(c)) -#define memmove(a,b,c) mmov((byte*)(a),(byte*)(b),(uint32)(c)) -#define memcpy(a,b,c) mcpy((byte*)(a),(byte*)(b),(uint32)(c)) -#define assert(a) if(!(a)) throw("assert") - -struct hash; /* 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 hash *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/lib/runtime/iface.c b/src/lib/runtime/iface.c deleted file mode 100644 index 6c933b1b2..000000000 --- a/src/lib/runtime/iface.c +++ /dev/null @@ -1,906 +0,0 @@ -// Copyright 2009 The Go Authors. 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" - -int32 iface_debug = 0; - -typedef struct Sigt Sigt; -typedef struct Sigi Sigi; -typedef struct Itype Itype; - -/* - * the layout of Iface, Sigt and Sigi are known to the compiler - */ -struct Sigt -{ - byte* name; // name of basic type - Sigt* link; // for linking into hash tables - uint32 thash; // hash of type - uint32 mhash; // hash of methods - uint16 width; // width of base type in bytes - uint16 alg; // algorithm - // note: on amd64 there is a 32-bit pad here. - struct { - byte* fname; - uint32 fhash; // hash of type - uint32 offset; // offset of substruct - void (*fun)(void); - } meth[1]; // one or more - last name is nil -}; - -struct Sigi -{ - byte* name; - uint32 hash; - uint32 size; // number of methods - struct { - byte* fname; - uint32 fhash; - uint32 perm; // location of fun in Sigt - } meth[1]; // [size+1] - last name is nil -}; - -struct Itype -{ - Sigi* sigi; - Sigt* sigt; - Itype* link; - int32 bad; - int32 unused; - void (*fun[])(void); -}; - -static Iface niliface; -static Eface nileface; - -static Itype* hash[1009]; -static Lock ifacelock; - -Sigi sigi·empty[2] = { (byte*)"interface { }" }; - -static void -printsigi(Sigi *si) -{ - int32 i; - byte *name; - - sys·printpointer(si); - prints("{"); - prints((int8*)si->name); - prints(":"); - for(i=0;; i++) { - name = si->meth[i].fname; - if(name == nil) - break; - prints("["); - sys·printint(i); - prints("]\""); - prints((int8*)name); - prints("\""); - sys·printint(si->meth[i].fhash%999); - prints("/"); - sys·printint(si->meth[i].perm); - } - prints("}"); -} - -static void -printsigt(Sigt *st) -{ - int32 i; - byte *name; - - sys·printpointer(st); - prints("{"); - prints((int8*)st->name); - prints(":"); - sys·printint(st->thash%999); // type hash - prints(","); - sys·printint(st->mhash%999); // method hash - prints(","); - sys·printint(st->width); // width - prints(","); - sys·printint(st->alg); // algorithm - for(i=0;; i++) { - name = st->meth[i].fname; - if(name == nil) - break; - prints("["); - sys·printint(i); - prints("]\""); - prints((int8*)name); - prints("\""); - sys·printint(st->meth[i].fhash%999); - prints("/"); - sys·printint(st->meth[i].offset); - prints("/"); - sys·printpointer(st->meth[i].fun); - } - prints("}"); -} - -static void -printiface(Iface i) -{ - prints("("); - sys·printpointer(i.type); - prints(","); - sys·printpointer(i.data); - prints(")"); -} - -static void -printeface(Eface e) -{ - prints("("); - sys·printpointer(e.type); - prints(","); - sys·printpointer(e.data); - prints(")"); -} - -static Itype* -itype(Sigi *si, Sigt *st, int32 canfail) -{ - int32 locked; - int32 nt, ni; - uint32 ihash, h; - byte *sname, *iname; - Itype *m; - - if(si->size == 0) - throw("internal error - misuse of itype"); - - // easy case - if(st->meth[0].fname == nil) { - if(canfail) - return nil; - iname = si->meth[0].fname; - goto throw1; - } - - // compiler has provided some good hash codes for us. - h = 0; - if(si) - h += si->hash; - if(st) { - h += st->thash; - h += st->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) - lock(&ifacelock); - for(m=hash[h]; m!=nil; m=m->link) { - if(m->sigi == si && m->sigt == st) { - 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 - // give a better error. - goto throw; - } - } - if(locked) - unlock(&ifacelock); - return m; - } - } - } - - ni = si->size; - m = malloc(sizeof(*m) + ni*sizeof(m->fun[0])); - m->sigi = si; - m->sigt = st; - -throw: - nt = 0; - for(ni=0;; ni++) { - iname = si->meth[ni].fname; - if(iname == nil) - break; - - // pick up next name from - // interface signature - ihash = si->meth[ni].fhash; - - for(;; nt++) { - // pick up and compare next name - // from structure signature - sname = st->meth[nt].fname; - if(sname == nil) { - if(!canfail) { - throw1: - printf("cannot convert type %s to interface %s: missing method %s\n", - st->name, si->name, iname); - if(iface_debug) { - prints("interface"); - printsigi(si); - prints("\ntype"); - printsigt(st); - prints("\n"); - } - throw("interface conversion"); - return nil; // not reached - } - m->bad = 1; - m->link = hash[h]; - hash[h] = m; - if(locked) - unlock(&ifacelock); - return nil; - } - if(ihash == st->meth[nt].fhash && strcmp(sname, iname) == 0) - break; - } - m->fun[si->meth[ni].perm] = st->meth[nt].fun; - } - m->link = hash[h]; - hash[h] = m; - if(locked) - unlock(&ifacelock); - - return m; -} - -static void -copyin(Sigt *st, void *src, void **dst) -{ - int32 wid, alg; - void *p; - - wid = st->width; - alg = st->alg; - - if(wid <= sizeof(*dst)) - algarray[alg].copy(wid, dst, src); - else { - p = mal(wid); - algarray[alg].copy(wid, p, src); - *dst = p; - } -} - -static void -copyout(Sigt *st, void **src, void *dst) -{ - int32 wid, alg; - - wid = st->width; - alg = st->alg; - - if(wid <= sizeof(*src)) - algarray[alg].copy(wid, dst, src); - else - algarray[alg].copy(wid, dst, *src); -} - -// ifaceT2I(sigi *byte, sigt *byte, elem any) (ret any); -#pragma textflag 7 -void -sys·ifaceT2I(Sigi *si, Sigt *st, ...) -{ - byte *elem; - Iface *ret; - int32 wid; - - elem = (byte*)(&st+1); - wid = st->width; - ret = (Iface*)(elem + rnd(wid, sizeof(uintptr))); - - ret->type = itype(si, st, 0); - copyin(st, elem, &ret->data); -} - -// ifaceT2E(sigt *byte, elem any) (ret any); -#pragma textflag 7 -void -sys·ifaceT2E(Sigt *st, ...) -{ - byte *elem; - Eface *ret; - int32 wid; - - elem = (byte*)(&st+1); - wid = st->width; - ret = (Eface*)(elem + rnd(wid, sizeof(uintptr))); - - ret->type = st; - copyin(st, elem, &ret->data); -} - -// ifaceI2T(sigt *byte, iface any) (ret any); -#pragma textflag 7 -void -sys·ifaceI2T(Sigt *st, Iface i, ...) -{ - Itype *im; - byte *ret; - - ret = (byte*)(&i+1); - - im = i.type; - if(im == nil) { - printf("interface is nil, not %s\n", st->name); - throw("interface conversion"); - } - if(im->sigt != st) { - printf("%s is %s, not %s\n", im->sigi->name, im->sigt->name, st->name); - throw("interface conversion"); - } - copyout(st, &i.data, ret); -} - -// ifaceI2T2(sigt *byte, iface any) (ret any, ok bool); -#pragma textflag 7 -void -sys·ifaceI2T2(Sigt *st, Iface i, ...) -{ - byte *ret; - bool *ok; - Itype *im; - int32 wid; - - ret = (byte*)(&i+1); - wid = st->width; - ok = (bool*)(ret+rnd(wid, 1)); - - im = i.type; - if(im == nil || im->sigt != st) { - *ok = false; - sys·memclr(ret, wid); - return; - } - - *ok = true; - copyout(st, &i.data, ret); -} - -// ifaceE2T(sigt *byte, iface any) (ret any); -#pragma textflag 7 -void -sys·ifaceE2T(Sigt *st, Eface e, ...) -{ - Sigt *t; - byte *ret; - - ret = (byte*)(&e+1); - - t = e.type; - if(t == nil) { - printf("interface is nil, not %s\n", st->name); - throw("interface conversion"); - } - if(t != st) { - printf("interface is %s, not %s\n", t->name, st->name); - throw("interface conversion"); - } - copyout(st, &e.data, ret); -} - -// ifaceE2T2(sigt *byte, iface any) (ret any, ok bool); -#pragma textflag 7 -void -sys·ifaceE2T2(Sigt *st, Eface e, ...) -{ - byte *ret; - bool *ok; - Sigt *t; - int32 wid; - - ret = (byte*)(&e+1); - wid = st->width; - ok = (bool*)(ret+rnd(wid, 1)); - - t = e.type; - if(t != st) { - *ok = false; - sys·memclr(ret, wid); - return; - } - - *ok = true; - copyout(st, &e.data, ret); -} - -// ifaceI2E(sigi *byte, iface any) (ret any); -// TODO(rsc): Move to back end, throw away function. -void -sys·ifaceI2E(Iface i, Eface ret) -{ - Itype *im; - - ret.data = i.data; - im = i.type; - if(im == nil) - ret.type = nil; - else - ret.type = im->sigt; - FLUSH(&ret); -} - -// ifaceI2I(sigi *byte, iface any) (ret any); -// called only for implicit (no type assertion) conversions -void -sys·ifaceI2I(Sigi *si, Iface i, Iface ret) -{ - Itype *im; - - im = i.type; - if(im == nil) { - // If incoming interface is uninitialized (zeroed) - // make the outgoing interface zeroed as well. - ret = niliface; - } else { - ret = i; - if(im->sigi != si) - ret.type = itype(si, im->sigt, 0); - } - - FLUSH(&ret); -} - -// ifaceI2Ix(sigi *byte, iface any) (ret any); -// called only for explicit conversions (with type assertion). -void -sys·ifaceI2Ix(Sigi *si, Iface i, Iface ret) -{ - Itype *im; - - im = i.type; - if(im == nil) { - // explicit conversions require non-nil interface value. - printf("interface is nil, not %s\n", si->name); - throw("interface conversion"); - } else { - ret = i; - if(im->sigi != si) - ret.type = itype(si, im->sigt, 0); - } - - FLUSH(&ret); -} - -// ifaceI2I2(sigi *byte, iface any) (ret any, ok bool); -void -sys·ifaceI2I2(Sigi *si, Iface i, Iface ret, bool ok) -{ - Itype *im; - - im = i.type; - if(im == nil) { - // If incoming interface is nil, the conversion fails. - ret = niliface; - ok = false; - } else { - ret = i; - ok = true; - if(im->sigi != si) { - ret.type = itype(si, im->sigt, 1); - if(ret.type == nil) { - ret = niliface; - ok = false; - } - } - } - - FLUSH(&ret); - FLUSH(&ok); -} - -// ifaceE2I(sigi *byte, iface any) (ret any); -// Called only for explicit conversions (with type assertion). -void -sys·ifaceE2I(Sigi *si, Eface e, Iface ret) -{ - Sigt *t; - - t = e.type; - if(t == nil) { - // explicit conversions require non-nil interface value. - printf("interface is nil, not %s\n", si->name); - throw("interface conversion"); - } else { - ret.data = e.data; - ret.type = itype(si, t, 0); - } - FLUSH(&ret); -} - -// ifaceE2I2(sigi *byte, iface any) (ret any, ok bool); -void -sys·ifaceE2I2(Sigi *si, Eface e, Iface ret, bool ok) -{ - Sigt *t; - - t = e.type; - ok = true; - if(t == nil) { - // If incoming interface is nil, the conversion fails. - ret = niliface; - ok = false; - } else { - ret.data = e.data; - ret.type = itype(si, t, 1); - if(ret.type == nil) { - ret = niliface; - ok = false; - } - } - FLUSH(&ret); - FLUSH(&ok); -} - -static uintptr -ifacehash1(void *data, Sigt *sigt) -{ - int32 alg, wid; - - if(sigt == nil) - return 0; - - alg = sigt->alg; - wid = sigt->width; - if(algarray[alg].hash == nohash) { - // calling nohash will throw too, - // but we can print a better error. - printf("hash of unhashable type %s\n", sigt->name); - if(alg == AFAKE) - throw("fake interface hash"); - throw("interface hash"); - } - if(wid <= sizeof(data)) - return algarray[alg].hash(wid, &data); - return algarray[alg].hash(wid, data); -} - -uintptr -ifacehash(Iface a) -{ - if(a.type == nil) - return 0; - return ifacehash1(a.data, a.type->sigt); -} - -uintptr -efacehash(Eface a) -{ - return ifacehash1(a.data, a.type); -} - -static bool -ifaceeq1(void *data1, void *data2, Sigt *sigt) -{ - int32 alg, wid; - - alg = sigt->alg; - wid = sigt->width; - - if(algarray[alg].equal == noequal) { - // calling noequal will throw too, - // but we can print a better error. - printf("comparing uncomparable type %s\n", sigt->name); - if(alg == AFAKE) - throw("fake interface compare"); - throw("interface compare"); - } - - if(wid <= sizeof(data1)) - return algarray[alg].equal(wid, &data1, &data2); - return algarray[alg].equal(wid, data1, data2); -} - -bool -ifaceeq(Iface i1, Iface i2) -{ - if(i1.type != i2.type) - return false; - if(i1.type == nil) - return true; - return ifaceeq1(i1.data, i2.data, i1.type->sigt); -} - -bool -efaceeq(Eface e1, Eface e2) -{ - 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 -sys·ifaceeq(Iface i1, Iface i2, bool ret) -{ - ret = ifaceeq(i1, i2); - FLUSH(&ret); -} - -// efaceeq(i1 any, i2 any) (ret bool) -void -sys·efaceeq(Eface e1, Eface e2, bool ret) -{ - ret = efaceeq(e1, e2); - FLUSH(&ret); -} - -// ifacethash(i1 any) (ret uint32); -void -sys·ifacethash(Iface i1, uint32 ret) -{ - Itype *im; - Sigt *st; - - ret = 0; - im = i1.type; - if(im != nil) { - st = im->sigt; - if(st != nil) - ret = st->thash; - } - FLUSH(&ret); -} - -// efacethash(e1 any) (ret uint32) -void -sys·efacethash(Eface e1, uint32 ret) -{ - Sigt *st; - - ret = 0; - st = e1.type; - if(st != nil) - ret = st->thash; - FLUSH(&ret); -} - -void -sys·printiface(Iface i) -{ - printiface(i); -} - -void -sys·printeface(Eface e) -{ - printeface(e); -} - -void -unsafe·Reflect(Eface i, uint64 retit, String rettype, bool retindir) -{ - int32 wid; - - if(i.type == nil) { - retit = 0; - rettype = emptystring; - retindir = false; - } else { - retit = (uint64)i.data; - rettype = gostring(i.type->name); - wid = i.type->width; - retindir = wid > sizeof(i.data); - } - FLUSH(&retit); - FLUSH(&rettype); - FLUSH(&retindir); -} - -extern Sigt *gotypesigs[]; -extern int32 ngotypesigs; - - -// The reflection library can ask to unreflect on a type -// that has never been used, so we don't have a signature for it. -// For concreteness, suppose a program does -// -// type T struct{ x []int } -// var t T; -// v := reflect.NewValue(v); -// vv := v.Field(0); -// if s, ok := vv.Interface().(string) { -// print("first field is string"); -// } -// -// vv.Interface() returns the result of sys.Unreflect with -// a typestring of "[]int". If []int is not used with interfaces -// in the rest of the program, there will be no signature in gotypesigs -// for "[]int", so we have to invent one. The requirements -// on the fake signature are: -// -// (1) any interface conversion using the signature will fail -// (2) calling unsafe.Reflect() returns the args to unreflect -// (3) the right algorithm type is used, for == and map insertion -// -// (1) is ensured by the fact that we allocate a new Sigt, -// so it will necessarily be != any Sigt in gotypesigs. -// (2) is ensured by storing the type string in the signature -// and setting the width to force the correct value of the bool indir. -// (3) is ensured by sniffing the type string. -// -// Note that (1) is correct behavior: if the program had tested -// for .([]int) instead of .(string) above, then there would be a -// signature with type string "[]int" in gotypesigs, and unreflect -// wouldn't call fakesigt. - -static Sigt* fake[1009]; -static int32 nfake; - -enum -{ - SizeofInt = 4, - SizeofFloat = 4, -}; - -// Table of prefixes of names of comparable types. -static struct { - int8 *s; - int8 n; - int8 alg; - int8 w; -} cmp[] = -{ - // basic types - "int", 3+1, AMEM, SizeofInt, // +1 is NUL - "uint", 4+1, AMEM, SizeofInt, - "int8", 4+1, AMEM, 1, - "uint8", 5+1, AMEM, 1, - "int16", 5+1, AMEM, 2, - "uint16", 6+1, AMEM, 2, - "int32", 5+1, AMEM, 4, - "uint32", 6+1, AMEM, 4, - "int64", 5+1, AMEM, 8, - "uint64", 6+1, AMEM, 8, - "uintptr", 7+1, AMEM, sizeof(uintptr), - "float", 5+1, AMEM, SizeofFloat, - "float32", 7+1, AMEM, 4, - "float64", 7+1, AMEM, 8, - "bool", 4+1, AMEM, sizeof(bool), - - // string compare is special - "string", 6+1, ASTRING, sizeof(String), - - // generic types, identified by prefix - "*", 1, AMEM, sizeof(uintptr), - "chan ", 5, AMEM, sizeof(uintptr), - "func(", 5, AMEM, sizeof(uintptr), - "map[", 4, AMEM, sizeof(uintptr), -}; - -static Sigt* -fakesigt(String type, bool indir) -{ - Sigt *sigt; - uint32 h; - int32 i, locked; - - h = 0; - for(i=0; ilink) { - // don't need to compare indir. - // same type string but different indir will have - // different hashes. - if(mcmp(sigt->name, type.str, type.len) == 0) - if(sigt->name[type.len] == '\0') { - if(locked) - unlock(&ifacelock); - return sigt; - } - } - } - - sigt = malloc(sizeof(*sigt)); - sigt->name = malloc(type.len + 1); - mcpy(sigt->name, type.str, type.len); - - sigt->alg = AFAKE; - sigt->width = 1; // small width - if(indir) - sigt->width = 2*sizeof(niliface.data); // big width - - // AFAKE is like ANOEQ; check whether the type - // should have a more capable algorithm. - for(i=0; iname, (byte*)cmp[i].s, cmp[i].n) == 0) { - sigt->alg = cmp[i].alg; - sigt->width = cmp[i].w; - break; - } - } - - sigt->link = fake[h]; - fake[h] = sigt; - - unlock(&ifacelock); - return sigt; -} - -static int32 -cmpstringchars(String a, uint8 *b) -{ - int32 i; - byte c1, c2; - - for(i=0;; i++) { - c1 = 0; - if(i < a.len) - c1 = a.str[i]; - c2 = b[i]; - if(c1 < c2) - return -1; - if(c1 > c2) - return +1; - if(c1 == 0) - return 0; - } -} - -static Sigt* -findtype(String type, bool indir) -{ - int32 i, lo, hi, m; - - lo = 0; - hi = ngotypesigs; - while(lo < hi) { - m = lo + (hi - lo)/2; - i = cmpstringchars(type, gotypesigs[m]->name); - if(i == 0) - return gotypesigs[m]; - if(i < 0) - hi = m; - else - lo = m+1; - } - return fakesigt(type, indir); -} - - -void -unsafe·Unreflect(uint64 it, String type, bool indir, Eface ret) -{ - Sigt *sigt; - - ret = nileface; - - if(cmpstring(type, emptystring) == 0) - goto out; - - if(type.len > 10 && mcmp(type.str, (byte*)"interface ", 10) == 0) { - printf("unsafe.Unreflect: cannot put %S in interface\n", type); - throw("unsafe.Unreflect"); - } - - // if we think the type should be indirect - // and caller does not, play it safe, return nil. - sigt = findtype(type, indir); - if(indir != (sigt->width > sizeof(ret.data))) - goto out; - - ret.type = sigt; - ret.data = (void*)it; - -out: - FLUSH(&ret); -} - diff --git a/src/lib/runtime/linux/386/defs.h b/src/lib/runtime/linux/386/defs.h deleted file mode 100755 index 112fc7b09..000000000 --- a/src/lib/runtime/linux/386/defs.h +++ /dev/null @@ -1,136 +0,0 @@ -// godefs -f -m32 -f -I/home/rsc/pub/linux-2.6/arch/x86/include -f -I/home/rsc/pub/linux-2.6/include 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, - SA_RESTART = 0x10000000, - SA_ONSTACK = 0x8000000, - SA_RESTORER = 0x4000000, - SA_SIGINFO = 0x4, -}; - -// 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 _anon_[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 { - byte _u[4]; - uint32 sa_mask; - uint32 sa_flags; - void *sa_restorer; -}; - -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; -}; -#pragma pack off diff --git a/src/lib/runtime/linux/386/rt0.s b/src/lib/runtime/linux/386/rt0.s deleted file mode 100755 index 7717c37e8..000000000 --- a/src/lib/runtime/linux/386/rt0.s +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Darwin and Linux use the same linkage to main - -TEXT _rt0_386_linux(SB),7,$0 - JMP _rt0_386(SB) diff --git a/src/lib/runtime/linux/386/signal.c b/src/lib/runtime/linux/386/signal.c deleted file mode 100644 index 7dfca6bb4..000000000 --- a/src/lib/runtime/linux/386/signal.c +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "runtime.h" -#include "defs.h" -#include "signals.h" -#include "os.h" - -void -dumpregs(Sigcontext *r) -{ - printf("eax %X\n", r->eax); - printf("ebx %X\n", r->ebx); - printf("ecx %X\n", r->ecx); - printf("edx %X\n", r->edx); - printf("edi %X\n", r->edi); - printf("esi %X\n", r->esi); - printf("ebp %X\n", r->ebp); - printf("esp %X\n", r->esp); - printf("eip %X\n", r->eip); - printf("eflags %X\n", r->eflags); - printf("cs %X\n", r->cs); - printf("fs %X\n", r->fs); - printf("gs %X\n", r->gs); -} - -/* - * This assembler routine takes the args from registers, puts them on the stack, - * and calls sighandler(). - */ -extern void sigtramp(void); -extern void sigignore(void); // just returns -extern void sigreturn(void); // calls sigreturn - -void -sighandler(int32 sig, Siginfo* info, void* context) -{ - Ucontext *uc; - Sigcontext *sc; - - if(panicking) // traceback already printed - exit(2); - panicking = 1; - - uc = context; - sc = &uc->uc_mcontext; - - if(sig < 0 || sig >= NSIG) - printf("Signal %d\n", sig); - else - printf("%s\n", sigtab[sig].name); - - printf("Faulting address: %p\n", *(void**)info->_sifields); - printf("pc=%X\n", sc->eip); - printf("\n"); - - if(gotraceback()){ - traceback((void*)sc->eip, (void*)sc->esp, m->curg); - tracebackothers(m->curg); - dumpregs(sc); - } - - breakpoint(); - exit(2); -} - -void -signalstack(byte *p, int32 n) -{ - Sigaltstack st; - - st.ss_sp = p; - st.ss_size = n; - st.ss_flags = 0; - sigaltstack(&st, nil); -} - -void -initsig(void) -{ - static Sigaction sa; - - int32 i; - sa.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESTORER; - sa.sa_mask = 0xFFFFFFFFFFFFFFFFULL; - sa.sa_restorer = (void*)sigreturn; - for(i = 0; igsignal - MOVL AX, 0(FS) // g = m->gsignal - JMP sighandler(SB) - -TEXT sigignore(SB),7,$0 - RET - -TEXT sigreturn(SB),7,$0 - MOVL 4(FS), BP // m - MOVL 32(BP), BP // m->curg - MOVL BP, 0(FS) // g = m->curg - MOVL $173, AX // rt_sigreturn - INT $0x80 - INT $3 // not reached - RET - -TEXT sys·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 2(PC) - INT $3 - RET - -// int64 futex(int32 *uaddr, int32 op, int32 val, -// struct timespec *timeout, int32 *uaddr2, int32 val2); -TEXT 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 - -// int64 clone(int32 flags, void *stack, M *m, G *g, void (*fn)(void)); -TEXT clone(SB),7,$0 - MOVL $120, AX // clone - MOVL flags+4(SP), BX - MOVL stack+8(SP), CX - - // Copy m, g, fn off parent stack for use by child. - SUBL $12, CX - MOVL m+12(SP), DX - MOVL DX, 0(CX) - MOVL g+16(SP), DX - MOVL DX, 4(CX) - MOVL fn+20(SP), DX - MOVL DX, 8(CX) - - MOVL $120, AX - INT $0x80 - - // In parent, return. - CMPL AX, $0 - JEQ 2(PC) - RET - - // In child, set up new stack, etc. - MOVL 0(CX), BX // m - MOVL 12(AX), AX // fs (= m->cret) - MOVW AX, FS - MOVL 8(CX), DX // fn - ADDL $12, CX - MOVL CX, SP - - // fn is now on top of stack. - - // initialize m->procid to Linux tid - MOVL $224, AX - INT $0x80 - MOVL AX, 20(BX) - - // call fn - CALL DX - - // It shouldn't return; if it does, exit. - MOVL $111, DI - MOVL $1, AX - INT $0x80 - JMP -3(PC) // keep exiting - -TEXT 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 - -// // fake the per-goroutine and per-mach registers -// LEAL m0(SB), - -// TODO(rsc): move to linux.s -// -// 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 setldt(SB),7,$32 - // set up user_desc - LEAL 16(SP), AX // struct user_desc - MOVL entry+0(FP), BX // entry - MOVL BX, 0(AX) - MOVL address+4(FP), BX // base address - MOVL BX, 4(AX) - MOVL limit+8(FP), BX // limit - MOVL BX, 8(AX) - MOVL $(SEG_32BIT|USEABLE|CONTENTS_DATA), 12(AX) // flag bits - - // call modify_ldt - MOVL $123, 0(SP) // syscall - modify_ldt - MOVL $1, 4(SP) // func = 1 (write) - MOVL AX, 8(SP) // user_desc - MOVL $16, 12(SP) // sizeof(user_desc) - CALL syscall(SB) - RET - diff --git a/src/lib/runtime/linux/amd64/defs.h b/src/lib/runtime/linux/amd64/defs.h deleted file mode 100644 index 43b047523..000000000 --- a/src/lib/runtime/linux/amd64/defs.h +++ /dev/null @@ -1,175 +0,0 @@ -// godefs -f -m64 defs.c - -// MACHINE GENERATED - DO NOT EDIT. - -// Constants -enum { - PROT_NONE = 0, - PROT_READ = 0x1, - PROT_WRITE = 0x2, - PROT_EXEC = 0x4, - MAP_ANON = 0x20, - MAP_PRIVATE = 0x2, - SA_RESTART = 0x10000000, - SA_ONSTACK = 0x8000000, - SA_RESTORER = 0x4000000, - SA_SIGINFO = 0x4, -}; - -// 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 pad0[4]; - byte _sifields[112]; -}; -#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 Sigaltstack Sigaltstack; -struct Sigaltstack { - void *ss_sp; - int32 ss_flags; - byte pad0[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/lib/runtime/linux/amd64/rt0.s b/src/lib/runtime/linux/amd64/rt0.s deleted file mode 100644 index 55be5bcee..000000000 --- a/src/lib/runtime/linux/amd64/rt0.s +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Darwin and Linux use the same linkage to main - -TEXT _rt0_amd64_linux(SB),7,$-8 - MOVQ $_rt0_amd64(SB), AX - JMP AX diff --git a/src/lib/runtime/linux/amd64/signal.c b/src/lib/runtime/linux/amd64/signal.c deleted file mode 100644 index 55215176d..000000000 --- a/src/lib/runtime/linux/amd64/signal.c +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright 2009 The Go Authors. 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 -dumpregs(Sigcontext *r) -{ - printf("rax %X\n", r->rax); - printf("rbx %X\n", r->rbx); - printf("rcx %X\n", r->rcx); - printf("rdx %X\n", r->rdx); - printf("rdi %X\n", r->rdi); - printf("rsi %X\n", r->rsi); - printf("rbp %X\n", r->rbp); - printf("rsp %X\n", r->rsp); - printf("r8 %X\n", r->r8 ); - printf("r9 %X\n", r->r9 ); - printf("r10 %X\n", r->r10); - printf("r11 %X\n", r->r11); - printf("r12 %X\n", r->r12); - printf("r13 %X\n", r->r13); - printf("r14 %X\n", r->r14); - printf("r15 %X\n", r->r15); - printf("rip %X\n", r->rip); - printf("rflags %X\n", r->eflags); - printf("cs %X\n", (uint64)r->cs); - printf("fs %X\n", (uint64)r->fs); - printf("gs %X\n", (uint64)r->gs); -} - -/* - * This assembler routine takes the args from registers, puts them on the stack, - * and calls sighandler(). - */ -extern void sigtramp(void); -extern void sigignore(void); // just returns -extern void sigreturn(void); // calls sigreturn - -void -sighandler(int32 sig, Siginfo* info, void* context) -{ - Ucontext *uc; - Mcontext *mc; - Sigcontext *sc; - - if(panicking) // traceback already printed - exit(2); - panicking = 1; - - uc = context; - mc = &uc->uc_mcontext; - sc = (Sigcontext*)mc; // same layout, more conveient names - - if(sig < 0 || sig >= NSIG) - printf("Signal %d\n", sig); - else - printf("%s\n", sigtab[sig].name); - - printf("Faulting address: %p\n", *(void**)info->_sifields); - printf("PC=%X\n", sc->rip); - printf("\n"); - - if(gotraceback()){ - traceback((void*)sc->rip, (void*)sc->rsp, (void*)sc->r15); - tracebackothers((void*)sc->r15); - dumpregs(sc); - } - - breakpoint(); - exit(2); -} - -void -signalstack(byte *p, int32 n) -{ - Sigaltstack st; - - st.ss_sp = p; - st.ss_size = n; - st.ss_flags = 0; - sigaltstack(&st, nil); -} - -void -initsig(void) -{ - static Sigaction sa; - - int32 i; - sa.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESTORER; - sa.sa_mask = 0xFFFFFFFFFFFFFFFFULL; - sa.sa_restorer = (void*)sigreturn; - for(i = 0; igsignal - MOVQ DI,0(SP) - MOVQ SI,8(SP) - MOVQ DX,16(SP) - CALL sighandler(SB) - RET - -TEXT sigignore(SB),7,$0 - RET - -TEXT sigreturn(SB),7,$0 - MOVL $15, AX // rt_sigreturn - SYSCALL - INT $3 // not reached - -TEXT sys·mmap(SB),7,$0-32 - MOVQ 8(SP), DI - MOVQ $0, SI - MOVL 16(SP), SI - MOVL 20(SP), DX - MOVL 24(SP), R10 - MOVL 28(SP), R8 - MOVL 32(SP), R9 - - MOVL $9, AX // syscall entry - SYSCALL - CMPQ AX, $0xfffffffffffff001 - JLS 2(PC) - CALL notok(SB) - RET - -TEXT notok(SB),7,$0 - MOVQ $0xf1, BP - MOVQ BP, (BP) - RET - -TEXT sys·memclr(SB),7,$0-16 - MOVQ 8(SP), DI // arg 1 addr - MOVL 16(SP), CX // arg 2 count (cannot be zero) - ADDL $7, CX - SHRL $3, CX - MOVQ $0, AX - CLD - REP - STOSQ - RET - -TEXT sys·getcallerpc+0(SB),7,$0 - MOVQ x+0(FP),AX // addr of first arg - MOVQ -8(AX),AX // get calling pc - RET - -TEXT sys·setcallerpc+0(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 - -// int64 futex(int32 *uaddr, int32 op, int32 val, -// struct timespec *timeout, int32 *uaddr2, int32 val2); -TEXT 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 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 m+24(SP), R8 - MOVQ g+32(SP), R9 - MOVQ fn+40(SP), R12 - - MOVL $56, AX - SYSCALL - - // In parent, return. - CMPQ AX, $0 - JEQ 2(PC) - RET - - // In child, set up new stack - MOVQ SI, SP - MOVQ R8, R14 // m - MOVQ R9, R15 // g - - // Initialize m->procid to Linux tid - MOVL $186, AX // gettid - SYSCALL - MOVQ AX, 24(R14) - - // Call fn - CALL R12 - - // It shouldn't return. If it does, exi - MOVL $111, DI - MOVL $60, AX - SYSCALL - JMP -3(PC) // keep exiting - -TEXT sigaltstack(SB),7,$-8 - MOVQ new+8(SP), DI - MOVQ old+16(SP), SI - MOVQ $131, AX - SYSCALL - CMPQ AX, $0xfffffffffffff001 - JLS 2(PC) - CALL notok(SB) - RET diff --git a/src/lib/runtime/linux/arm/defs.h b/src/lib/runtime/linux/arm/defs.h deleted file mode 100644 index caad66989..000000000 --- a/src/lib/runtime/linux/arm/defs.h +++ /dev/null @@ -1,27 +0,0 @@ -// godefs -carm-gcc -f -I/usr/local/google/src/linux-2.6.28/arch/arm/include -f -I/usr/local/google/src/linux-2.6.28/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, - SA_RESTART = 0x10000000, - SA_ONSTACK = 0x8000000, - SA_RESTORER = 0x4000000, - SA_SIGINFO = 0x4, -}; - -// Types -#pragma pack on - -typedef struct Timespec Timespec; -struct Timespec { - int32 tv_sec; - int32 tv_nsec; -}; -#pragma pack off diff --git a/src/lib/runtime/linux/arm/rt0.s b/src/lib/runtime/linux/arm/rt0.s deleted file mode 100644 index 024547ddd..000000000 --- a/src/lib/runtime/linux/arm/rt0.s +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright 2009 The Go 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/lib/runtime/linux/arm/signal.c b/src/lib/runtime/linux/arm/signal.c deleted file mode 100644 index 024018d5a..000000000 --- a/src/lib/runtime/linux/arm/signal.c +++ /dev/null @@ -1,4 +0,0 @@ -// Copyright 2009 The Go 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/lib/runtime/linux/arm/sys.s b/src/lib/runtime/linux/arm/sys.s deleted file mode 100644 index f5db32305..000000000 --- a/src/lib/runtime/linux/arm/sys.s +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// -// System calls and other sys.stuff for arm, Linux -// - -TEXT write(SB),7,$0 - MOVW 4(SP), R0 - MOVW 8(SP), R1 - MOVW 12(SP), R2 - SWI $0x00900004 // syscall write - RET - diff --git a/src/lib/runtime/linux/defs.c b/src/lib/runtime/linux/defs.c deleted file mode 100644 index 35fa02953..000000000 --- a/src/lib/runtime/linux/defs.c +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2009 The Go 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 -#include -#include - -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, - - $SA_RESTART = SA_RESTART, - $SA_ONSTACK = SA_ONSTACK, - $SA_RESTORER = SA_RESTORER, - $SA_SIGINFO = SA_SIGINFO, -}; - -typedef struct timespec $Timespec; -typedef struct timeval $Timeval; -typedef struct sigaction $Sigaction; -typedef siginfo_t $Siginfo; diff --git a/src/lib/runtime/linux/defs1.c b/src/lib/runtime/linux/defs1.c deleted file mode 100644 index 0fe3506ad..000000000 --- a/src/lib/runtime/linux/defs1.c +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* - * Input to godefs - godefs -f -m64 defs.c >amd64/defs.h - godefs -f -m64 defs1.c >>amd64/defs.h - */ - -#include - -typedef __sigset_t $Usigset; -typedef struct _libc_fpxreg $Fpxreg; -typedef struct _libc_xmmreg $Xmmreg; -typedef struct _libc_fpstate $Fpstate; -typedef struct _libc_fpreg $Fpreg; -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/lib/runtime/linux/defs2.c b/src/lib/runtime/linux/defs2.c deleted file mode 100644 index aa0331a37..000000000 --- a/src/lib/runtime/linux/defs2.c +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* - * 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 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 -#include -#include -#include - -/* -#include -#include -#include -*/ - -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, - - $SA_RESTART = SA_RESTART, - $SA_ONSTACK = SA_ONSTACK, - $SA_RESTORER = SA_RESTORER, - $SA_SIGINFO = SA_SIGINFO, -}; - -typedef struct _fpreg $Fpreg; -typedef struct _fpxreg $Fpxreg; -typedef struct _xmmreg $Xmmreg; -typedef struct _fpstate $Fpstate; -typedef struct timespec $Timespec; -typedef struct timeval $Timeval; -typedef struct sigaction $Sigaction; -typedef siginfo_t $Siginfo; -typedef struct sigaltstack $Sigaltstack; -typedef struct sigcontext $Sigcontext; -typedef struct ucontext $Ucontext; - diff --git a/src/lib/runtime/linux/defs_arm.c b/src/lib/runtime/linux/defs_arm.c deleted file mode 100644 index eaec05154..000000000 --- a/src/lib/runtime/linux/defs_arm.c +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* - * Input to godefs - godefs -carm-gcc -f -I/usr/local/google/src/linux-2.6.28/arch/arm/include -f - -I/usr/local/google/src/linux-2.6.28/include defs_arm.c >arm/defs.h - - * Another input file for ARM defs.h - */ - -#include -#include -#include -#include - -/* -#include -#include -#include -*/ - -#include - -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, - - $SA_RESTART = SA_RESTART, - $SA_ONSTACK = SA_ONSTACK, - $SA_RESTORER = SA_RESTORER, - $SA_SIGINFO = SA_SIGINFO -}; - - - - -//typedef struct _fpreg $Fpreg; -//typedef struct _fpxreg $Fpxreg; -//typedef struct _xmmreg $Xmmreg; -//typedef struct _fpstate $Fpstate; -typedef struct timespec $Timespec; -//typedef struct timeval $Timeval; -// typedef struct sigaction $Sigaction; -// typedef siginfo_t $Siginfo; -// typedef struct sigaltstack $Sigaltstack; -// typedef struct sigcontext $Sigcontext; -// typedef struct ucontext $Ucontext; diff --git a/src/lib/runtime/linux/os.h b/src/lib/runtime/linux/os.h deleted file mode 100644 index c61619367..000000000 --- a/src/lib/runtime/linux/os.h +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Linux-specific system calls -int64 futex(uint32*, int32, uint32, Timespec*, uint32*, uint32); -int64 clone(int32, void*, M*, G*, void(*)(void)); - -struct Sigaction; -void rt_sigaction(int64, struct Sigaction*, void*, uint64); diff --git a/src/lib/runtime/linux/signals.h b/src/lib/runtime/linux/signals.h deleted file mode 100644 index 1fb49c513..000000000 --- a/src/lib/runtime/linux/signals.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - - -#define C SigCatch -#define I SigIgnore -#define R SigRestart - -static SigTab sigtab[] = { - /* 0 */ 0, "SIGNONE: no trap", - /* 1 */ 0, "SIGHUP: terminal line hangup", - /* 2 */ 0, "SIGINT: interrupt", - /* 3 */ C, "SIGQUIT: quit", - /* 4 */ C, "SIGILL: illegal instruction", - /* 5 */ C, "SIGTRAP: trace trap", - /* 6 */ C, "SIGABRT: abort", - /* 7 */ C, "SIGBUS: bus error", - /* 8 */ C, "SIGFPE: floating-point exception", - /* 9 */ 0, "SIGKILL: kill", - /* 10 */ 0, "SIGUSR1: user-defined signal 1", - /* 11 */ C, "SIGSEGV: segmentation violation", - /* 12 */ 0, "SIGUSR2: user-defined signal 2", - /* 13 */ I, "SIGPIPE: write to broken pipe", - /* 14 */ 0, "SIGALRM: alarm clock", - /* 15 */ 0, "SIGTERM: termination", - /* 16 */ 0, "SIGSTKFLT: stack fault", - /* 17 */ I+R, "SIGCHLD: child status has changed", - /* 18 */ 0, "SIGCONT: continue", - /* 19 */ 0, "SIGSTOP: stop, unblockable", - /* 20 */ 0, "SIGTSTP: keyboard stop", - /* 21 */ 0, "SIGTTIN: background read from tty", - /* 22 */ 0, "SIGTTOU: background write to tty", - /* 23 */ 0, "SIGURG: urgent condition on socket", - /* 24 */ 0, "SIGXCPU: cpu limit exceeded", - /* 25 */ 0, "SIGXFSZ: file size limit exceeded", - /* 26 */ 0, "SIGVTALRM: virtual alarm clock", - /* 27 */ 0, "SIGPROF: profiling alarm clock", - /* 28 */ I+R, "SIGWINCH: window size change", - /* 29 */ 0, "SIGIO: i/o now possible", - /* 30 */ 0, "SIGPWR: power failure restart", - /* 31 */ C, "SIGSYS: bad system call", -}; -#undef C -#undef I -#undef R - -#define NSIG 32 diff --git a/src/lib/runtime/linux/thread.c b/src/lib/runtime/linux/thread.c deleted file mode 100644 index cc9ba161b..000000000 --- a/src/lib/runtime/linux/thread.c +++ /dev/null @@ -1,282 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "runtime.h" -#include "defs.h" -#include "signals.h" -#include "os.h" - -// 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 one thread sleeping on addr. -// Futexsleep is allowed to wake up spuriously. - -enum -{ - 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) -{ - int64 ret; - - ret = futex(addr, FUTEX_WAIT, val, &longtime, nil, 0); - if(ret >= 0 || ret == -EAGAIN || ret == -EINTR) - return; - - prints("futexsleep addr="); - sys·printpointer(addr); - prints(" val="); - sys·printint(val); - prints(" returned "); - sys·printint(ret); - prints("\n"); - *(int32*)0x1005 = 0x1005; -} - -// If any procs are sleeping on addr, wake up at least one. -static void -futexwakeup(uint32 *addr) -{ - int64 ret; - - ret = futex(addr, FUTEX_WAKE, 1, 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. - - prints("futexwakeup addr="); - sys·printpointer(addr); - prints(" returned "); - sys·printint(ret); - prints("\n"); - *(int32*)0x1006 = 0x1006; -} - - -// Lock and unlock. -// -// The lock state is a single 32-bit word that holds -// a 31-bit count of threads waiting for the lock -// and a single bit (the low bit) saying whether the lock is held. -// The uncontended case runs entirely in user space. -// When contention is detected, we defer to the kernel (futex). -// -// A reminder: compare-and-swap cas(addr, old, new) does -// if(*addr == old) { *addr = new; return 1; } -// else return 0; -// but atomically. - -static void -futexlock(Lock *l) -{ - uint32 v; - -again: - v = l->key; - if((v&1) == 0){ - if(cas(&l->key, v, v|1)){ - // Lock wasn't held; we grabbed it. - return; - } - goto again; - } - - // Lock was held; try to add ourselves to the waiter count. - if(!cas(&l->key, v, v+2)) - goto again; - - // We're accounted for, now sleep in the kernel. - // - // We avoid the obvious lock/unlock race because - // the kernel won't put us to sleep if l->key has - // changed underfoot and is no longer v+2. - // - // We only really care that (v&1) == 1 (the lock is held), - // and in fact there is a futex variant that could - // accomodate that check, but let's not get carried away.) - futexsleep(&l->key, v+2); - - // We're awake: remove ourselves from the count. - for(;;){ - v = l->key; - if(v < 2) - throw("bad lock key"); - if(cas(&l->key, v, v-2)) - break; - } - - // Try for the lock again. - goto again; -} - -static void -futexunlock(Lock *l) -{ - uint32 v; - - // Atomically get value and clear lock bit. -again: - v = l->key; - if((v&1) == 0) - throw("unlock of unlocked lock"); - if(!cas(&l->key, v, v&~1)) - goto again; - - // If there were waiters, wake one. - if(v & ~1) - futexwakeup(&l->key); -} - -void -lock(Lock *l) -{ - if(m->locks < 0) - throw("lock count"); - m->locks++; - futexlock(l); -} - -void -unlock(Lock *l) -{ - m->locks--; - if(m->locks < 0) - throw("lock count"); - futexunlock(l); -} - - -// One-time notifications. -// -// Since the lock/unlock implementation already -// takes care of sleeping in the kernel, we just reuse it. -// (But it's a weird use, so it gets its own interface.) -// -// We use a lock to represent the event: -// unlocked == event has happened. -// Thus the lock starts out locked, and to wait for the -// event you try to lock the lock. To signal the event, -// you unlock the lock. - -void -noteclear(Note *n) -{ - n->lock.key = 0; // memset(n, 0, sizeof *n) - futexlock(&n->lock); -} - -void -notewakeup(Note *n) -{ - futexunlock(&n->lock); -} - -void -notesleep(Note *n) -{ - futexlock(&n->lock); - futexunlock(&n->lock); // Let other sleepers find out too. -} - - -// 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 -newosproc(M *m, G *g, void *stk, void (*fn)(void)) -{ - int64 ret; - int32 flags; - - /* - * note: strace gets confused if we use CLONE_PTRACE here. - */ - flags = CLONE_PARENT /* getppid doesn't change in child */ - | 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 */ - ; - - if(0){ - prints("newosproc stk="); - sys·printpointer(stk); - prints(" m="); - sys·printpointer(m); - prints(" g="); - sys·printpointer(g); - prints(" fn="); - sys·printpointer(fn); - prints(" clone="); - sys·printpointer(clone); - prints("\n"); - } - - ret = clone(flags, stk, m, g, fn); - if(ret < 0) - *(int32*)123 = 123; -} - -void -osinit(void) -{ -} - -// Called to initialize a new m (including the bootstrap m). -void -minit(void) -{ - // Initialize signal handling. - m->gsignal = malg(32*1024); // OS X wants >=8K, Linux >=2K - signalstack(m->gsignal->stackguard, 32*1024); -} diff --git a/src/lib/runtime/malloc.c b/src/lib/runtime/malloc.c deleted file mode 100644 index 81cdfb300..000000000 --- a/src/lib/runtime/malloc.c +++ /dev/null @@ -1,308 +0,0 @@ -// Copyright 2009 The Go 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. -// TODO(rsc): solve "stack overflow during malloc" problem. - -#include "runtime.h" -#include "malloc.h" -#include "defs.h" - -MHeap mheap; -MStats mstats; - -// 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* -malloc(uintptr size) -{ - int32 sizeclass; - MCache *c; - uintptr npages; - MSpan *s; - void *v; - uint32 *ref; - - if(m->mallocing) - throw("malloc/free - deadlock"); - m->mallocing = 1; - - if(size == 0) - size = 1; - - if(size <= MaxSmallSize) { - // Allocate from mcache free lists. - sizeclass = SizeToClass(size); - size = class_to_size[sizeclass]; - c = m->mcache; - v = MCache_Alloc(c, sizeclass, size); - if(v == nil) - throw("out of memory"); - mstats.alloc += size; - } else { - // TODO(rsc): Report tracebacks for very large allocations. - - // Allocate directly from heap. - npages = size >> PageShift; - if((size & PageMask) != 0) - npages++; - s = MHeap_Alloc(&mheap, npages, 0); - if(s == nil) - throw("out of memory"); - mstats.alloc += npages<start << PageShift); - } - - // setup for mark sweep - if(!mlookup(v, nil, nil, &ref)) { - printf("malloc %D; mlookup failed\n", (uint64)size); - throw("malloc mlookup"); - } - *ref = RefNone; - - m->mallocing = 0; - return v; -} - -void* -mallocgc(uintptr size) -{ - void *v; - - v = malloc(size); - if(mstats.inuse_pages > mstats.next_gc) - gc(0); - return v; -} - -// Free the object whose base pointer is v. -void -free(void *v) -{ - int32 sizeclass, size; - uintptr page, tmp; - MSpan *s; - MCache *c; - uint32 *ref; - - if(v == nil) - return; - - if(m->mallocing) - throw("malloc/free - deadlock"); - m->mallocing = 1; - - if(!mlookup(v, nil, nil, &ref)) - throw("free mlookup"); - *ref = RefFree; - - // Find size class for v. - page = (uintptr)v >> PageShift; - sizeclass = MHeapMapCache_GET(&mheap.mapcache, page, tmp); - if(sizeclass == 0) { - // Missed in cache. - s = MHeap_Lookup(&mheap, page); - if(s == nil) - throw("free - invalid pointer"); - sizeclass = s->sizeclass; - if(sizeclass == 0) { - // Large object. - mstats.alloc -= s->npages<npages<mcache; - size = class_to_size[sizeclass]; - sys_memclr(v, size); - mstats.alloc -= size; - MCache_Free(c, v, sizeclass, size); - -out: - m->mallocing = 0; -} - -int32 -mlookup(void *v, byte **base, uintptr *size, uint32 **ref) -{ - uintptr n, nobj, i; - byte *p; - MSpan *s; - - s = MHeap_LookupMaybe(&mheap, (uintptr)v>>PageShift); - if(s == nil) { - if(base) - *base = nil; - if(size) - *size = 0; - if(ref) - *ref = 0; - return 0; - } - - p = (byte*)((uintptr)s->start<sizeclass == 0) { - // Large object. - if(base) - *base = p; - if(size) - *size = s->npages<gcref0; - return 1; - } - - if((byte*)v >= (byte*)s->gcref) { - // pointers into the gc ref counts - // do not count as pointers. - return 0; - } - - n = class_to_size[s->sizeclass]; - i = ((byte*)v - p)/n; - if(base) - *base = p + i*n; - if(size) - *size = n; - nobj = (s->npages << PageShift) / (n + RefcountOverhead); - if((byte*)s->gcref < p || (byte*)(s->gcref+nobj) > p+(s->npages<state, s, p, s->sizeclass, (uint64)nobj, (uint64)n, (uint64)s->npages); - printf("s->base sizeclass %d v=%p base=%p gcref=%p blocksize=%D nobj=%D size=%D end=%p end=%p\n", - s->sizeclass, v, p, s->gcref, (uint64)s->npages<gcref + nobj, p+(s->npages<gcref[i]; - - return 1; -} - -MCache* -allocmcache(void) -{ - return FixAlloc_Alloc(&mheap.cachealloc); -} - -void -mallocinit(void) -{ - InitSizes(); - MHeap_Init(&mheap, SysAlloc); - m->mcache = allocmcache(); - - // See if it works. - free(malloc(1)); -} - -void* -SysAlloc(uintptr n) -{ - mstats.sys += n; - return sys_mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0); -} - -void -SysUnused(void *v, uintptr n) -{ - USED(v); - USED(n); - // TODO(rsc): call madvise MADV_DONTNEED -} - -void -SysFree(void *v, uintptr n) -{ - USED(v); - USED(n); - // TODO(rsc): call munmap -} - -// Runtime stubs. - -extern void *oldmal(uint32); - -void* -mal(uint32 n) -{ -//return oldmal(n); - void *v; - - v = mallocgc(n); - - if(0) { - byte *p; - uint32 i; - p = v; - for(i=0; i %p: byte %d is non-zero\n", n, v, i); - throw("mal"); - } - } - } - -//printf("mal %d %p\n", n, v); // |checkmal to check for overlapping returns. - return v; -} - -// 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). -struct { - Lock; - FixAlloc; -} stacks; - -void* -stackalloc(uint32 n) -{ - void *v; - uint32 *ref; - -//return oldmal(n); - if(m->mallocing) { - lock(&stacks); - if(stacks.size == 0) - FixAlloc_Init(&stacks, n, SysAlloc, nil, nil); - if(stacks.size != n) { - printf("stackalloc: in malloc, size=%D want %d", (uint64)stacks.size, n); - throw("stackalloc"); - } - v = FixAlloc_Alloc(&stacks); - unlock(&stacks); - return v; - } - v = malloc(n); - if(!mlookup(v, nil, nil, &ref)) - throw("stackalloc mlookup"); - *ref = RefStack; - return v; -} - -void -stackfree(void *v) -{ -//return; - - if(m->mallocing) { - lock(&stacks); - FixAlloc_Free(&stacks, v); - unlock(&stacks); - return; - } - free(v); -} diff --git a/src/lib/runtime/malloc.h b/src/lib/runtime/malloc.h deleted file mode 100644 index 9b3d6b811..000000000 --- a/src/lib/runtime/malloc.h +++ /dev/null @@ -1,308 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Memory allocator, based on tcmalloc. -// http://goog-perftools.sourceforge.net/doc/tcmalloc.html - -// The main allocator works in runs of pages. -// Small allocation sizes (up to and including 32 kB) are -// rounded to one of about 100 size classes, each of which -// has its own free list of objects of exactly that size. -// Any free page of memory can be split into a set of objects -// of one size class, which are then managed using free list -// allocators. -// -// The allocator's data structures are: -// -// FixAlloc: a free-list allocator for fixed-size objects, -// used to manage storage used by the allocator. -// MHeap: the malloc heap, managed at page (4096-byte) granularity. -// MSpan: a run of pages managed by the MHeap. -// MHeapMap: a mapping from page IDs to MSpans. -// MHeapMapCache: a small cache of MHeapMap mapping page IDs -// to size classes for pages used for small objects. -// 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. -// -// This C code was written with an eye toward translating to Go -// in the future. Methods have the form Type_Method(Type *t, ...). - - -typedef struct FixAlloc FixAlloc; -typedef struct MCentral MCentral; -typedef struct MHeap MHeap; -typedef struct MHeapMap MHeapMap; -typedef struct MHeapMapCache MHeapMapCache; -typedef struct MSpan MSpan; -typedef struct MStats MStats; -typedef struct MLink MLink; - -enum -{ - PageShift = 12, - PageSize = 1<> PageShift - -enum -{ - // Tunable constants. - NumSizeClasses = 67, // Number of size classes (must match msize.c) - MaxSmallSize = 32<<10, - - FixAllocChunk = 128<<10, // Chunk size for FixAlloc - MaxMCacheListLen = 256, // Maximum objects on MCacheList - MaxMCacheSize = 2<<20, // Maximum bytes in one MCache - MaxMHeapList = 1<<(20 - PageShift), // Maximum page length for fixed-size list in MHeap. - HeapAllocChunk = 1<<20, // Chunk size for heap growth -}; - -#ifdef _64BIT -#include "mheapmap64.h" -#else -#include "mheapmap32.h" -#endif - -// A generic linked list of blocks. (Typically the block is bigger than sizeof(MLink).) -struct MLink -{ - MLink *next; -}; - -// SysAlloc obtains a large chunk of memory from the operating system, -// typically on the order of a hundred kilobytes or a megabyte. -// -// SysUnused notifies the operating system that the contents -// of the memory region are no longer needed and can be reused -// for other purposes. The program reserves the right to start -// accessing those pages in the future. -// -// SysFree returns it unconditionally; this is only used if -// an out-of-memory error has been detected midway through -// an allocation. It is okay if SysFree is a no-op. - -void* SysAlloc(uintptr nbytes); -void SysFree(void *v, uintptr nbytes); -void SysUnused(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; -}; - -void FixAlloc_Init(FixAlloc *f, uintptr size, void *(*alloc)(uintptr), void (*first)(void*, byte*), void *arg); -void* FixAlloc_Alloc(FixAlloc *f); -void FixAlloc_Free(FixAlloc *f, void *p); - - -// Statistics. -// Shared with Go: if you edit this structure, also edit ../lib/malloc.go. -struct MStats -{ - uint64 alloc; - uint64 sys; - uint64 stacks; - uint64 inuse_pages; // protected by mheap.Lock - uint64 next_gc; // protected by mheap.Lock - bool enablegc; -}; -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 SizeToClass(int32); -extern int32 class_to_size[NumSizeClasses]; -extern int32 class_to_allocnpages[NumSizeClasses]; -extern int32 class_to_transfercount[NumSizeClasses]; -extern void 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; -}; - -void* MCache_Alloc(MCache *c, int32 sizeclass, uintptr size); -void MCache_Free(MCache *c, void *p, int32 sizeclass, uintptr size); - - -// An MSpan is a run of pages. -enum -{ - MSpanInUse = 0, - MSpanFree, - MSpanListHead, - MSpanDead, -}; -struct MSpan -{ - MSpan *next; // in a span linked list - MSpan *prev; // in a span linked list - MSpan *allnext; // in the list of all spans - PageID start; // starting page number - uintptr npages; // number of pages in span - MLink *freelist; // list of free objects - uint32 ref; // number of allocated objects in this span - uint32 sizeclass; // size class - uint32 state; // MSpanInUse etc - union { - uint32 *gcref; // sizeclass > 0 - uint32 gcref0; // sizeclass == 0 - }; -}; - -void MSpan_Init(MSpan *span, PageID start, uintptr npages); - -// Every MSpan is in one doubly-linked list, -// either one of the MHeap's free lists or one of the -// MCentral's span lists. We use empty MSpan structures as list heads. -void MSpanList_Init(MSpan *list); -bool MSpanList_IsEmpty(MSpan *list); -void MSpanList_Insert(MSpan *list, MSpan *span); -void MSpanList_Remove(MSpan *span); // from whatever list it is in - - -// Central list of free objects of a given size. -struct MCentral -{ - Lock; - int32 sizeclass; - MSpan nonempty; - MSpan empty; - int32 nfree; -}; - -void MCentral_Init(MCentral *c, int32 sizeclass); -int32 MCentral_AllocList(MCentral *c, int32 n, MLink **first); -void MCentral_FreeList(MCentral *c, int32 n, MLink *first); - -// Main malloc heap. -// The heap itself is the "free[]" and "large" arrays, -// but all the other global data is here too. -struct MHeap -{ - Lock; - MSpan free[MaxMHeapList]; // free lists of given length - MSpan large; // free lists length >= MaxMHeapList - MSpan *allspans; - - // span lookup - MHeapMap map; - MHeapMapCache mapcache; - - // 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 mheap; - -void MHeap_Init(MHeap *h, void *(*allocator)(uintptr)); -MSpan* MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass); -void MHeap_Free(MHeap *h, MSpan *s); -MSpan* MHeap_Lookup(MHeap *h, PageID p); -MSpan* MHeap_LookupMaybe(MHeap *h, PageID p); - -int32 mlookup(void *v, byte **base, uintptr *size, uint32 **ref); -void gc(int32 force); - -enum -{ - RefcountOverhead = 4, // one uint32 per object - - RefFree = 0, // must be zero - RefManual, // manual allocation - don't free - RefStack, // stack segment - don't free and don't scan for pointers - RefNone, // no references - RefSome, // some references -}; - diff --git a/src/lib/runtime/malloc_go.cgo b/src/lib/runtime/malloc_go.cgo deleted file mode 100644 index 6dcdaece2..000000000 --- a/src/lib/runtime/malloc_go.cgo +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package malloc -#include "runtime.h" -#include "malloc.h" - -func Alloc(n uintptr) (p *byte) { - p = malloc(n); -} - -func Free(p *byte) { - free(p); -} - -func Lookup(p *byte) (base *byte, size uintptr) { - mlookup(p, &base, &size, nil); -} - -func GetStats() (s *MStats) { - s = &mstats; -} - -func GC() { - gc(1); -} - diff --git a/src/lib/runtime/mcache.c b/src/lib/runtime/mcache.c deleted file mode 100644 index ae2594023..000000000 --- a/src/lib/runtime/mcache.c +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Per-thread (in Go, per-M) malloc cache for small objects. -// -// See malloc.h for an overview. - -#include "runtime.h" -#include "malloc.h" - -void* -MCache_Alloc(MCache *c, int32 sizeclass, uintptr size) -{ - MCacheList *l; - MLink *first, *v; - int32 n; - - // Allocate from list. - l = &c->list[sizeclass]; - if(l->list == nil) { - // Replenish using central lists. - n = MCentral_AllocList(&mheap.central[sizeclass], - class_to_transfercount[sizeclass], &first); - l->list = first; - l->nlist = n; - c->size += n*size; - } - v = l->list; - l->list = v->next; - l->nlist--; - if(l->nlist < l->nlistmin) - l->nlistmin = l->nlist; - c->size -= size; - - // v is zeroed except for the link pointer - // that we used above; zero that. - v->next = nil; - 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; inext; - l->list = *lp; - *lp = nil; - l->nlist -= n; - if(l->nlist < l->nlistmin) - l->nlistmin = l->nlist; - c->size -= n*class_to_size[sizeclass]; - - // Return them to central free list. - MCentral_FreeList(&mheap.central[sizeclass], n, first); -} - -void -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; - - if(l->nlist >= MaxMCacheListLen) { - // Release a chunk back. - ReleaseN(c, l, class_to_transfercount[sizeclass], sizeclass); - } - - if(c->size >= MaxMCacheSize) { - // Scavenge. - for(i=0; ilist[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; - } - } -} - diff --git a/src/lib/runtime/mcentral.c b/src/lib/runtime/mcentral.c deleted file mode 100644 index 5c9f720c0..000000000 --- a/src/lib/runtime/mcentral.c +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// 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 -MCentral_Init(MCentral *c, int32 sizeclass) -{ - c->sizeclass = sizeclass; - MSpanList_Init(&c->nonempty); - 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 -MCentral_AllocList(MCentral *c, int32 n, MLink **pfirst) -{ - MLink *first, *last, *v; - int32 i; - - - lock(c); - // Replenish central list if empty. - if(MSpanList_IsEmpty(&c->nonempty)) { - if(!MCentral_Grow(c)) { - 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; inext = v; - last = v; - } - last->next = nil; - c->nfree -= i; - - 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(MSpanList_IsEmpty(&c->nonempty)) - return nil; - s = c->nonempty.next; - s->ref++; - v = s->freelist; - s->freelist = v->next; - if(s->freelist == nil) { - MSpanList_Remove(s); - MSpanList_Insert(&c->empty, s); - } - 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 -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); - - lock(c); - for(v=start; v; v=next) { - next = v->next; - MCentral_Free(c, v); - } - unlock(c); -} - -// Helper: free one object back into the central free list. -static void -MCentral_Free(MCentral *c, void *v) -{ - MSpan *s; - PageID page; - MLink *p, *next; - - // Find span for v. - page = (uintptr)v >> PageShift; - s = MHeap_Lookup(&mheap, page); - if(s == nil || s->ref == 0) - throw("invalid free"); - - // Move to nonempty if necessary. - if(s->freelist == nil) { - MSpanList_Remove(s); - 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) { - MSpanList_Remove(s); - // Freed blocks are zeroed except for the link pointer. - // Zero the link pointers so that the page is all zero. - for(p=s->freelist; p; p=next) { - next = p->next; - p->next = nil; - } - s->freelist = nil; - c->nfree -= (s->npages << PageShift) / class_to_size[c->sizeclass]; - unlock(c); - MHeap_Free(&mheap, s); - lock(c); - } -} - -// Fetch a new span from the heap and -// carve into objects for the free list. -static bool -MCentral_Grow(MCentral *c) -{ - int32 i, n, npages, size; - MLink **tailp, *v; - byte *p; - MSpan *s; - - unlock(c); - npages = class_to_allocnpages[c->sizeclass]; - s = MHeap_Alloc(&mheap, npages, c->sizeclass); - if(s == nil) { - // TODO(rsc): Log out of memory - lock(c); - return false; - } - - // Carve span into sequence of blocks. - tailp = &s->freelist; - p = (byte*)(s->start << PageShift); - size = class_to_size[c->sizeclass]; - n = (npages << PageShift) / (size + RefcountOverhead); - s->gcref = (uint32*)(p + size*n); - for(i=0; inext; - p += size; - } - *tailp = nil; - - lock(c); - c->nfree += n; - MSpanList_Insert(&c->nonempty, s); - return true; -} diff --git a/src/lib/runtime/mem.c b/src/lib/runtime/mem.c deleted file mode 100644 index 7ed299eb0..000000000 --- a/src/lib/runtime/mem.c +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "runtime.h" -#include "defs.h" - -// Stubs for memory management. -// In a separate file so they can be overridden during testing of gc. - -enum -{ - NHUNK = 20<<20, -}; - -// Convenient wrapper around mmap. -static void* -brk(uint32 n) -{ - byte *v; - - v = sys_mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, 0, 0); - m->mem.nmmap += n; - return v; -} - -// Allocate n bytes of memory. Note that this gets used -// to allocate new stack segments, so at each call to a function -// you have to ask yourself "would it be okay to call mal recursively -// right here?" The answer is yes unless we're in the middle of -// editing the malloc state in m->mem. -void* -oldmal(uint32 n) -{ - byte* v; - - // round to keep everything 64-bit aligned - n = rnd(n, 8); - - // be careful. calling any function might invoke - // mal to allocate more stack. - if(n > NHUNK) { - v = brk(n); - } else { - // allocate a new hunk if this one is too small - if(n > m->mem.nhunk) { - // here we're in the middle of editing m->mem - // (we're about to overwrite m->mem.hunk), - // so we can't call brk - it might call mal to grow the - // stack, and the recursive call would allocate a new - // hunk, and then once brk returned we'd immediately - // overwrite that hunk with our own. - // (the net result would be a memory leak, not a crash.) - // so we have to call sys_mmap directly - it is written - // in assembly and tagged not to grow the stack. - m->mem.hunk = - sys_mmap(nil, NHUNK, PROT_READ|PROT_WRITE|PROT_EXEC, - MAP_ANON|MAP_PRIVATE, 0, 0); - m->mem.nhunk = NHUNK; - m->mem.nmmap += NHUNK; - } - v = m->mem.hunk; - m->mem.hunk += n; - m->mem.nhunk -= n; - } - m->mem.nmal += n; - return v; -} - -void -sys_mal(uint32 n, uint8 *ret) -{ - ret = mal(n); - FLUSH(&ret); -} diff --git a/src/lib/runtime/mfixalloc.c b/src/lib/runtime/mfixalloc.c deleted file mode 100644 index dd4f3f251..000000000 --- a/src/lib/runtime/mfixalloc.c +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2009 The Go 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 -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; -} - -void* -FixAlloc_Alloc(FixAlloc *f) -{ - void *v; - - if(f->list) { - v = f->list; - f->list = *(void**)f->list; - return v; - } - if(f->nchunk < f->size) { - f->chunk = f->alloc(FixAllocChunk); - if(f->chunk == nil) - 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; - return v; -} - -void -FixAlloc_Free(FixAlloc *f, void *p) -{ - *(void**)p = f->list; - f->list = p; -} - diff --git a/src/lib/runtime/mgc0.c b/src/lib/runtime/mgc0.c deleted file mode 100644 index d58d6ce44..000000000 --- a/src/lib/runtime/mgc0.c +++ /dev/null @@ -1,231 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Garbage collector -- step 0. -// -// Stop the world, mark and sweep garbage collector. -// NOT INTENDED FOR PRODUCTION USE. -// -// A mark and sweep collector provides a way to exercise -// and test the memory allocator and the stack walking machinery -// without also needing to get reference counting -// exactly right. - -#include "runtime.h" -#include "malloc.h" - -enum { - Debug = 0 -}; - -extern byte etext[]; -extern byte end[]; - -enum { - PtrSize = sizeof(void*) -}; - -static void -scanblock(int32 depth, byte *b, int64 n) -{ - int32 off; - void *obj; - uintptr size; - uint32 *ref; - void **vp; - int64 i; - - if(Debug) - printf("%d scanblock %p %D\n", depth, b, n); - off = (uint32)(uintptr)b & (PtrSize-1); - if(off) { - b += PtrSize - off; - n -= PtrSize - off; - } - - vp = (void**)b; - n /= PtrSize; - for(i=0; isched.SP; - stk = (Stktop*)g->stackbase; - while(stk) { - scanblock(0, sp, (byte*)stk - sp); - sp = stk->oldsp; - stk = (Stktop*)stk->oldbase; - } -} - -static void -mark(void) -{ - G *gp; - - // mark data+bss - scanblock(0, etext, end - etext); - - // mark stacks - for(gp=allg; gp!=nil; gp=gp->alllink) { - switch(gp->status){ - default: - printf("unexpected G.status %d\n", gp->status); - throw("mark - bad status"); - case Gdead: - break; - case Grunning: - if(gp != g) - throw("mark - world not stopped"); - scanstack(gp); - break; - case Grunnable: - case Gsyscall: - case Gwaiting: - scanstack(gp); - break; - } - } -} - -static void -sweepspan(MSpan *s) -{ - int32 i, n, npages, size; - byte *p; - - if(s->state != MSpanInUse) - return; - - p = (byte*)(s->start << PageShift); - if(s->sizeclass == 0) { - // Large block. - switch(s->gcref0) { - default: - throw("bad 'ref count'"); - case RefFree: - case RefManual: - case RefStack: - break; - case RefNone: - if(Debug) - printf("free %D at %p\n", (uint64)s->npages<gcref0 = RefNone; // set up for next mark phase - break; - } - return; - } - - // Chunk full of small blocks. - // Must match computation in MCentral_Grow. - size = class_to_size[s->sizeclass]; - npages = class_to_allocnpages[s->sizeclass]; - n = (npages << PageShift) / (size + RefcountOverhead); - for(i=0; igcref[i]) { - default: - throw("bad 'ref count'"); - case RefFree: - case RefManual: - case RefStack: - break; - case RefNone: - if(Debug) - printf("free %d at %p\n", size, p+i*size); - free(p + i*size); - break; - case RefSome: - s->gcref[i] = RefNone; // set up for next mark phase - break; - } - } -} - -static void -sweep(void) -{ - MSpan *s; - - // Sweep all the spans. - for(s = mheap.allspans; s != nil; s = s->allnext) - sweepspan(s); -} - -// 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; - -void -gc(int32 force) -{ - byte *p; - - // 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 || panicking) - return; - - if(gcpercent == -2) { // first time through - p = getenv("GOGC"); - if(p == nil || p[0] == '\0') - gcpercent = 100; - else if(strcmp(p, (byte*)"off") == 0) - gcpercent = -1; - else - gcpercent = atoi(p); - } - if(gcpercent < 0) - return; - - semacquire(&gcsema); - gosave(&g->sched); // update g's stack pointer for scanstack - stoptheworld(); - if(mheap.Lock.key != 0) - throw("mheap locked during gc"); - if(force || mstats.inuse_pages >= mstats.next_gc) { - mark(); - sweep(); - mstats.next_gc = mstats.inuse_pages+mstats.inuse_pages*gcpercent/100; - } - starttheworld(); - gosave(&g->sched); // update g's stack pointer for debugging - semrelease(&gcsema); -} diff --git a/src/lib/runtime/mheap.c b/src/lib/runtime/mheap.c deleted file mode 100644 index d0cf2237b..000000000 --- a/src/lib/runtime/mheap.c +++ /dev/null @@ -1,333 +0,0 @@ -// Copyright 2009 The Go 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 -MHeap_Init(MHeap *h, void *(*alloc)(uintptr)) -{ - uint32 i; - - FixAlloc_Init(&h->spanalloc, sizeof(MSpan), alloc, RecordSpan, h); - FixAlloc_Init(&h->cachealloc, sizeof(MCache), alloc, nil, nil); - MHeapMap_Init(&h->map, alloc); - // h->mapcache needs no init - for(i=0; ifree); i++) - MSpanList_Init(&h->free[i]); - MSpanList_Init(&h->large); - for(i=0; icentral); i++) - MCentral_Init(&h->central[i], i); -} - -// Allocate a new span of npage pages from the heap -// and record its size class in the HeapMap and HeapMapCache. -MSpan* -MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass) -{ - MSpan *s; - - lock(h); - s = MHeap_AllocLocked(h, npage, sizeclass); - if(s != nil) - mstats.inuse_pages += npage; - unlock(h); - return s; -} - -static MSpan* -MHeap_AllocLocked(MHeap *h, uintptr npage, int32 sizeclass) -{ - uintptr n; - MSpan *s, *t; - - // Try in fixed-size lists up to max. - for(n=npage; n < nelem(h->free); n++) { - if(!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) - throw("MHeap_AllocLocked - MSpan not free"); - if(s->npages < npage) - throw("MHeap_AllocLocked - bad npages"); - MSpanList_Remove(s); - s->state = MSpanInUse; - - if(s->npages > npage) { - // Trim extra and put it back in the heap. - t = FixAlloc_Alloc(&h->spanalloc); - MSpan_Init(t, s->start + npage, s->npages - npage); - s->npages = npage; - MHeapMap_Set(&h->map, t->start - 1, s); - MHeapMap_Set(&h->map, t->start, t); - MHeapMap_Set(&h->map, t->start + t->npages - 1, t); - t->state = MSpanInUse; - MHeap_FreeLocked(h, t); - } - - // If span is being used for small objects, cache size class. - // No matter what, cache span info, because gc needs to be - // able to map interior pointer to containing span. - s->sizeclass = sizeclass; - for(n=0; nmap, s->start+n, s); - if(sizeclass == 0) { - uintptr tmp; - - // If there are entries for this span, invalidate them, - // but don't blow out cache entries about other spans. - for(n=0; nmapcache, s->start+n, tmp) != 0) - MHeapMapCache_SET(&h->mapcache, s->start+n, 0); - } else { - // Save cache entries for this span. - // If there's a size class, there aren't that many pages. - for(n=0; nmapcache, s->start+n, sizeclass); - } - - return s; -} - -// Allocate a span of exactly npage pages from the list of large spans. -static MSpan* -MHeap_AllocLarge(MHeap *h, uintptr npage) -{ - return BestFit(&h->large, npage, nil); -} - -// Search list for smallest span with >= npage pages. -// If there are multiple smallest spans, take the one -// with the earliest starting address. -static MSpan* -BestFit(MSpan *list, uintptr npage, MSpan *best) -{ - MSpan *s; - - for(s=list->next; s != list; s=s->next) { - if(s->npages < npage) - continue; - if(best == nil - || s->npages < best->npages - || (s->npages == best->npages && s->start < best->start)) - best = s; - } - return best; -} - -// Try to add at least npage pages of memory to the heap, -// returning whether it worked. -static bool -MHeap_Grow(MHeap *h, uintptr npage) -{ - uintptr ask; - void *v; - MSpan *s; - - // Ask for a big chunk, to reduce the number of mappings - // the operating system needs to track; also amortizes - // the overhead of an operating system mapping. - ask = npage< (npage<map, ((uintptr)v>>PageShift) - 1, (ask>>PageShift) + 2)) { - SysFree(v, ask); - return false; - } - - // Create a fake "in use" span and free it, so that the - // right coalescing happens. - s = FixAlloc_Alloc(&h->spanalloc); - MSpan_Init(s, (uintptr)v>>PageShift, ask>>PageShift); - MHeapMap_Set(&h->map, s->start, s); - MHeapMap_Set(&h->map, s->start + s->npages - 1, s); - s->state = MSpanInUse; - MHeap_FreeLocked(h, s); - return true; -} - -// Look up the span at the given page number. -// Page number is guaranteed to be in map -// and is guaranteed to be start or end of span. -MSpan* -MHeap_Lookup(MHeap *h, PageID p) -{ - return MHeapMap_Get(&h->map, p); -} - -// Look up the span at the given page number. -// Page number is *not* guaranteed to be in map -// and may be anywhere in the span. -// Map entries for the middle of a span are only -// valid for allocated spans. Free spans may have -// other garbage in their middles, so we have to -// check for that. -MSpan* -MHeap_LookupMaybe(MHeap *h, PageID p) -{ - MSpan *s; - - s = MHeapMap_GetMaybe(&h->map, p); - if(s == nil || p < s->start || p - s->start >= s->npages) - return nil; - if(s->state != MSpanInUse) - return nil; - return s; -} - -// Free the span back into the heap. -void -MHeap_Free(MHeap *h, MSpan *s) -{ - lock(h); - mstats.inuse_pages -= s->npages; - MHeap_FreeLocked(h, s); - unlock(h); -} - -static void -MHeap_FreeLocked(MHeap *h, MSpan *s) -{ - MSpan *t; - - if(s->state != MSpanInUse || s->ref != 0) { - printf("MHeap_FreeLocked - span %p ptr %p state %d ref %d\n", s, s->start<state, s->ref); - throw("MHeap_FreeLocked - invalid free"); - } - s->state = MSpanFree; - MSpanList_Remove(s); - - // Coalesce with earlier, later spans. - if((t = MHeapMap_Get(&h->map, s->start - 1)) != nil && t->state != MSpanInUse) { - s->start = t->start; - s->npages += t->npages; - MHeapMap_Set(&h->map, s->start, s); - MSpanList_Remove(t); - t->state = MSpanDead; - FixAlloc_Free(&h->spanalloc, t); - } - if((t = MHeapMap_Get(&h->map, s->start + s->npages)) != nil && t->state != MSpanInUse) { - s->npages += t->npages; - MHeapMap_Set(&h->map, s->start + s->npages - 1, s); - MSpanList_Remove(t); - t->state = MSpanDead; - FixAlloc_Free(&h->spanalloc, t); - } - - // Insert s into appropriate list. - if(s->npages < nelem(h->free)) - MSpanList_Insert(&h->free[s->npages], s); - else - MSpanList_Insert(&h->large, s); - - // TODO(rsc): IncrementalScavenge() to return memory to OS. -} - -// Initialize a new span with the given start and npages. -void -MSpan_Init(MSpan *span, PageID start, uintptr npages) -{ - 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 -MSpanList_Init(MSpan *list) -{ - list->state = MSpanListHead; - list->next = list; - list->prev = list; -} - -void -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 -MSpanList_IsEmpty(MSpan *list) -{ - return list->next == list; -} - -void -MSpanList_Insert(MSpan *list, MSpan *span) -{ - if(span->next != nil || span->prev != nil) - throw("MSpanList_Insert"); - span->next = list->next; - span->prev = list; - span->next->prev = span; - span->prev->next = span; -} diff --git a/src/lib/runtime/mheapmap32.c b/src/lib/runtime/mheapmap32.c deleted file mode 100644 index 420ca2d83..000000000 --- a/src/lib/runtime/mheapmap32.c +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Heap map, 32-bit version -// See malloc.h and mheap.c for overview. - -#include "runtime.h" -#include "malloc.h" - -// 3-level radix tree mapping page ids to Span*. -void -MHeapMap_Init(MHeapMap *m, void *(*allocator)(size_t)) -{ - m->allocator = allocator; -} - -MSpan* -MHeapMap_Get(MHeapMap *m, PageID k) -{ - int32 i1, i2; - - i2 = k & MHeapMap_Level2Mask; - k >>= MHeapMap_Level2Bits; - i1 = k & MHeapMap_Level1Mask; - k >>= MHeapMap_Level1Bits; - if(k != 0) - throw("MHeapMap_Get"); - - return m->p[i1]->s[i2]; -} - -MSpan* -MHeapMap_GetMaybe(MHeapMap *m, PageID k) -{ - int32 i1, i2; - MHeapMapNode2 *p2; - - i2 = k & MHeapMap_Level2Mask; - k >>= MHeapMap_Level2Bits; - i1 = k & MHeapMap_Level1Mask; - k >>= MHeapMap_Level1Bits; - if(k != 0) - throw("MHeapMap_Get"); - - p2 = m->p[i1]; - if(p2 == nil) - return nil; - return p2->s[i2]; -} - -void -MHeapMap_Set(MHeapMap *m, PageID k, MSpan *s) -{ - int32 i1, i2; - - i2 = k & MHeapMap_Level2Mask; - k >>= MHeapMap_Level2Bits; - i1 = k & MHeapMap_Level1Mask; - k >>= MHeapMap_Level1Bits; - if(k != 0) - throw("MHeapMap_Set"); - - m->p[i1]->s[i2] = s; -} - -// Allocate the storage required for entries [k, k+1, ..., k+len-1] -// so that Get and Set calls need not check for nil pointers. -bool -MHeapMap_Preallocate(MHeapMap *m, PageID k, uintptr len) -{ - uintptr end; - int32 i1; - MHeapMapNode2 *p2; - - end = k+len; - while(k < end) { - if((k >> MHeapMap_TotalBits) != 0) - return false; - i1 = (k >> MHeapMap_Level2Bits) & MHeapMap_Level1Mask; - - // first-level pointer - if(m->p[i1] == nil) { - p2 = m->allocator(sizeof *p2); - if(p2 == nil) - return false; - sys_memclr((byte*)p2, sizeof *p2); - m->p[i1] = p2; - } - - // advance key past this leaf node - k = ((k >> MHeapMap_Level2Bits) + 1) << MHeapMap_Level2Bits; - } - return true; -} - diff --git a/src/lib/runtime/mheapmap32.h b/src/lib/runtime/mheapmap32.h deleted file mode 100644 index 0a16ccd10..000000000 --- a/src/lib/runtime/mheapmap32.h +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Free(v) must be able to determine the MSpan containing v. -// The MHeapMap is a 2-level radix tree mapping page numbers to MSpans. - -typedef struct MHeapMapNode2 MHeapMapNode2; - -enum -{ - // 32 bit address - 12 bit page size = 20 bits to map - MHeapMap_Level1Bits = 10, - MHeapMap_Level2Bits = 10, - - MHeapMap_TotalBits = - MHeapMap_Level1Bits + - MHeapMap_Level2Bits, - - MHeapMap_Level1Mask = (1<array[(key) & HMASK] = (key) | ((uintptr)(value) << KBITS)) - -#define MHeapMapCache_GET(cache, key, tmp) \ - (tmp = (cache)->array[(key) & HMASK], \ - (tmp & KMASK) == (key) ? (tmp >> KBITS) : 0) diff --git a/src/lib/runtime/mheapmap64.c b/src/lib/runtime/mheapmap64.c deleted file mode 100644 index 1886ba529..000000000 --- a/src/lib/runtime/mheapmap64.c +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Heap map, 64-bit version -// See malloc.h and mheap.c for overview. - -#include "runtime.h" -#include "malloc.h" - -// 3-level radix tree mapping page ids to Span*. -void -MHeapMap_Init(MHeapMap *m, void *(*allocator)(size_t)) -{ - m->allocator = allocator; -} - -MSpan* -MHeapMap_Get(MHeapMap *m, PageID k) -{ - int32 i1, i2, i3; - - i3 = k & MHeapMap_Level3Mask; - k >>= MHeapMap_Level3Bits; - i2 = k & MHeapMap_Level2Mask; - k >>= MHeapMap_Level2Bits; - i1 = k & MHeapMap_Level1Mask; - k >>= MHeapMap_Level1Bits; - if(k != 0) - throw("MHeapMap_Get"); - - return m->p[i1]->p[i2]->s[i3]; -} - -MSpan* -MHeapMap_GetMaybe(MHeapMap *m, PageID k) -{ - int32 i1, i2, i3; - MHeapMapNode2 *p2; - MHeapMapNode3 *p3; - - i3 = k & MHeapMap_Level3Mask; - k >>= MHeapMap_Level3Bits; - i2 = k & MHeapMap_Level2Mask; - k >>= MHeapMap_Level2Bits; - i1 = k & MHeapMap_Level1Mask; - k >>= MHeapMap_Level1Bits; - if(k != 0) - throw("MHeapMap_Get"); - - p2 = m->p[i1]; - if(p2 == nil) - return nil; - p3 = p2->p[i2]; - if(p3 == nil) - return nil; - return p3->s[i3]; -} - -void -MHeapMap_Set(MHeapMap *m, PageID k, MSpan *s) -{ - int32 i1, i2, i3; - - i3 = k & MHeapMap_Level3Mask; - k >>= MHeapMap_Level3Bits; - i2 = k & MHeapMap_Level2Mask; - k >>= MHeapMap_Level2Bits; - i1 = k & MHeapMap_Level1Mask; - k >>= MHeapMap_Level1Bits; - if(k != 0) - throw("MHeapMap_Set"); - - m->p[i1]->p[i2]->s[i3] = s; -} - -// Allocate the storage required for entries [k, k+1, ..., k+len-1] -// so that Get and Set calls need not check for nil pointers. -bool -MHeapMap_Preallocate(MHeapMap *m, PageID k, uintptr len) -{ - uintptr end; - int32 i1, i2; - MHeapMapNode2 *p2; - MHeapMapNode3 *p3; - - end = k+len; - while(k < end) { - if((k >> MHeapMap_TotalBits) != 0) - return false; - i2 = (k >> MHeapMap_Level3Bits) & MHeapMap_Level2Mask; - i1 = (k >> (MHeapMap_Level3Bits + MHeapMap_Level2Bits)) & MHeapMap_Level1Mask; - - // first-level pointer - if((p2 = m->p[i1]) == nil) { - p2 = m->allocator(sizeof *p2); - if(p2 == nil) - return false; - sys_memclr((byte*)p2, sizeof *p2); - m->p[i1] = p2; - } - - // second-level pointer - if(p2->p[i2] == nil) { - p3 = m->allocator(sizeof *p3); - if(p3 == nil) - return false; - sys_memclr((byte*)p3, sizeof *p3); - p2->p[i2] = p3; - } - - // advance key past this leaf node - k = ((k >> MHeapMap_Level3Bits) + 1) << MHeapMap_Level3Bits; - } - return true; -} - diff --git a/src/lib/runtime/mheapmap64.h b/src/lib/runtime/mheapmap64.h deleted file mode 100644 index 127b773f7..000000000 --- a/src/lib/runtime/mheapmap64.h +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Free(v) must be able to determine the MSpan containing v. -// The MHeapMap is a 3-level radix tree mapping page numbers to MSpans. -// -// NOTE(rsc): On a 32-bit platform (= 20-bit page numbers), -// we can swap in a 2-level radix tree. -// -// NOTE(rsc): We use a 3-level tree because tcmalloc does, but -// having only three levels requires approximately 1 MB per node -// in the tree, making the minimum map footprint 3 MB. -// Using a 4-level tree would cut the minimum footprint to 256 kB. -// On the other hand, it's just virtual address space: most of -// the memory is never going to be touched, thus never paged in. - -typedef struct MHeapMapNode2 MHeapMapNode2; -typedef struct MHeapMapNode3 MHeapMapNode3; - -enum -{ - // 64 bit address - 12 bit page size = 52 bits to map - MHeapMap_Level1Bits = 18, - MHeapMap_Level2Bits = 18, - MHeapMap_Level3Bits = 16, - - MHeapMap_TotalBits = - MHeapMap_Level1Bits + - MHeapMap_Level2Bits + - MHeapMap_Level3Bits, - - MHeapMap_Level1Mask = (1<array[(key) & HMASK] = (key) | ((uintptr)(value) << KBITS)) - -#define MHeapMapCache_GET(cache, key, tmp) \ - (tmp = (cache)->array[(key) & HMASK], \ - (tmp & KMASK) == (key) ? (tmp >> KBITS) : 0) diff --git a/src/lib/runtime/msize.c b/src/lib/runtime/msize.c deleted file mode 100644 index 25e22637d..000000000 --- a/src/lib/runtime/msize.c +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright 2009 The Go 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 class_to_size[NumSizeClasses]; -int32 class_to_allocnpages[NumSizeClasses]; -int32 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 -SizeToClass(int32 size) -{ - if(size > MaxSmallSize) - throw("SizeToClass - invalid size"); - if(size > 1024-8) - return size_to_class128[(size-1024+127) >> 7]; - return size_to_class8[(size+7)>>3]; -} - -void -InitSizes(void) -{ - int32 align, sizeclass, size, osize, nextsize, n; - uint32 i; - uintptr allocsize, npages; - - // Initialize the class_to_size table (and choose class sizes in the process). - class_to_size[0] = 0; - 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) - throw("InitSizes - bug"); - - // Make the allocnpages big enough that - // the leftover is less than 1/8 of the total, - // so wasted space is at most 12.5%. - allocsize = PageSize; - osize = size + RefcountOverhead; - while(allocsize%osize > (allocsize/8)) - allocsize += PageSize; - npages = allocsize >> PageShift; - - // If the previous sizeclass chose the same - // allocation size and fit the same number of - // objects into the page, we might as well - // use just this size instead of having two - // different sizes. - if(sizeclass > 1 - && npages == class_to_allocnpages[sizeclass-1] - && allocsize/osize == allocsize/(class_to_size[sizeclass-1]+RefcountOverhead)) { - class_to_size[sizeclass-1] = size; - continue; - } - - class_to_allocnpages[sizeclass] = npages; - class_to_size[sizeclass] = size; - sizeclass++; - } - if(sizeclass != NumSizeClasses) { - printf("sizeclass=%d NumSizeClasses=%d\n", sizeclass, NumSizeClasses); - throw("InitSizes - bad NumSizeClasses"); - } - - // Initialize the size_to_class tables. - nextsize = 0; - for (sizeclass = 1; sizeclass < NumSizeClasses; sizeclass++) { - for(; nextsize < 1024 && nextsize <= class_to_size[sizeclass]; nextsize+=8) - size_to_class8[nextsize/8] = sizeclass; - if(nextsize >= 1024) - for(; nextsize <= class_to_size[sizeclass]; nextsize += 128) - size_to_class128[(nextsize-1024)/128] = sizeclass; - } - - // Double-check SizeToClass. - if(0) { - for(n=0; n < MaxSmallSize; n++) { - sizeclass = SizeToClass(n); - if(sizeclass < 1 || sizeclass >= NumSizeClasses || class_to_size[sizeclass] < n) { - printf("size=%d sizeclass=%d class_to_size=%d\n", n, sizeclass, class_to_size[sizeclass]); - printf("incorrect SizeToClass"); - goto dump; - } - if(sizeclass > 1 && class_to_size[sizeclass-1] >= n) { - printf("size=%d sizeclass=%d class_to_size=%d\n", n, sizeclass, class_to_size[sizeclass]); - printf("SizeToClass too big"); - goto dump; - } - } - } - - // Initialize the class_to_transfercount table. - for(sizeclass = 1; sizeclass < NumSizeClasses; sizeclass++) { - n = 64*1024 / class_to_size[sizeclass]; - if(n < 2) - n = 2; - if(n > 32) - n = 32; - class_to_transfercount[sizeclass] = n; - } - return; - -dump: - if(1){ - printf("NumSizeClasses=%d\n", NumSizeClasses); - printf("class_to_size:"); - for(sizeclass=0; sizeclass%d(%d)\n", i*8, size_to_class8[i], class_to_size[size_to_class8[i]]); - printf("\n"); - printf("size_to_class128:"); - for(i=0; i%d(%d)\n", i*128, size_to_class128[i], class_to_size[size_to_class128[i]]); - printf("\n"); - } - throw("InitSizes failed"); -} diff --git a/src/lib/runtime/print.c b/src/lib/runtime/print.c deleted file mode 100644 index 5295e338d..000000000 --- a/src/lib/runtime/print.c +++ /dev/null @@ -1,268 +0,0 @@ -// Copyright 2009 The Go Authors. 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 -dump(byte *p, int32 n) -{ - int32 i; - - for(i=0; i>4)); - sys·printpointer((byte*)(p[i]&0xf)); - if((i&15) == 15) - prints("\n"); - else - prints(" "); - } - if(n & 15) - prints("\n"); -} - -void -prints(int8 *s) -{ - sys·write(1, s, findnull((byte*)s)); -} - -// Very simple printf. Only for debugging prints. -// Do not add to this without checking with Rob. -void -printf(int8 *s, ...) -{ - int8 *p, *lp; - byte *arg, *narg; - - lp = p = s; - arg = (byte*)(&s+1); - for(; *p; p++) { - if(*p != '%') - continue; - if(p > lp) - sys·write(1, lp, p-lp); - p++; - narg = nil; - switch(*p) { - case 'd': // 32-bit - case 'x': - narg = arg + 4; - break; - case 'D': // 64-bit - case 'X': - if(sizeof(uintptr) == 8 && ((uint32)(uint64)arg)&4) - arg += 4; - narg = arg + 8; - break; - case 'p': // pointer-sized - case 's': - if(sizeof(uintptr) == 8 && ((uint32)(uint64)arg)&4) - arg += 4; - narg = arg + sizeof(uintptr); - break; - case 'S': // pointer-aligned but bigger - if(sizeof(uintptr) == 8 && ((uint32)(uint64)arg)&4) - arg += 4; - narg = arg + sizeof(String); - break; - } - switch(*p) { - case 'd': - sys·printint(*(int32*)arg); - break; - case 'D': - sys·printint(*(int64*)arg); - break; - case 'x': - sys·printhex(*(int32*)arg); - break; - case 'X': - sys·printhex(*(int64*)arg); - break; - case 'p': - sys·printpointer(*(void**)arg); - break; - case 's': - prints(*(int8**)arg); - break; - case 'S': - sys·printstring(*(String*)arg); - break; - } - arg = narg; - lp = p+1; - } - if(p > lp) - sys·write(1, lp, p-lp); -} - - -void -sys·printpc(void *p) -{ - prints("PC="); - sys·printhex((uint64)sys·getcallerpc(p)); -} - -void -sys·printbool(bool v) -{ - if(v) { - sys·write(1, (byte*)"true", 4); - return; - } - sys·write(1, (byte*)"false", 5); -} - -void -sys·printfloat(float64 v) -{ - byte buf[20]; - int32 e, s, i, n; - float64 h; - - if(isNaN(v)) { - sys·write(1, "NaN", 3); - return; - } - if(isInf(v, 0)) { - sys·write(1, "+Inf", 4); - return; - } - if(isInf(v, -1)) { - sys·write(1, "+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= 10) { - e++; - v /= 10; - } - } - - // format +d.dddd+edd - buf[0] = '+'; - if(s) - buf[0] = '-'; - for(i=0; i0; i--) { - buf[i] = v%10 + '0'; - if(v < 10) - break; - v = v/10; - } - sys·write(1, buf+i, nelem(buf)-i); -} - -void -sys·printint(int64 v) -{ - if(v < 0) { - sys·write(1, "-", 1); - v = -v; - } - sys·printuint(v); -} - -void -sys·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'; - sys·write(1, buf+i, nelem(buf)-i); -} - -void -sys·printpointer(void *p) -{ - sys·printhex((uint64)p); -} - -void -sys·printstring(String v) -{ - extern int32 maxstring; - - if(v.len > maxstring) { - sys·write(1, "[invalid string]", 16); - return; - } - if(v.len > 0) - sys·write(1, v.str, v.len); -} - -void -sys·printsp(void) -{ - sys·write(1, " ", 1); -} - -void -sys·printnl(void) -{ - sys·write(1, "\n", 1); -} diff --git a/src/lib/runtime/proc.c b/src/lib/runtime/proc.c deleted file mode 100644 index 1d065e6d2..000000000 --- a/src/lib/runtime/proc.c +++ /dev/null @@ -1,858 +0,0 @@ -// Copyright 2009 The Go Authors. 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" - -typedef struct Sched Sched; - -M m0; -G g0; // idle goroutine for m0 - -static int32 debug = 0; -static Lock debuglock; - -// 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 gs -// and no waiting ms, ready() will start a new m running in a new -// OS thread, so that all ready gs can run simultaneously, up to a limit. -// For now, ms never go away. -// -// The default maximum number of ms is one: go runs single-threaded. -// This is because some locking details have to be worked ou -// (select in particular is not locked properly) and because the low-level -// code hasn't been written yet for OS X. Setting the environmen -// variable $gomaxprocs changes sched.mmax for now. -// -// Even a program that can run without deadlock in a single process -// might use more ms if given the chance. For example, the prime -// sieve will use as many ms as there are primes (up to sched.mmax), -// allowing different stages of the pipeline to execute in parallel. -// We could revisit this choice, only kicking off new ms for blocking -// system calls, but that would limit the amount of parallel computation -// 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 gs (status == Gdead) - - G *ghead; // gs waiting to run - G *gtail; - int32 gwait; // number of gs waiting to run - int32 gcount; // number of gs that are alive - - M *mhead; // ms waiting for work - int32 mwait; // number of ms waiting for work - int32 mcount; // number of ms that have been created - int32 mcpu; // number of ms executing on cpu - int32 mcpumax; // max number of ms allowed on cpu - int32 gomaxprocs; - int32 msyscall; // number of ms in system calls - - int32 predawn; // running initialization, don't run new gs. - - Note stopped; // one g can wait here for ms to stop - int32 waitstop; // after setting this flag -}; - -Sched sched; - -// 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(void); -static void gfput(G*); // put/get on gfree -static G* gfget(void); -static void matchmg(void); // match ms to gs -static void readylocked(G*); // ready, but sched is locked - -// Scheduler loop. -static void scheduler(void); - -// The bootstrap sequence is: -// -// call osinit -// call schedinit -// make & queue new G -// call mstart -// -// The new G does: -// -// call main·init_function -// call initdone -// call main·main -void -schedinit(void) -{ - int32 n; - byte *p; - - mallocinit(); - goargs(); - - // Allocate internal symbol table representation now, - // so that we don't need to call malloc when we crash. - findfunc(0); - - sched.gomaxprocs = 1; - p = getenv("GOMAXPROCS"); - if(p != nil && (n = atoi(p)) != 0) - sched.gomaxprocs = n; - sched.mcpumax = sched.gomaxprocs; - sched.mcount = 1; - sched.predawn = 1; -} - -// Called after main·init_function; main·main will be called on return. -void -initdone(void) -{ - // Let's go. - sched.predawn = 0; - mstats.enablegc = 1; - - // If main·init_function started other goroutines, - // kick off new ms to handle them, like ready - // would have, had it not been pre-dawn. - lock(&sched); - matchmg(); - unlock(&sched); -} - -void -goexit(void) -{ - if(debug > 1){ - lock(&debuglock); - printf("goexit goid=%d\n", g->goid); - unlock(&debuglock); - } - g->status = Gmoribund; - gosched(); -} - -void -tracebackothers(G *me) -{ - G *g; - - for(g = allg; g != nil; g = g->alllink) { - if(g == me || g->status == Gdead) - continue; - printf("\ngoroutine %d:\n", g->goid); - traceback(g->sched.PC, g->sched.SP+sizeof(uintptr), g); // gogo adjusts SP by one word - } -} - -// Put on `g' queue. Sched must be locked. -static void -gput(G *g) -{ - g->schedlink = nil; - if(sched.ghead == nil) - sched.ghead = g; - else - sched.gtail->schedlink = g; - sched.gtail = g; - sched.gwait++; -} - -// Get from `g' queue. Sched must be locked. -static G* -gget(void) -{ - G *g; - - g = sched.ghead; - if(g){ - sched.ghead = g->schedlink; - if(sched.ghead == nil) - sched.gtail = nil; - sched.gwait--; - } - return g; -} - -// Put on `m' list. Sched must be locked. -static void -mput(M *m) -{ - m->schedlink = sched.mhead; - sched.mhead = m; - sched.mwait++; -} - -// Get from `m' list. Sched must be locked. -static M* -mget(void) -{ - M *m; - - m = sched.mhead; - if(m){ - sched.mhead = m->schedlink; - sched.mwait--; - } - return m; -} - -// Put on gfree list. Sched must be locked. -static void -gfput(G *g) -{ - g->schedlink = sched.gfree; - sched.gfree = g; -} - -// Get from gfree list. Sched must be locked. -static G* -gfget(void) -{ - G *g; - - g = sched.gfree; - if(g) - sched.gfree = g->schedlink; - return g; -} - -// Mark g ready to run. -void -ready(G *g) -{ - lock(&sched); - readylocked(g); - unlock(&sched); -} - -// 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) - throw("bad g->status in ready"); - g->status = Grunnable; - - gput(g); - if(!sched.predawn) - matchmg(); -} - -// Get the next goroutine that m should run. -// Sched must be locked on entry, is unlocked on exit. -// Makes sure that at most $GOMAXPROCS gs are -// running on cpus (not in system calls) at any given time. -static G* -nextgandunlock(void) -{ - G *gp; - - // On startup, each m is assigned a nextg and - // has already been accounted for in mcpu. - if(m->nextg != nil) { - gp = m->nextg; - m->nextg = nil; - unlock(&sched); - if(debug > 1) { - lock(&debuglock); - printf("m%d nextg found g%d\n", m->id, gp->goid); - unlock(&debuglock); - } - return gp; - } - - // Otherwise, look for work. - if(sched.mcpu < sched.mcpumax && (gp=gget()) != nil) { - sched.mcpu++; - unlock(&sched); - if(debug > 1) { - lock(&debuglock); - printf("m%d nextg got g%d\n", m->id, gp->goid); - unlock(&debuglock); - } - return gp; - } - - // Otherwise, sleep. - mput(m); - if(sched.mcpu == 0 && sched.msyscall == 0) - throw("all goroutines are asleep - deadlock!"); - m->nextg = nil; - noteclear(&m->havenextg); - if(sched.waitstop && sched.mcpu <= sched.mcpumax) { - sched.waitstop = 0; - notewakeup(&sched.stopped); - } - unlock(&sched); - - notesleep(&m->havenextg); - if((gp = m->nextg) == nil) - throw("bad m->nextg in nextgoroutine"); - m->nextg = nil; - if(debug > 1) { - lock(&debuglock); - printf("m%d nextg woke g%d\n", m->id, gp->goid); - unlock(&debuglock); - } - return gp; -} - -// TODO(rsc): Remove. This is only temporary, -// for the mark and sweep collector. -void -stoptheworld(void) -{ - lock(&sched); - sched.mcpumax = 1; - while(sched.mcpu > 1) { - noteclear(&sched.stopped); - sched.waitstop = 1; - unlock(&sched); - notesleep(&sched.stopped); - lock(&sched); - } - unlock(&sched); -} - -// TODO(rsc): Remove. This is only temporary, -// for the mark and sweep collector. -void -starttheworld(void) -{ - lock(&sched); - sched.mcpumax = sched.gomaxprocs; - matchmg(); - unlock(&sched); -} - -// Called to start an M. -void -mstart(void) -{ - if(m->mcache == nil) - m->mcache = allocmcache(); - minit(); - scheduler(); -} - -// Kick of new ms 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) -{ - M *m; - G *g; - - if(debug > 1 && sched.ghead != nil) { - lock(&debuglock); - printf("matchmg mcpu=%d mcpumax=%d gwait=%d\n", sched.mcpu, sched.mcpumax, sched.gwait); - unlock(&debuglock); - } - - while(sched.mcpu < sched.mcpumax && (g = gget()) != nil){ - sched.mcpu++; - if((m = mget()) != nil){ - if(debug > 1) { - lock(&debuglock); - printf("wakeup m%d g%d\n", m->id, g->goid); - unlock(&debuglock); - } - m->nextg = g; - notewakeup(&m->havenextg); - }else{ - m = malloc(sizeof(M)); - m->g0 = malg(8192); - m->nextg = g; - m->id = sched.mcount++; - if(debug) { - lock(&debuglock); - printf("alloc m%d g%d\n", m->id, g->goid); - unlock(&debuglock); - } - newosproc(m, m->g0, m->g0->stackbase, mstart); - } - } -} - -// Scheduler loop: find g to run, run it, repeat. -static void -scheduler(void) -{ - G* gp; - - lock(&sched); - if(gosave(&m->sched)){ - // Jumped here via gosave/gogo, so didn't - // execute lock(&sched) above. - lock(&sched); - - if(sched.predawn) - throw("init sleeping"); - - // Just finished running m->curg. - gp = m->curg; - gp->m = nil; - sched.mcpu--; - if(debug > 1) { - lock(&debuglock); - printf("m%d sched g%d status %d\n", m->id, gp->goid, gp->status); - unlock(&debuglock); - } - switch(gp->status){ - case Grunnable: - case Gdead: - // Shouldn't have been running! - throw("bad gp->status in sched"); - case Grunning: - gp->status = Grunnable; - gput(gp); - break; - case Gmoribund: - gp->status = Gdead; - if(--sched.gcount == 0) - exit(0); - break; - } - if(gp->readyonstop){ - gp->readyonstop = 0; - readylocked(gp); - } - } - - // Find (or wait for) g to run. Unlocks sched. - gp = nextgandunlock(); - gp->readyonstop = 0; - gp->status = Grunning; - if(debug > 1) { - lock(&debuglock); - printf("m%d run g%d at %p\n", m->id, gp->goid, gp->sched.PC); - traceback(gp->sched.PC, gp->sched.SP+8, gp); - unlock(&debuglock); - } - m->curg = gp; - gp->m = m; - g = gp; - gogo(&gp->sched); -} - -// 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. -void -gosched(void) -{ - if(g == m->g0) - throw("gosched of g0"); - if(gosave(&g->sched) == 0){ - g = m->g0; - gogo(&m->sched); - } -} - -// 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, not -// from the low-level system calls used by the runtime. -// The "arguments" are syscall.Syscall's stack frame -void -sys·entersyscall(uint64 callerpc, int64 trap) -{ - USED(callerpc); - - if(debug > 1) { - lock(&debuglock); - printf("m%d g%d enter syscall %D\n", m->id, g->goid, trap); - unlock(&debuglock); - } - lock(&sched); - g->status = Gsyscall; - sched.mcpu--; - sched.msyscall++; - if(sched.gwait != 0) - matchmg(); - if(sched.waitstop && sched.mcpu <= sched.mcpumax) { - sched.waitstop = 0; - notewakeup(&sched.stopped); - } - unlock(&sched); - // leave SP around for gc and traceback - gosave(&g->sched); -} - -// 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 -sys·exitsyscall(void) -{ - if(debug > 1) { - lock(&debuglock); - printf("m%d g%d exit syscall mcpu=%d mcpumax=%d\n", m->id, g->goid, sched.mcpu, sched.mcpumax); - unlock(&debuglock); - } - - lock(&sched); - g->status = Grunning; - sched.msyscall--; - sched.mcpu++; - // Fast path - if there's room for this m, we're done. - if(sched.mcpu <= sched.mcpumax) { - unlock(&sched); - return; - } - unlock(&sched); - - // Slow path - all the cpus are taken. - // The scheduler will ready g and put this m to sleep. - // When the scheduler takes g awa from m, - // it will undo the sched.mcpu++ above. - gosched(); -} - -/* - * stack layout parameters. - * known to linkers. - * - * 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: - * - * 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 sys.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 sys.morestack(SB) - * - * stack frame size >= StackBig: - * MOVQ m->morearg, $((argsize << 32) | frame) - * CALL sys.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 (sys.deferproc) - * or because they handle the imminent stack overflow (sys.morestack). - * - * for example, sys.deferproc might call malloc, - * which does one of the above checks (without allocating a full frame), - * which might trigger a call to sys.morestack. - * this sequence needs to fit in the bottom section of the stack. - * on amd64, sys.morestack's frame is 40 bytes, and - * sys.deferproc's frame is 56 bytes. that fits well within - * the StackGuard - StackSmall = 128 bytes at the bottom. - * there may be other sequences lurking or yet to be written - * that require more stack. sys.morestack checks to make sure - * the stack has not completely overflowed and should - * catch such sequences. - */ -enum -{ - // byte offset of stack guard (g->stackguard) above bottom of stack. - StackGuard = 256, - - // checked frames are allowed to protrude below the guard by - // this many bytes. this saves an instruction in the checking - // sequence when the stack frame is tiny. - StackSmall = 128, - - // extra space in the frame (beyond the function for which - // the frame is allocated) is assumed not to be much bigger - // than this amount. it may not be used efficiently if it is. - StackBig = 4096, -}; - -void -oldstack(void) -{ - Stktop *top; - uint32 args; - byte *sp; - uintptr oldsp, oldpc, oldbase, oldguard; - -// printf("oldstack m->cret=%p\n", m->cret); - - top = (Stktop*)m->curg->stackbase; - - args = (top->magic>>32) & 0xffffLL; - - sp = (byte*)top; - if(args > 0) { - args = (args+7) & ~7; - sp -= args; - mcpy(top->oldsp+2*sizeof(uintptr), sp, args); - } - - oldsp = (uintptr)top->oldsp + sizeof(uintptr); - oldpc = *(uintptr*)oldsp; - oldbase = (uintptr)top->oldbase; - oldguard = (uintptr)top->oldguard; - - stackfree((byte*)m->curg->stackguard - StackGuard); - - m->curg->stackbase = (byte*)oldbase; - m->curg->stackguard = (byte*)oldguard; - m->morestack.SP = (byte*)oldsp; - m->morestack.PC = (byte*)oldpc; - - // These two lines must happen in sequence; - // once g has been changed, must switch to g's stack - // before calling any non-assembly functions. - // TODO(rsc): Perhaps make the new g a parameter - // to gogoret and setspgoto, so that g is never - // explicitly assigned to without also setting - // the stack pointer. - g = m->curg; - gogoret(&m->morestack, m->cret); -} - -#pragma textflag 7 -void -lessstack(void) -{ - g = m->g0; - setspgoto(m->sched.SP, oldstack, nil); -} - -void -newstack(void) -{ - int32 frame, args; - Stktop *top; - byte *stk, *sp; - void (*fn)(void); - - frame = m->morearg & 0xffffffffLL; - args = (m->morearg>>32) & 0xffffLL; - -// printf("newstack frame=%d args=%d moresp=%p morepc=%p\n", frame, args, m->moresp, *(uintptr*)m->moresp); - - if(frame < StackBig) - frame = StackBig; - frame += 1024; // for more functions, Stktop. - stk = stackalloc(frame); - - top = (Stktop*)(stk+frame-sizeof(*top)); - - top->oldbase = m->curg->stackbase; - top->oldguard = m->curg->stackguard; - top->oldsp = m->moresp; - top->magic = m->morearg; - - m->curg->stackbase = (byte*)top; - m->curg->stackguard = stk + StackGuard; - - sp = (byte*)top; - - if(args > 0) { - // Copy args. There have been two function calls - // since they got pushed, so skip over those return - // addresses. - args = (args+7) & ~7; - sp -= args; - mcpy(sp, m->moresp+2*sizeof(uintptr), args); - } - - g = m->curg; - - // sys.morestack's return address - fn = (void(*)(void))(*(uintptr*)m->moresp); - -// printf("fn=%p\n", fn); - - setspgoto(sp, fn, retfromnewstack); - - *(int32*)345 = 123; // never return -} - -#pragma textflag 7 -void -sys·morestack(uintptr u) -{ - while(g == m->g0) { - // very bad news - *(int32*)0x1001 = 123; - } - - // Morestack's frame is about 0x30 bytes on amd64. - // If that the frame ends below the stack bottom, we've already - // overflowed. Stop right now. - while((byte*)&u - 0x30 < m->curg->stackguard - StackGuard) { - // very bad news - *(int32*)0x1002 = 123; - } - - g = m->g0; - m->moresp = (byte*)(&u-1); - setspgoto(m->sched.SP, newstack, nil); - - *(int32*)0x1003 = 123; // never return -} - -G* -malg(int32 stacksize) -{ - G *g; - byte *stk; - - g = malloc(sizeof(G)); - stk = stackalloc(stacksize + StackGuard); - g->stack0 = stk; - g->stackguard = stk + StackGuard; - g->stackbase = stk + StackGuard + stacksize; - return g; -} - -/* - * 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 -sys·newproc(int32 siz, byte* fn, byte* arg0) -{ - byte *stk, *sp; - G *newg; - -//printf("newproc siz=%d fn=%p", siz, fn); - - siz = (siz+7) & ~7; - if(siz > 1024) - throw("sys·newproc: too many args"); - - lock(&sched); - - if((newg = gfget()) != nil){ - newg->status = Gwaiting; - } else { - newg = malg(4096); - newg->status = Gwaiting; - newg->alllink = allg; - allg = newg; - } - stk = newg->stack0; - - newg->stackguard = stk+StackGuard; - - sp = stk + 4096 - 4*8; - newg->stackbase = sp; - - sp -= siz; - mcpy(sp, (byte*)&arg0, siz); - - sp -= sizeof(uintptr); - *(byte**)sp = (byte*)goexit; - - sp -= sizeof(uintptr); // retpc used by gogo - newg->sched.SP = sp; - newg->sched.PC = fn; - - sched.gcount++; - goidgen++; - newg->goid = goidgen; - - readylocked(newg); - unlock(&sched); - -//printf(" goid=%d\n", newg->goid); -} - -#pragma textflag 7 -void -sys·deferproc(int32 siz, byte* fn, byte* arg0) -{ - Defer *d; - - d = malloc(sizeof(*d) + siz - sizeof(d->args)); - d->fn = fn; - d->sp = (byte*)&arg0; - d->siz = siz; - mcpy(d->args, d->sp, d->siz); - - d->link = g->defer; - g->defer = d; -} - -#pragma textflag 7 -void -sys·deferreturn(uintptr arg0) -{ - Defer *d; - byte *sp, *fn; - uintptr *caller; - - d = g->defer; - if(d == nil) - return; - sp = (byte*)&arg0; - if(d->sp != sp) - return; - mcpy(d->sp, d->args, d->siz); - g->defer = d->link; - fn = d->fn; - free(d); - jmpdefer(fn, sp); - } - -void -runtime·Breakpoint(void) -{ - breakpoint(); -} - -void -runtime·Goexit(void) -{ - goexit(); -} - -void -runtime·Gosched(void) -{ - gosched(); -} - diff --git a/src/lib/runtime/rune.c b/src/lib/runtime/rune.c deleted file mode 100644 index ca4f9ac6a..000000000 --- a/src/lib/runtime/rune.c +++ /dev/null @@ -1,238 +0,0 @@ -/* - * 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. - */ - -/* - * 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. - */ - -/* - * 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< 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: - *rune = Bad; - return 0; - -} - -int32 -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/lib/runtime/runtime.c b/src/lib/runtime/runtime.c deleted file mode 100644 index c5ba3e6a5..000000000 --- a/src/lib/runtime/runtime.c +++ /dev/null @@ -1,462 +0,0 @@ -// Copyright 2009 The Go Authors. 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" - -int32 panicking = 0; -int32 maxround = sizeof(uintptr); - -int32 -gotraceback(void) -{ - byte *p; - - p = getenv("GOTRACEBACK"); - if(p == nil || p[0] == '\0') - return 1; // default is on - return atoi(p); -} - -void -sys·panicl(int32 lno) -{ - uint8 *sp; - - if(panicking) { - printf("double panic\n"); - exit(3); - } - panicking++; - - printf("\npanic PC=%X\n", (uint64)(uintptr)&lno); - sp = (uint8*)&lno; - if(gotraceback()){ - traceback(sys·getcallerpc(&lno), sp, g); - tracebackothers(g); - } - breakpoint(); // so we can grab it in a debugger - exit(2); -} - -void -sys·throwindex(void) -{ - throw("index out of range"); -} - -void -sys·throwreturn(void) -{ - throw("no return at end of a typed function"); -} - -void -sys·throwinit(void) -{ - throw("recursive call during initialization"); -} - -void -throw(int8 *s) -{ - printf("throw: %s\n", s); - sys·panicl(-1); - *(int32*)0 = 0; // not reached - exit(1); // even more not reached -} - -void -mcpy(byte *t, byte *f, uint32 n) -{ - while(n > 0) { - *t = *f; - t++; - f++; - n--; - } -} - -int32 -mcmp(byte *s1, byte *s2, uint32 n) -{ - uint32 i; - byte c1, c2; - - for(i=0; i c2) - return +1; - } - return 0; -} - - -void -mmov(byte *t, byte *f, uint32 n) -{ - if(t < f) { - while(n > 0) { - *t = *f; - t++; - f++; - n--; - } - } else { - t += n; - f += n; - while(n > 0) { - t--; - f--; - *t = *f; - n--; - } - } -} - -byte* -mchr(byte *p, byte c, byte *ep) -{ - for(; p < ep; p++) - if(*p == c) - return p; - return nil; -} - -uint32 -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; - -Array os·Args; -Array os·Envs; - -void -args(int32 c, uint8 **v) -{ - argc = c; - argv = v; -} - -void -goargs(void) -{ - String *gargv; - String *genvv; - int32 i, envc; - - for(envc=0; argv[argc+1+envc] != 0; envc++) - ; - - gargv = malloc(argc*sizeof gargv[0]); - genvv = malloc(envc*sizeof genvv[0]); - - for(i=0; i 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; - uint32 i; - - ba = a; - bb = b; - for(i=0; iaddr = addr; - s->g = nil; - - lock(&semlock); - s->prev = semlast; - s->next = nil; - if(semlast) - semlast->next = s; - else - semfirst = s; - semlast = s; - unlock(&semlock); -} - -static void -semdequeue(Sema *s) -{ - lock(&semlock); - if(s->next) - s->next->prev = s->prev; - else - semlast = s->prev; - if(s->prev) - s->prev->next = s->next; - else - semfirst = s->next; - s->prev = nil; - s->next = nil; - unlock(&semlock); -} - -static void -semwakeup(uint32 *addr) -{ - Sema *s; - - lock(&semlock); - for(s=semfirst; s; s=s->next) { - if(s->addr == addr && s->g) { - ready(s->g); - s->g = nil; - break; - } - } - unlock(&semlock); -} - -// Step 1 of sleep: make ourselves available for wakeup. -// TODO(rsc): Maybe we can write a version without -// locks by using cas on s->g. Maybe not: I need to -// think more about whether it would be correct. -static void -semsleep1(Sema *s) -{ - lock(&semlock); - s->g = g; - unlock(&semlock); -} - -// Decided not to go through with it: undo step 1. -static void -semsleepundo1(Sema *s) -{ - lock(&semlock); - if(s->g != nil) { - s->g = nil; // back ourselves out - } else { - // If s->g == nil already, semwakeup - // already readied us. Since we never stopped - // running, readying us just set g->readyonstop. - // Clear it. - if(g->readyonstop == 0) - *(int32*)0x555 = 555; - g->readyonstop = 0; - } - unlock(&semlock); -} - -// Step 2: wait for the wakeup. -static void -semsleep2(Sema *s) -{ - USED(s); - g->status = Gwaiting; - gosched(); -} - -static int32 -cansemacquire(uint32 *addr) -{ - uint32 v; - - while((v = *addr) > 0) - if(cas(addr, v, v-1)) - return 1; - return 0; -} - -// For now has no return value. -// Might return an ok (not interrupted) bool in the future? -void -semacquire(uint32 *addr) -{ - Sema s; - - // Easy case. - if(cansemacquire(addr)) - return; - - // Harder case: - // queue - // try semacquire one more time, sleep if failed - // dequeue - // wake up one more guy to avoid races (TODO(rsc): maybe unnecessary?) - semqueue(addr, &s); - for(;;) { - semsleep1(&s); - if(cansemacquire(addr)) { - semsleepundo1(&s); - break; - } - semsleep2(&s); - } - semdequeue(&s); - semwakeup(addr); -} - -void -semrelease(uint32 *addr) -{ - uint32 v; - - for(;;) { - v = *addr; - if(cas(addr, v, v+1)) - break; - } - semwakeup(addr); -} diff --git a/src/lib/runtime/sema_go.cgo b/src/lib/runtime/sema_go.cgo deleted file mode 100644 index eb4082a0d..000000000 --- a/src/lib/runtime/sema_go.cgo +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package sync -#include "runtime.h" - -func semacquire(addr *uint32) { - semacquire(addr); -} - -func semrelease(addr *uint32) { - semrelease(addr); -} - diff --git a/src/lib/runtime/string.c b/src/lib/runtime/string.c deleted file mode 100644 index 5bfe8196f..000000000 --- a/src/lib/runtime/string.c +++ /dev/null @@ -1,263 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "runtime.h" - -String emptystring; - -int32 -findnull(byte *s) -{ - int32 l; - - if(s == nil) - return 0; - for(l=0; s[l]!=0; l++) - ; - return l; -} - -int32 maxstring; - -String -gostringsize(int32 l) -{ - String s; - - if(l == 0) - return emptystring; - s.str = mal(l+1); // leave room for NUL for C runtime (e.g., callers of getenv) - s.len = l; - if(l > maxstring) - maxstring = l; - return s; -} - -String -gostring(byte *str) -{ - int32 l; - String s; - - l = findnull(str); - s = gostringsize(l); - mcpy(s.str, str, l); - return s; -} - -void -sys·catstring(String s1, String s2, String s3) -{ - if(s1.len == 0) { - s3 = s2; - goto out; - } - if(s2.len == 0) { - s3 = s1; - goto out; - } - - s3 = gostringsize(s1.len + s2.len); - mcpy(s3.str, s1.str, s1.len); - mcpy(s3.str+s1.len, s2.str, s2.len); - -out: - FLUSH(&s3); -} - -static void -prbounds(int8* s, int32 a, int32 b, int32 c) -{ - prints(s); - prints(" "); - sys·printint(a); - prints("<"); - sys·printint(b); - prints(">"); - sys·printint(c); - prints("\n"); - throw("string bounds"); -} - -uint32 -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 c2) - return +1; - } - if(s1.len < s2.len) - return -1; - if(s1.len > s2.len) - return +1; - return 0; -} - -void -sys·cmpstring(String s1, String s2, int32 v) -{ - v = cmpstring(s1, s2); - FLUSH(&v); -} - -int32 -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; - } -} - -void -sys·slicestring(String si, int32 lindex, int32 hindex, String so) -{ - int32 l; - - if(lindex < 0 || lindex > si.len || - hindex < lindex || hindex > si.len) { - sys·printpc(&si); - prints(" "); - prbounds("slice", lindex, si.len, hindex); - } - - l = hindex-lindex; - so.str = si.str + lindex; - so.len = l; - -// alternate to create a new string -// so = gostringsize(l); -// mcpy(so.str, si.str+lindex, l); - - FLUSH(&so); -} - -void -sys·indexstring(String s, int32 i, byte b) -{ - if(i < 0 || i >= s.len) { - sys·printpc(&s); - prints(" "); - prbounds("index", 0, i, s.len); - } - - b = s.str[i]; - FLUSH(&b); -} - -void -sys·intstring(int64 v, String s) -{ - s = gostringsize(8); - s.len = runetochar(s.str, v); - FLUSH(&s); -} - -void -sys·arraystring(Array b, String s) -{ - s = gostringsize(b.nel); - mcpy(s.str, b.array, s.len); - FLUSH(&s); -} - -void -sys·arraystringi(Array b, String s) -{ - int32 siz1, siz2, i; - int32 *a; - byte dum[8]; - - a = (int32*)b.array; - siz1 = 0; - for(i=0; i= siz1) - break; - siz2 += runetochar(s.str+siz2, a[i]); - } - s.len = siz2; - - FLUSH(&s); -} - -enum -{ - Runeself = 0x80, -}; - -// func stringiter(string, int) (retk int); -void -sys·stringiter(String s, int32 k, int32 retk) -{ - 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 + charntorune(&l, s.str+k, s.len-k); - -out: - FLUSH(&retk); -} - -// func stringiter2(string, int) (retk int, retv any); -void -sys·stringiter2(String s, int32 k, int32 retk, int32 retv) -{ - 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 + charntorune(&retv, s.str+k, s.len-k); - -out: - FLUSH(&retk); - FLUSH(&retv); -} diff --git a/src/lib/runtime/symtab.c b/src/lib/runtime/symtab.c deleted file mode 100644 index b4802715e..000000000 --- a/src/lib/runtime/symtab.c +++ /dev/null @@ -1,377 +0,0 @@ -// Copyright 2009 The Go 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" - -// TODO(rsc): Move this *under* the text segment. -// Then define names for these addresses instead of hard-coding magic ones. -#ifdef _64BIT -#define SYMCOUNTS ((int32*)(0x99LL<<32)) // known to 6l -#define SYMDATA ((byte*)(0x99LL<<32) + 8) -#else -#define SYMCOUNTS ((int32*)(0x99LL<<24)) // known to 8l -#define SYMDATA ((byte*)(0x99LL<<24) + 8) -#endif - - -// Return a pointer to a byte array containing the symbol table segment. -void -sys·symdat(Array *symtab, Array *pclntab) -{ - Array *a; - int32 *v; - - v = SYMCOUNTS; - - a = mal(sizeof *a); - a->nel = v[0]; - a->cap = a->nel; - a->array = SYMDATA; - symtab = a; - FLUSH(&symtab); - - a = mal(sizeof *a); - a->nel = v[1]; - a->cap = a->nel; - a->array = SYMDATA + v[0]; - pclntab = a; - FLUSH(&pclntab); -} - -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*)) -{ - int32 *v; - byte *p, *ep, *q; - Sym s; - - v = SYMCOUNTS; - p = SYMDATA; - ep = p + v[0]; - 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 = mchr(p, '\0', ep); - if(q == nil) - break; - p = q+1; - } - q = mchr(p, '\0', ep); - if(q == nil) - break; - s.gotype = p; - p = q+1; - fn(&s); - } -} - -// Symtab walker; accumulates info about functions. - -static Func *func; -static int32 nfunc; - -static byte **fname; -static int32 nfname; - -static void -dofunc(Sym *sym) -{ - Func *f; - - switch(sym->symtype) { - case 't': - case 'T': - if(strcmp(sym->name, (byte*)"etext") == 0) - break; - if(func == nil) { - nfunc++; - break; - } - f = &func[nfunc++]; - f->name = gostring(sym->name); - f->entry = sym->value; - 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) - 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 = findnull(q); - if(p+1+len >= ep) - break; - if(p > buf && p[-1] != '/') - *p++ = '/'; - mcpy(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). -static void -dosrcline(Sym *sym) -{ - static byte srcbuf[1000]; - static String srcstring; - static int32 lno, incstart; - static int32 nf, nhist; - Func *f; - - switch(sym->symtype) { - case 't': - case 'T': - if(strcmp(sym->name, (byte*)"etext") == 0) - break; - f = &func[nf++]; - f->src = srcstring; - f->ln0 += lno; - break; - case 'z': - if(sym->value == 1) { - // entry for main source file for a new object. - makepath(srcbuf, sizeof srcbuf, sym->name+1); - srcstring = gostring(srcbuf); - lno = 0; - nhist = 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; - }else{ - if(--nhist == 0) - lno -= sym->value - incstart; - } - } - } -} - -enum { PcQuant = 1 }; - -// 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 *v; - - // pc/ln table bounds - v = SYMCOUNTS; - p = SYMDATA; - p += v[0]; - ep = p+v[1]; - - f = func; - ef = func + nfunc; - pc = func[0].entry; // text base - f->pcln.array = p; - f->pc0 = pc - PcQuant; - line = 0; - for(; p < ep; p++) { - if(f < ef && pc >= (f+1)->entry) { - f->pcln.nel = p - f->pcln.array; - f->pcln.cap = f->pcln.nel; - f++; - f->pcln.array = p; - f->pc0 = pc; - f->ln0 = line; - } - if(*p == 0) { - // 4 byte add to line - line += (p[1]<<24) | (p[2]<<16) | (p[3]<<8) | p[4]; - p += 4; - } else if(*p <= 64) { - line += *p; - } else if(*p <= 128) { - line -= *p - 64; - } else { - pc += PcQuant*(*p - 129); - } - pc += PcQuant; - } - if(f < ef) { - f->pcln.nel = p - f->pcln.array; - f->pcln.cap = f->pcln.nel; - } -} - - -// Return actual file line number for targetpc in func f. -// (Source file is f->src.) -int32 -funcline(Func *f, uint64 targetpc) -{ - byte *p, *ep; - uintptr pc; - int32 line; - - p = f->pcln.array; - ep = p + f->pcln.nel; - pc = f->pc0; - line = f->ln0; - for(; p < ep; p++) { - if(pc >= targetpc) - return line; - if(*p == 0) { - line += (p[1]<<24) | (p[2]<<16) | (p[3]<<8) | p[4]; - p += 4; - } else if(*p <= 64) { - line += *p; - } else if(*p <= 128) { - line -= *p - 64; - } else { - pc += PcQuant*(*p - 129); - } - pc += PcQuant; - } - return line; -} - -static void -buildfuncs(void) -{ - extern byte etext[]; - - if(func != nil) - return; - // count funcs, fnames - nfunc = 0; - nfname = 0; - walksymtab(dofunc); - - // initialize tables - func = mal((nfunc+1)*sizeof func[0]); - func[nfunc].entry = (uint64)etext; - fname = 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); -} - -Func* -findfunc(uintptr addr) -{ - Func *f; - int32 nf, n; - - if(func == nil) - buildfuncs(); - 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. - prints("findfunc unreachable\n"); - return nil; -} diff --git a/src/lib/sort/Makefile b/src/lib/sort/Makefile deleted file mode 100644 index 4d193f859..000000000 --- a/src/lib/sort/Makefile +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m >Makefile - -D= - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - sort.$O\ - - -phases: a1 -_obj$D/sort.a: phases - -a1: $(O1) - $(AR) grc _obj$D/sort.a sort.$O - rm -f $(O1) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/sort.a - -$(O1): newpkg -$(O2): a1 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/sort.a - -packages: _obj$D/sort.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/sort.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/sort.a diff --git a/src/lib/sort/sort.go b/src/lib/sort/sort.go deleted file mode 100644 index 99ba0a0ef..000000000 --- a/src/lib/sort/sort.go +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// The sort package provides primitives for sorting arrays -// and user-defined collections. -package sort - -// SortInterface is the interface that a type, typically a collection, -// must implement for its contents to be sorted in increasing order. -// Its methods require that the elements of the collection be enumerated -// by an integer index. -type SortInterface interface { - // Len is the number of elements in the collection. - Len() int; - // Less returns whether the element with index i is should sort - // before the element with index j. - // TODO(r): should this method be renamed Before? - 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 SortInterface, 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 SortInterface, 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 SortInterface, a, b, n int) { - for i := 0; i < n; i++ { - data.Swap(a+i, b+i); - } -} - -func doPivot(data SortInterface, lo, hi int) (midlo, midhi int) { - m := (lo+hi)/2; - if hi - lo > 40 { - // Tukey's ``Ninther,'' median of three medians of three. - s := (hi - lo) / 8; - medianOfThree(data, lo, lo+s, lo+2*s); - medianOfThree(data, m, m-s, m+s); - medianOfThree(data, hi-1, hi-1-s, hi-1-2*s); - } - medianOfThree(data, lo, m, hi-1); - - // Invariants are: - // data[lo] = pivot (set up by ChoosePivot) - // data[lo <= i < a] = pivot - // data[a <= i < b] < pivot - // data[b <= i < c] is unexamined - // data[c <= i < d] > pivot - // data[d <= i < hi] = pivot - // - // Once b meets c, can swap the "= pivot" sections - // into the middle of the array. - pivot := lo; - a, b, c, d := lo+1, lo+1, hi, hi; - for b < c { - if data.Less(b, pivot) { // data[b] < pivot - b++; - continue; - } - if !data.Less(pivot, b) { // data[b] = pivot - data.Swap(a, b); - a++; - b++; - continue; - } - if data.Less(pivot, c-1) { // data[c-1] > pivot - c--; - continue; - } - if !data.Less(c-1, pivot) { // data[c-1] = pivot - data.Swap(c-1, d-1); - c--; - d--; - continue; - } - // data[b] > pivot; data[c-1] < pivot - data.Swap(b, c-1); - b++; - c--; - } - - n := min(b-a, a-lo); - swapRange(data, lo, b-n, n); - - n = min(hi-d, d-c); - swapRange(data, c, hi-n, n); - - return lo+b-a, hi-(d-c); -} - -func quickSort(data SortInterface, a, b int) { - if b - a > 7 { - mlo, mhi := doPivot(data, a, b); - quickSort(data, a, mlo); - quickSort(data, mhi, b); - } else if b - a > 1 { - insertionSort(data, a, b); - } -} - -func Sort(data SortInterface) { - quickSort(data, 0, data.Len()); -} - - -func IsSorted(data SortInterface) bool { - n := data.Len(); - for i := n - 1; i > 0; i-- { - if data.Less(i, i - 1) { - return false; - } - } - return true; -} - - -// Convenience types for common cases - -// IntArray attaches the methods of SortInterface to []int, sorting in increasing order. -type IntArray []int - -func (p IntArray) Len() int { return len(p); } -func (p IntArray) Less(i, j int) bool { return p[i] < p[j]; } -func (p IntArray) Swap(i, j int) { p[i], p[j] = p[j], p[i]; } - - -// FloatArray attaches the methods of SortInterface to []float, sorting in increasing order. -type FloatArray []float - -func (p FloatArray) Len() int { return len(p); } -func (p FloatArray) Less(i, j int) bool { return p[i] < p[j]; } -func (p FloatArray) Swap(i, j int) { p[i], p[j] = p[j], p[i]; } - - -// StringArray attaches the methods of SortInterface to []string, sorting in increasing order. -type StringArray []string - -func (p StringArray) Len() int { return len(p); } -func (p StringArray) Less(i, j int) bool { return p[i] < p[j]; } -func (p StringArray) Swap(i, j int) { p[i], p[j] = p[j], p[i]; } - - -// Convenience wrappers for common cases - -// SortInts sorts an array of ints in increasing order. -func SortInts(a []int) { Sort(IntArray(a)); } -// SortFloats sorts an array of floats in increasing order. -func SortFloats(a []float) { Sort(FloatArray(a)); } -// SortStrings sorts an array of strings in increasing order. -func SortStrings(a []string) { Sort(StringArray(a)); } - - -// IntsAreSorted tests whether an array of ints is sorted in increasing order. -func IntsAreSorted(a []int) bool { return IsSorted(IntArray(a)); } -// FloatsAreSorted tests whether an array of floats is sorted in increasing order. -func FloatsAreSorted(a []float) bool { return IsSorted(FloatArray(a)); } -// StringsAreSorted tests whether an array of strings is sorted in increasing order. -func StringsAreSorted(a []string) bool { return IsSorted(StringArray(a)); } diff --git a/src/lib/sort/sort_test.go b/src/lib/sort/sort_test.go deleted file mode 100644 index 1747daca6..000000000 --- a/src/lib/sort/sort_test.go +++ /dev/null @@ -1,229 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package sort - -import ( - "fmt"; - "rand"; - "sort"; - "testing"; -) - - -var ints = [...]int{74, 59, 238, -784, 9845, 959, 905, 0, 0, 42, 7586, -5467984, 7586} -var floats = [...]float{74.3, 59.0, 238.2, -784.0, 2.3, 9845.768, -959.7485, 905, 7.8, 7.8} -var strings = [...]string{"", "Hello", "foo", "bar", "foo", "f00", "%*&^*&^&", "***"} - -func TestSortIntArray(t *testing.T) { - data := ints; - a := IntArray(&data); - sort.Sort(a); - if !sort.IsSorted(a) { - t.Errorf("sorted %v", ints); - t.Errorf(" got %v", data); - } -} - -func TestSortFloatArray(t *testing.T) { - data := floats; - a := FloatArray(&data); - sort.Sort(a); - if !sort.IsSorted(a) { - t.Errorf("sorted %v", floats); - t.Errorf(" got %v", data); - } -} - -func TestSortStringArray(t *testing.T) { - data := strings; - a := StringArray(&data); - sort.Sort(a); - if !sort.IsSorted(a) { - t.Errorf("sorted %v", strings); - t.Errorf(" got %v", data); - } -} - -func TestSortInts(t *testing.T) { - data := ints; - sort.SortInts(&data); - if !sort.IntsAreSorted(&data) { - t.Errorf("sorted %v", ints); - t.Errorf(" got %v", data); - } -} - -func TestSortFloats(t *testing.T) { - data := floats; - sort.SortFloats(&data); - if !sort.FloatsAreSorted(&data) { - t.Errorf("sorted %v", floats); - t.Errorf(" got %v", data); - } -} - -func TestSortStrings(t *testing.T) { - data := strings; - sort.SortStrings(&data); - if !sort.StringsAreSorted(&data) { - t.Errorf("sorted %v", strings); - t.Errorf(" got %v", data); - } -} - -func TestSortLarge_Random(t *testing.T) { - data := make([]int, 1000000); - for i := 0; i < len(data); i++ { - data[i] = rand.Intn(100); - } - if sort.IntsAreSorted(data) { - t.Fatalf("terrible rand.rand"); - } - sort.SortInts(data); - if !sort.IntsAreSorted(data) { - t.Errorf("sort didn't sort - 1M ints"); - } -} - -const ( - _Sawtooth = iota; - _Rand; - _Stagger; - _Plateau; - _Shuffle; - _NDist; -) - -const ( - _Copy = iota; - _Reverse; - _ReverseFirstHalf; - _ReverseSecondHalf; - _Sorted; - _Dither; - _NMode; -) - -type testingData struct { - desc string; - t *testing.T; - data []int; - maxswap int; // number of swaps allowed - nswap int; -} - -func (d *testingData) Len() int { return len(d.data); } -func (d *testingData) Less(i, j int) bool { return d.data[i] < d.data[j]; } -func (d *testingData) Swap(i, j int) { - if d.nswap >= d.maxswap { - d.t.Errorf("%s: used %d swaps sorting array of %d", d.desc, d.nswap, len(d.data)); - d.t.FailNow(); - } - d.nswap++; - d.data[i], d.data[j] = d.data[j], d.data[i]; -} - -func lg(n int) int { - i := 0; - for 1<Makefile - -D= - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - atoi.$O\ - decimal.$O\ - itoa.$O\ - quote.$O\ - -O2=\ - ftoa.$O\ - -O3=\ - atof.$O\ - - -phases: a1 a2 a3 -_obj$D/strconv.a: phases - -a1: $(O1) - $(AR) grc _obj$D/strconv.a atoi.$O decimal.$O itoa.$O quote.$O - rm -f $(O1) - -a2: $(O2) - $(AR) grc _obj$D/strconv.a ftoa.$O - rm -f $(O2) - -a3: $(O3) - $(AR) grc _obj$D/strconv.a atof.$O - rm -f $(O3) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/strconv.a - -$(O1): newpkg -$(O2): a1 -$(O3): a2 -$(O4): a3 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/strconv.a - -packages: _obj$D/strconv.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/strconv.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/strconv.a diff --git a/src/lib/strconv/atof.go b/src/lib/strconv/atof.go deleted file mode 100644 index c257b2a33..000000000 --- a/src/lib/strconv/atof.go +++ /dev/null @@ -1,372 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// decimal to binary floating point conversion. -// Algorithm: -// 1) Store input in multiprecision decimal. -// 2) Multiply/divide decimal by powers of two until in range [0.5, 1) -// 3) Multiply by 2^precision and round to get mantissa. - -// The strconv package implements conversions to and from -// string representations of basic data types. -package strconv - -import ( - "math"; - "os"; - "strconv"; -) - -var optimize = true // can change for testing - -// 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' { - 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<>= 1; - exp++; - if exp-flt.bias >= 1< 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. -// -// If s is not syntactically well-formed, Atof32 returns err = 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 = os.ERANGE. -func Atof32(s string) (f float32, err os.Error) { - neg, d, trunc, ok := stringToDecimal(s); - if !ok { - return 0, 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 = 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) { - neg, d, trunc, ok := stringToDecimal(s); - if !ok { - return 0, 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 = os.ERANGE; - } - return f, err -} - -// Atof is like Atof32 or Atof64, depending on the size of float. -func Atof(s string) (f float, err os.Error) { - if FloatSize == 32 { - f1, err1 := Atof32(s); - return float(f1), err1; - } - f1, err1 := Atof64(s); - return float(f1), err1; -} - diff --git a/src/lib/strconv/atof_test.go b/src/lib/strconv/atof_test.go deleted file mode 100644 index 6782f274a..000000000 --- a/src/lib/strconv/atof_test.go +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright 2009 The Go Authors. 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 ( - "fmt"; - "os"; - "strconv"; - "testing" -) - -type atofTest struct { - in string; - out string; - err os.Error; -} - -var atoftests = []atofTest { - atofTest{ "", "0", os.EINVAL }, - atofTest{ "1", "1", nil }, - atofTest{ "+1", "1", nil }, - atofTest{ "1x", "0", os.EINVAL }, - atofTest{ "1.1.", "0", os.EINVAL }, - atofTest{ "1e23", "1e+23", nil }, - atofTest{ "100000000000000000000000", "1e+23", nil }, - atofTest{ "1e-100", "1e-100", nil }, - atofTest{ "123456700", "1.234567e+08", nil }, - atofTest{ "99999999999999974834176", "9.999999999999997e+22", nil }, - atofTest{ "100000000000000000000001", "1.0000000000000001e+23", nil }, - atofTest{ "100000000000000008388608", "1.0000000000000001e+23", nil }, - atofTest{ "100000000000000016777215", "1.0000000000000001e+23", nil }, - atofTest{ "100000000000000016777216", "1.0000000000000003e+23", nil }, - atofTest{ "-1", "-1", nil }, - atofTest{ "-0", "-0", nil }, - atofTest{ "1e-20", "1e-20", nil }, - atofTest{ "625e-3", "0.625", nil }, - - // largest float64 - atofTest{ "1.7976931348623157e308", "1.7976931348623157e+308", nil }, - atofTest{ "-1.7976931348623157e308", "-1.7976931348623157e+308", nil }, - // next float64 - too large - atofTest{ "1.7976931348623159e308", "+Inf", os.ERANGE }, - atofTest{ "-1.7976931348623159e308", "-Inf", os.ERANGE }, - // the border is ...158079 - // borderline - okay - atofTest{ "1.7976931348623158e308", "1.7976931348623157e+308", nil }, - atofTest{ "-1.7976931348623158e308", "-1.7976931348623157e+308", nil }, - // borderline - too large - atofTest{ "1.797693134862315808e308", "+Inf", os.ERANGE }, - atofTest{ "-1.797693134862315808e308", "-Inf", os.ERANGE }, - - // a little too large - atofTest{ "1e308", "1e+308", nil }, - atofTest{ "2e308", "+Inf", os.ERANGE }, - atofTest{ "1e309", "+Inf", os.ERANGE }, - - // way too large - atofTest{ "1e310", "+Inf", os.ERANGE }, - atofTest{ "-1e310", "-Inf", os.ERANGE }, - atofTest{ "1e400", "+Inf", os.ERANGE }, - atofTest{ "-1e400", "-Inf", os.ERANGE }, - atofTest{ "1e400000", "+Inf", os.ERANGE }, - atofTest{ "-1e400000", "-Inf", os.ERANGE }, - - // denormalized - atofTest{ "1e-305", "1e-305", nil }, - atofTest{ "1e-306", "1e-306", nil }, - atofTest{ "1e-307", "1e-307", nil }, - atofTest{ "1e-308", "1e-308", nil }, - atofTest{ "1e-309", "1e-309", nil }, - atofTest{ "1e-310", "1e-310", nil }, - atofTest{ "1e-322", "1e-322", nil }, - // smallest denormal - atofTest{ "5e-324", "5e-324", nil }, - // too small - atofTest{ "4e-324", "0", nil }, - // way too small - atofTest{ "1e-350", "0", nil }, - atofTest{ "1e-400000", "0", nil }, - - // try to overflow exponent - atofTest{ "1e-4294967296", "0", nil }, - atofTest{ "1e+4294967296", "+Inf", os.ERANGE }, - atofTest{ "1e-18446744073709551616", "0", nil }, - atofTest{ "1e+18446744073709551616", "+Inf", os.ERANGE }, - - // Parse errors - atofTest{ "1e", "0", os.EINVAL }, - atofTest{ "1e-", "0", os.EINVAL }, - atofTest{ ".e-1", "0", os.EINVAL }, -} - -func testAtof(t *testing.T, opt bool) { - oldopt := strconv.optimize; - strconv.optimize = opt; - for i := 0; i < len(atoftests); i++ { - test := &atoftests[i]; - out, err := strconv.Atof64(test.in); - outs := strconv.Ftoa64(out, 'g', -1); - if outs != test.out || err != test.err { - t.Errorf("strconv.Atof64(%v) = %v, %v want %v, %v\n", - test.in, out, err, test.out, test.err); - } - - if float64(float32(out)) == out { - out32, err := strconv.Atof32(test.in); - outs := strconv.Ftoa32(out32, 'g', -1); - if outs != test.out || err != test.err { - t.Errorf("strconv.Atof32(%v) = %v, %v want %v, %v # %v\n", - test.in, out32, err, test.out, test.err, out); - } - } - - if FloatSize == 64 || float64(float32(out)) == out { - outf, err := strconv.Atof(test.in); - outs := strconv.Ftoa(outf, 'g', -1); - if outs != test.out || err != test.err { - t.Errorf("strconv.Ftoa(%v) = %v, %v want %v, %v # %v\n", - test.in, outf, err, test.out, test.err, out); - } - } - } - strconv.optimize = oldopt; -} - -func TestAtof(t *testing.T) { - testAtof(t, true); -} - -func TestAtofSlow(t *testing.T) { - testAtof(t, false); -} diff --git a/src/lib/strconv/atoi.go b/src/lib/strconv/atoi.go deleted file mode 100644 index a5d896a05..000000000 --- a/src/lib/strconv/atoi.go +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright 2009 The Go Authors. 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" - -func computeIntsize() uint { - siz := uint(8); - for 1<= 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. -// -// Btoui64 returns err == os.EINVAL if b is out of -// range or s is empty or contains invalid digits. -// It returns err == os.ERANGE if the value corresponding -// to s cannot be represented by a uint64. -func Btoui64(s string, b int) (n uint64, err os.Error) { - if b < 2 || b > 36 || len(s) < 1 { - return 0, os.EINVAL; - } - - n = 0; - cutoff := cutoff64(b); - - for i := 0; i < len(s); i++ { - var v byte; - switch { - case '0' <= s[i] && s[i] <= '9': - v = s[i] - '0'; - case 'a' <= s[i] && s[i] <= 'z': - v = s[i] - 'a' + 10; - case 'A' <= s[i] && s[i] <= 'Z': - v = s[i] - 'A' + 10; - default: - return 0, os.EINVAL; - } - if int(v) >= b { - return 0, os.EINVAL; - } - - if n >= cutoff { - // n*b overflows - return 1<<64-1, os.ERANGE; - } - n *= uint64(b); - - n1 := n+uint64(v); - if n1 < n { - // n+v overflows - return 1<<64-1, os.ERANGE; - } - n = n1; - } - - return n, nil; -} - -// Atoui64 interprets a string s as an unsigned decimal, octal, or -// hexadecimal number and returns the corresponding value n. -// The default base is decimal. Strings beginning with 0x are -// hexadecimal; strings beginning with 0 are octal. -// -// 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) { - // Empty string bad. - if len(s) == 0 { - return 0, os.EINVAL - } - - // Look for octal, hex prefix. - if s[0] == '0' && len(s) > 1 { - if s[1] == 'x' || s[1] == 'X' { - // hex - return Btoui64(s[2:len(s)], 16); - } - // octal - return Btoui64(s[1:len(s)], 8); - } - // decimal - return Btoui64(s, 10); -} - - -// Atoi64 is like Atoui64 but allows signed numbers and -// returns its result in an int64. -func Atoi64(s string) (i int64, err os.Error) { - // Empty string bad. - if len(s) == 0 { - return 0, os.EINVAL - } - - // Pick off leading sign. - neg := false; - if s[0] == '+' { - s = s[1:len(s)] - } else if s[0] == '-' { - neg = true; - s = s[1:len(s)] - } - - // Convert unsigned and check range. - var un uint64; - un, err = Atoui64(s); - if err != nil && err != os.ERANGE { - return 0, err - } - if !neg && un >= 1<<63 { - return 1<<63-1, os.ERANGE - } - if neg && un > 1<<63 { - return -1<<63, os.ERANGE - } - n := int64(un); - if neg { - n = -n - } - return n, nil -} - -// 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 != os.ERANGE { - return 0, e1 - } - i = uint(i1); - if uint64(i) != i1 { - // TODO: return uint(^0), os.ERANGE. - i1 = 1<<64-1; - return uint(i1), 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 != os.ERANGE { - return 0, e1 - } - i = int(i1); - if int64(i) != i1 { - if i1 < 0 { - return -1<<(intsize-1), os.ERANGE - } - return 1<<(intsize-1) - 1, os.ERANGE - } - return i, nil -} - diff --git a/src/lib/strconv/atoi_test.go b/src/lib/strconv/atoi_test.go deleted file mode 100644 index e4a9f955d..000000000 --- a/src/lib/strconv/atoi_test.go +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package strconv - -import ( - "fmt"; - "os"; - "strconv"; - "testing" -) - -type atoui64Test struct { - in string; - out uint64; - err os.Error; -} - -var atoui64tests = []atoui64Test { - atoui64Test{"", 0, os.EINVAL}, - atoui64Test{"0", 0, nil}, - atoui64Test{"1", 1, nil}, - atoui64Test{"12345", 12345, nil}, - atoui64Test{"012345", 012345, nil}, - atoui64Test{"0x12345", 0x12345, nil}, - atoui64Test{"0X12345", 0x12345, nil}, - atoui64Test{"12345x", 0, os.EINVAL}, - atoui64Test{"98765432100", 98765432100, nil}, - atoui64Test{"18446744073709551615", 1<<64-1, nil}, - atoui64Test{"18446744073709551616", 1<<64-1, os.ERANGE}, - atoui64Test{"18446744073709551620", 1<<64-1, os.ERANGE}, - atoui64Test{"0xFFFFFFFFFFFFFFFF", 1<<64-1, nil}, - atoui64Test{"0x10000000000000000", 1<<64-1, os.ERANGE}, - atoui64Test{"01777777777777777777777", 1<<64-1, nil}, - atoui64Test{"01777777777777777777778", 0, os.EINVAL}, - atoui64Test{"02000000000000000000000", 1<<64-1, os.ERANGE}, - atoui64Test{"0200000000000000000000", 1<<61, nil}, -} - -type atoi64Test struct { - in string; - out int64; - err os.Error; -} - -var atoi64test = []atoi64Test { - atoi64Test{"", 0, os.EINVAL}, - atoi64Test{"0", 0, nil}, - atoi64Test{"-0", 0, nil}, - atoi64Test{"1", 1, nil}, - atoi64Test{"-1", -1, nil}, - atoi64Test{"12345", 12345, nil}, - atoi64Test{"-12345", -12345, nil}, - atoi64Test{"012345", 012345, nil}, - atoi64Test{"-012345", -012345, nil}, - atoi64Test{"0x12345", 0x12345, nil}, - atoi64Test{"-0X12345", -0x12345, nil}, - atoi64Test{"12345x", 0, os.EINVAL}, - atoi64Test{"-12345x", 0, os.EINVAL}, - atoi64Test{"98765432100", 98765432100, nil}, - atoi64Test{"-98765432100", -98765432100, nil}, - atoi64Test{"9223372036854775807", 1<<63-1, nil}, - atoi64Test{"-9223372036854775807", -(1<<63-1), nil}, - atoi64Test{"9223372036854775808", 1<<63-1, os.ERANGE}, - atoi64Test{"-9223372036854775808", -1<<63, nil}, - atoi64Test{"9223372036854775809", 1<<63-1, os.ERANGE}, - atoi64Test{"-9223372036854775809", -1<<63, os.ERANGE}, -} - -type atoui32Test struct { - in string; - out uint32; - err os.Error; -} - -var atoui32tests = []atoui32Test { - atoui32Test{"", 0, os.EINVAL}, - atoui32Test{"0", 0, nil}, - atoui32Test{"1", 1, nil}, - atoui32Test{"12345", 12345, nil}, - atoui32Test{"012345", 012345, nil}, - atoui32Test{"0x12345", 0x12345, nil}, - atoui32Test{"0X12345", 0x12345, nil}, - atoui32Test{"12345x", 0, os.EINVAL}, - atoui32Test{"987654321", 987654321, nil}, - atoui32Test{"4294967295", 1<<32-1, nil}, - atoui32Test{"4294967296", 1<<32-1, os.ERANGE}, -} - -type atoi32Test struct { - in string; - out int32; - err os.Error; -} - -var atoi32tests = []atoi32Test { - atoi32Test{"", 0, os.EINVAL}, - atoi32Test{"0", 0, nil}, - atoi32Test{"-0", 0, nil}, - atoi32Test{"1", 1, nil}, - atoi32Test{"-1", -1, nil}, - atoi32Test{"12345", 12345, nil}, - atoi32Test{"-12345", -12345, nil}, - atoi32Test{"012345", 012345, nil}, - atoi32Test{"-012345", -012345, nil}, - atoi32Test{"0x12345", 0x12345, nil}, - atoi32Test{"-0X12345", -0x12345, nil}, - atoi32Test{"12345x", 0, os.EINVAL}, - atoi32Test{"-12345x", 0, os.EINVAL}, - atoi32Test{"987654321", 987654321, nil}, - atoi32Test{"-987654321", -987654321, nil}, - atoi32Test{"2147483647", 1<<31-1, nil}, - atoi32Test{"-2147483647", -(1<<31-1), nil}, - atoi32Test{"2147483648", 1<<31-1, os.ERANGE}, - atoi32Test{"-2147483648", -1<<31, nil}, - atoi32Test{"2147483649", 1<<31-1, os.ERANGE}, - atoi32Test{"-2147483649", -1<<31, os.ERANGE}, -} - -func TestAtoui64(t *testing.T) { - for i := 0; i < len(atoui64tests); i++ { - test := &atoui64tests[i]; - out, err := strconv.Atoui64(test.in); - if test.out != out || test.err != err { - t.Errorf("strconv.Atoui64(%v) = %v, %v want %v, %v\n", - test.in, out, err, test.out, test.err); - } - } -} - -func TestAtoi64(t *testing.T) { - for i := 0; i < len(atoi64test); i++ { - test := &atoi64test[i]; - out, err := strconv.Atoi64(test.in); - if test.out != out || test.err != err { - t.Errorf("strconv.Atoi64(%v) = %v, %v want %v, %v\n", - test.in, out, err, test.out, test.err); - } - } -} - -func TestAtoui(t *testing.T) { - switch intsize { - case 32: - for i := 0; i < len(atoui32tests); i++ { - test := &atoui32tests[i]; - out, err := strconv.Atoui(test.in); - if test.out != uint32(out) || test.err != err { - t.Errorf("strconv.Atoui(%v) = %v, %v want %v, %v\n", - test.in, out, err, test.out, test.err); - } - } - case 64: - for i := 0; i < len(atoui64tests); i++ { - test := &atoui64tests[i]; - out, err := strconv.Atoui(test.in); - if test.out != uint64(out) || test.err != err { - t.Errorf("strconv.Atoui(%v) = %v, %v want %v, %v\n", - test.in, out, err, test.out, test.err); - } - } - } -} - -func TestAtoi(t *testing.T) { - switch intsize { - case 32: - for i := 0; i < len(atoi32tests); i++ { - test := &atoi32tests[i]; - out, err := strconv.Atoi(test.in); - if test.out != int32(out) || test.err != err { - t.Errorf("strconv.Atoi(%v) = %v, %v want %v, %v\n", - test.in, out, err, test.out, test.err); - } - } - case 64: - for i := 0; i < len(atoi64test); i++ { - test := &atoi64test[i]; - out, err := strconv.Atoi(test.in); - if test.out != int64(out) || test.err != err { - t.Errorf("strconv.Atoi(%v) = %v, %v want %v, %v\n", - test.in, out, err, test.out, test.err); - } - } - } -} - diff --git a/src/lib/strconv/decimal.go b/src/lib/strconv/decimal.go deleted file mode 100644 index 38d9c47fb..000000000 --- a/src/lib/strconv/decimal.go +++ /dev/null @@ -1,392 +0,0 @@ -// Copyright 2009 The Go 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 - -import "bytes" - -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; -func (a *decimal) Assign(v uint64); -func (a *decimal) Shift(k int) *decimal; -func (a *decimal) Round(nd int) *decimal; -func (a *decimal) RoundUp(nd int) *decimal; -func (a *decimal) RoundDown(nd int) *decimal; -func (a *decimal) RoundedInteger() uint64; - - -func digitZero(dst []byte) int; - -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 += bytes.Copy(buf[w:w+a.nd], a.d[0:a.nd]); - - case a.dp < a.nd: - // decimal point in middle of digits - w += bytes.Copy(buf[w:w+a.dp], a.d[0:a.dp]); - buf[w] = '.'; - w++; - w += bytes.Copy(buf[w:w+a.nd-a.dp], a.d[a.dp:a.nd]); - - default: - // zeros fill space between digits and decimal point - w += bytes.Copy(buf[w:w+a.nd], a.d[0:a.nd]); - w += digitZero(buf[w:w+a.dp-a.nd]); - } - return string(buf[0:w]); -} - -func copy(dst []byte, src []byte) int { - for i := 0; i < len(dst); i++ { - dst[i] = src[i]; - } - return len(dst); -} - -func digitZero(dst []byte) int { - for i := 0; i < len(dst); i++ { - dst[i] = '0'; - } - return len(dst); -} - -// trim trailing zeros from number. -// (They are meaningless; the decimal point is tracked -// independent of the number of digits.) -func trim(a *decimal) { - for a.nd > 0 && a.d[a.nd-1] == '0' { - a.nd--; - } - if a.nd == 0 { - a.dp = 0; - } -} - -// Assign v to a. -func (a *decimal) Assign(v uint64) { - var buf [50]byte; - - // Write reversed decimal in buf. - n := 0; - for v > 0 { - v1 := v/10; - v -= 10*v1; - buf[n] = byte(v + '0'); - n++; - v = v1; - } - - // Reverse again to produce forward decimal in a.d. - a.nd = 0; - for n--; n>=0; n-- { - a.d[a.nd] = buf[n]; - a.nd++; - } - a.dp = a.nd; - trim(a); -} - -func newDecimal(i uint64) *decimal { - a := new(decimal); - a.Assign(i); - return a; -} - -// Maximum shift that we can do in one pass without overflow. -// Signed int has 31 bits, and we have to be able to accomodate 9<>k == 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< 0 { - dig := n>>k; - n -= dig<= 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; - } - - if w != 0 { - // TODO: Remove - has no business panicking. - panicln("strconv: bad leftShift", w); - } - 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 (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. -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/lib/strconv/decimal_test.go b/src/lib/strconv/decimal_test.go deleted file mode 100644 index bc82861bd..000000000 --- a/src/lib/strconv/decimal_test.go +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package strconv - -import ( - "fmt"; - "strconv"; - "testing"; -) - -type shiftTest struct { - i uint64; - shift int; - out string; -} - -var shifttests = []shiftTest { - shiftTest{ 0, -100, "0" }, - shiftTest{ 0, 100, "0" }, - shiftTest{ 1, 100, "1267650600228229401496703205376" }, - shiftTest{ 1, -100, - "0.00000000000000000000000000000078886090522101180541" - "17285652827862296732064351090230047702789306640625" }, - shiftTest{ 12345678, 8, "3160493568" }, - shiftTest{ 12345678, -8, "48225.3046875" }, - shiftTest{ 195312, 9, "99999744" }, - shiftTest{ 1953125, 9, "1000000000" }, -} - -func TestDecimalShift(t *testing.T) { - ok := true; - for i := 0; i < len(shifttests); i++ { - test := &shifttests[i]; - s := strconv.newDecimal(test.i).Shift(test.shift).String(); - if s != test.out { - t.Errorf("Decimal %v << %v = %v, want %v\n", - test.i, test.shift, s, test.out); - } - } -} - -type roundTest struct { - i uint64; - nd int; - down, round, up string; - int uint64; -} - -var roundtests = []roundTest { - roundTest{ 0, 4, "0", "0", "0", 0 }, - roundTest{ 12344999, 4, "12340000", "12340000", "12350000", 12340000 }, - roundTest{ 12345000, 4, "12340000", "12340000", "12350000", 12340000 }, - roundTest{ 12345001, 4, "12340000", "12350000", "12350000", 12350000 }, - roundTest{ 23454999, 4, "23450000", "23450000", "23460000", 23450000 }, - roundTest{ 23455000, 4, "23450000", "23460000", "23460000", 23460000 }, - roundTest{ 23455001, 4, "23450000", "23460000", "23460000", 23460000 }, - - roundTest{ 99994999, 4, "99990000", "99990000", "100000000", 99990000 }, - roundTest{ 99995000, 4, "99990000", "100000000", "100000000", 100000000 }, - roundTest{ 99999999, 4, "99990000", "100000000", "100000000", 100000000 }, - - roundTest{ 12994999, 4, "12990000", "12990000", "13000000", 12990000 }, - roundTest{ 12995000, 4, "12990000", "13000000", "13000000", 13000000 }, - roundTest{ 12999999, 4, "12990000", "13000000", "13000000", 13000000 }, -} - -func TestDecimalRound(t *testing.T) { - for i := 0; i < len(roundtests); i++ { - test := &roundtests[i]; - s := strconv.newDecimal(test.i).RoundDown(test.nd).String(); - if s != test.down { - t.Errorf("Decimal %v RoundDown %d = %v, want %v\n", - test.i, test.nd, s, test.down); - } - s = strconv.newDecimal(test.i).Round(test.nd).String(); - if s != test.round { - t.Errorf("Decimal %v Round %d = %v, want %v\n", - test.i, test.nd, s, test.down); - } - s = strconv.newDecimal(test.i).RoundUp(test.nd).String(); - if s != test.up { - t.Errorf("Decimal %v RoundUp %d = %v, want %v\n", - test.i, test.nd, s, test.up); - } - } -} - -type roundIntTest struct { - i uint64; - shift int; - int uint64; -} - -var roundinttests = []roundIntTest { - roundIntTest{ 0, 100, 0 }, - roundIntTest{ 512, -8, 2 }, - roundIntTest{ 513, -8, 2 }, - roundIntTest{ 640, -8, 2 }, - roundIntTest{ 641, -8, 3 }, - roundIntTest{ 384, -8, 2 }, - roundIntTest{ 385, -8, 2 }, - roundIntTest{ 383, -8, 1 }, - roundIntTest{ 1, 100, 1<<64-1 }, - roundIntTest{ 1000, 0, 1000 }, -} - -func TestDecimalRoundedInteger(t *testing.T) { - for i := 0; i < len(roundinttests); i++ { - test := roundinttests[i]; - // TODO: should be able to use int := here. - int1 := strconv.newDecimal(test.i).Shift(test.shift).RoundedInteger(); - if int1 != test.int { - t.Errorf("Decimal %v >> %v RoundedInteger = %v, want %v\n", - test.i, test.shift, int1, test.int); - } - } -} diff --git a/src/lib/strconv/fp_test.go b/src/lib/strconv/fp_test.go deleted file mode 100644 index 60d7ce6cf..000000000 --- a/src/lib/strconv/fp_test.go +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright 2009 The Go Authors. 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 ( - "bufio"; - "fmt"; - "io"; - "os"; - "strconv"; - "strings"; - "testing"; -) - -func pow2(i int) float64 { - switch { - case i < 0: - return 1 / pow2(-i); - case i == 0: - return 1; - case i == 1: - return 2; - } - return pow2(i/2) * pow2(i-i/2); -} - -// Wrapper around strconv.Atof64. Handles dddddp+ddd (binary exponent) -// itself, passes the rest on to strconv.Atof64. -func myatof64(s string) (f float64, ok bool) { - a := strings.Split(s, "p"); - if len(a) == 2 { - n, err := strconv.Atoi64(a[0]); - if err != nil { - return 0, false; - } - e, err1 := strconv.Atoi(a[1]); - if err1 != nil { - println("bad e", a[1]); - return 0, false; - } - v := float64(n); - // We expect that v*pow2(e) fits in a float64, - // but pow2(e) by itself may not. Be careful. - if e <= -1000 { - v *= pow2(-1000); - e += 1000; - for e < 0 { - v /= 2; - e++; - } - return v, true; - } - if e >= 1000 { - v *= pow2(1000); - e -= 1000; - for e > 0 { - v *= 2; - e--; - } - return v, true; - } - return v*pow2(e), true; - } - f1, err := strconv.Atof64(s); - if err != nil { - return 0, false; - } - return f1, true; -} - -// Wrapper around strconv.Atof32. Handles dddddp+ddd (binary exponent) -// itself, passes the rest on to strconv.Atof32. -func myatof32(s string) (f float32, ok bool) { - a := strings.Split(s, "p"); - if len(a) == 2 { - n, err := strconv.Atoi(a[0]); - if err != nil { - println("bad n", a[0]); - return 0, false; - } - e, err1 := strconv.Atoi(a[1]); - if err1 != nil { - println("bad p", a[1]); - return 0, false; - } - return float32(float64(n)*pow2(e)), true; - } - f1, err1 := strconv.Atof32(s); - if err1 != nil { - return 0, false; - } - return f1, true; -} - -func TestFp(t *testing.T) { - f, err := os.Open("testfp.txt", os.O_RDONLY, 0); - if err != nil { - panicln("testfp: open testfp.txt:", err.String()); - } - defer f.Close(); - - b := bufio.NewReader(f); - - lineno := 0; - for { - line, err2 := b.ReadLineString('\n', false); - if err2 == io.ErrEOF { - break; - } - if err2 != nil { - panicln("testfp: read testfp.txt:", err2.String()); - } - lineno++; - if len(line) == 0 || line[0] == '#' { - continue - } - a := strings.Split(line, " "); - if len(a) != 4 { - t.Error("testfp.txt:", lineno, ": wrong field count\n"); - 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); - } -//else print("testfp.txt:", lineno, ": worked! ", s, "\n"); - } -} diff --git a/src/lib/strconv/ftoa.go b/src/lib/strconv/ftoa.go deleted file mode 100644 index b17115175..000000000 --- a/src/lib/strconv/ftoa.go +++ /dev/null @@ -1,418 +0,0 @@ -// Copyright 2009 The Go 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"; - "strconv"; -) - -// TODO: move elsewhere? -type floatInfo struct { - mantbits uint; - expbits uint; - bias int; -} -var float32info = floatInfo{ 23, 8, -127 } -var float64info = floatInfo{ 52, 11, -1023 } - -func fmtB(neg bool, mant uint64, exp int, flt *floatInfo) string -func fmtE(neg bool, d *decimal, prec int) string -func fmtF(neg bool, d *decimal, prec int) string -func genericFtoa(bits uint64, fmt byte, prec int, flt *floatInfo) string -func max(a, b int) int -func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) - -func floatsize() int { - // Figure out whether float is float32 or float64. - // 1e-35 is representable in both, but 1e-70 - // is too small for a float32. - var f float = 1e-35; - if f*f == 0 { - return 32; - } - return 64; -} - -// Floatsize gives the size of the float type, either 32 or 64. -var FloatSize = floatsize() - -// 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), -// 'f' (-ddd.dddd, no exponent), or -// 'g' ('e' for large exponents, 'f' otherwise). -// -// The precision prec controls the number of digits -// (excluding the exponent) printed by the 'e', 'f', and 'g' formats. -// For 'e' and 'f' it is the number of digits after the decimal point. -// For 'g' it is the total number of digits. -// 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); -} - -// Ftoa behaves as Ftoa32 or Ftoa64, depending on the size of the float type. -func Ftoa(f float, fmt byte, prec int) string { - if FloatSize == 32 { - return Ftoa32(float32(f), fmt, prec); - } - return Ftoa64(float64(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< d.nd { - prec = 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. - eprec := prec; - if shortest { - eprec = 6 - } - exp := d.dp - 1; - if exp < -4 || exp >= eprec { - return fmtE(neg, d, prec - 1); - } - 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: Unless exp == minexp, if the number of digits in d - // is less than 17, it seems unlikely that it could not 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< 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] = 'e'; - 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:len(buf)]); -} - -func max(a, b int) int { - if a > b { - return a; - } - return b; -} - diff --git a/src/lib/strconv/ftoa_test.go b/src/lib/strconv/ftoa_test.go deleted file mode 100644 index 0f0baa514..000000000 --- a/src/lib/strconv/ftoa_test.go +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package strconv - -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 { - ftoaTest{ 1, 'e', 5, "1.00000e+00" }, - ftoaTest{ 1, 'f', 5, "1.00000" }, - ftoaTest{ 1, 'g', 5, "1" }, - ftoaTest{ 1, 'g', -1, "1" }, - ftoaTest{ 20, 'g', -1, "20" }, - ftoaTest{ 1234567.8, 'g', -1, "1.2345678e+06" }, - ftoaTest{ 200000, 'g', -1, "200000" }, - ftoaTest{ 2000000, 'g', -1, "2e+06" }, - - ftoaTest{ 0, 'e', 5, "0.00000e+00" }, - ftoaTest{ 0, 'f', 5, "0.00000" }, - ftoaTest{ 0, 'g', 5, "0" }, - ftoaTest{ 0, 'g', -1, "0" }, - - ftoaTest{ -1, 'e', 5, "-1.00000e+00" }, - ftoaTest{ -1, 'f', 5, "-1.00000" }, - ftoaTest{ -1, 'g', 5, "-1" }, - ftoaTest{ -1, 'g', -1, "-1" }, - - ftoaTest{ 12, 'e', 5, "1.20000e+01" }, - ftoaTest{ 12, 'f', 5, "12.00000" }, - ftoaTest{ 12, 'g', 5, "12" }, - ftoaTest{ 12, 'g', -1, "12" }, - - ftoaTest{ 123456700, 'e', 5, "1.23457e+08" }, - ftoaTest{ 123456700, 'f', 5, "123456700.00000" }, - ftoaTest{ 123456700, 'g', 5, "1.2346e+08" }, - ftoaTest{ 123456700, 'g', -1, "1.234567e+08" }, - - ftoaTest{ 1.2345e6, 'e', 5, "1.23450e+06" }, - ftoaTest{ 1.2345e6, 'f', 5, "1234500.00000" }, - ftoaTest{ 1.2345e6, 'g', 5, "1.2345e+06" }, - - ftoaTest{ 1e23, 'e', 17, "9.99999999999999916e+22" }, - ftoaTest{ 1e23, 'f', 17, "99999999999999991611392.00000000000000000" }, - ftoaTest{ 1e23, 'g', 17, "9.9999999999999992e+22" }, - - ftoaTest{ 1e23, 'e', -1, "1e+23" }, - ftoaTest{ 1e23, 'f', -1, "100000000000000000000000" }, - ftoaTest{ 1e23, 'g', -1, "1e+23" }, - - ftoaTest{ below1e23, 'e', 17, "9.99999999999999748e+22" }, - ftoaTest{ below1e23, 'f', 17, "99999999999999974834176.00000000000000000" }, - ftoaTest{ below1e23, 'g', 17, "9.9999999999999975e+22" }, - - ftoaTest{ below1e23, 'e', -1, "9.999999999999997e+22" }, - ftoaTest{ below1e23, 'f', -1, "99999999999999970000000" }, - ftoaTest{ below1e23, 'g', -1, "9.999999999999997e+22" }, - - ftoaTest{ above1e23, 'e', 17, "1.00000000000000008e+23" }, - ftoaTest{ above1e23, 'f', 17, "100000000000000008388608.00000000000000000" }, - ftoaTest{ above1e23, 'g', 17, "1.0000000000000001e+23" }, - - ftoaTest{ above1e23, 'e', -1, "1.0000000000000001e+23" }, - ftoaTest{ above1e23, 'f', -1, "100000000000000010000000" }, - ftoaTest{ above1e23, 'g', -1, "1.0000000000000001e+23" }, - - ftoaTest{ fdiv(5e-304, 1e20), 'g', -1, "5e-324" }, - ftoaTest{ fdiv(-5e-304, 1e20), 'g', -1, "-5e-324" }, - - ftoaTest{ 32, 'g', -1, "32" }, - ftoaTest{ 32, 'g', 0, "3e+01" }, - - ftoaTest{ 100, 'x', -1, "%x" }, - - ftoaTest{ math.NaN(), 'g', -1, "NaN" }, - ftoaTest{ -math.NaN(), 'g', -1, "NaN" }, - ftoaTest{ math.Inf(0), 'g', -1, "+Inf" }, - ftoaTest{ math.Inf(-1), 'g', -1, "-Inf" }, - ftoaTest{ -math.Inf(0), 'g', -1, "-Inf" }, - - ftoaTest{ -1, 'b', -1, "-4503599627370496p-52" }, -} - -func TestFtoa(t *testing.T) { - if strconv.FloatSize != 32 { - panic("floatsize: ", strconv.FloatSize); - } - for i := 0; i < len(ftoatests); i++ { - test := &ftoatests[i]; - s := strconv.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); - } - if float64(float32(test.f)) == test.f && test.fmt != 'b' { - s := strconv.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); - } - } - } -} diff --git a/src/lib/strconv/itoa.go b/src/lib/strconv/itoa.go deleted file mode 100644 index 7f693ea8c..000000000 --- a/src/lib/strconv/itoa.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2009 The Go Authors. 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 - -// Itob64 returns the string representation of i in the given base. -func Itob64(i int64, base uint) string { - if i == 0 { - return "0" - } - - u := uint64(i); - if i < 0 { - u = -u; - } - - // Assemble decimal in reverse order. - var buf [32]byte; - j := len(buf); - b := uint64(base); - for u > 0 { - j--; - buf[j] = "0123456789abcdefghijklmnopqrstuvwxyz"[u%b]; - u /= b; - } - - if i < 0 { // add sign - j--; - buf[j] = '-' - } - - return string(buf[j:len(buf)]) -} - -// Itoa64 returns the decimal string representation of i. -func Itoa64(i int64) string { - return Itob64(i, 10); -} - -// 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); -} diff --git a/src/lib/strconv/itoa_test.go b/src/lib/strconv/itoa_test.go deleted file mode 100644 index 34caf9a32..000000000 --- a/src/lib/strconv/itoa_test.go +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright 2009 The Go Authors. 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 ( - "fmt"; - "os"; - "strconv"; - "testing"; -) - -type itob64Test struct { - in int64; - base uint; - out string; -} - -var itob64tests = []itob64Test { - itob64Test{ 0, 10, "0" }, - itob64Test{ 1, 10, "1" }, - itob64Test{ -1, 10, "-1" }, - itob64Test{ 12345678, 10, "12345678" }, - itob64Test{ -987654321, 10, "-987654321" }, - itob64Test{ 1<<31-1, 10, "2147483647" }, - itob64Test{ -1<<31+1, 10, "-2147483647" }, - itob64Test{ 1<<31, 10, "2147483648" }, - itob64Test{ -1<<31, 10, "-2147483648" }, - itob64Test{ 1<<31+1, 10, "2147483649" }, - itob64Test{ -1<<31-1, 10, "-2147483649" }, - itob64Test{ 1<<32-1, 10, "4294967295" }, - itob64Test{ -1<<32+1, 10, "-4294967295" }, - itob64Test{ 1<<32, 10, "4294967296" }, - itob64Test{ -1<<32, 10, "-4294967296" }, - itob64Test{ 1<<32+1, 10, "4294967297" }, - itob64Test{ -1<<32-1, 10, "-4294967297" }, - itob64Test{ 1<<50, 10, "1125899906842624" }, - itob64Test{ 1<<63-1, 10, "9223372036854775807" }, - itob64Test{ -1<<63+1, 10, "-9223372036854775807" }, - itob64Test{ -1<<63, 10, "-9223372036854775808" }, - - itob64Test{ 0, 2, "0" }, - itob64Test{ 10, 2, "1010" }, - itob64Test{ -1, 2, "-1" }, - itob64Test{ 1<<15, 2, "1000000000000000" }, - - itob64Test{ -8, 8, "-10" }, - itob64Test{ 057635436545, 8, "57635436545" }, - itob64Test{ 1<<24, 8, "100000000" }, - - itob64Test{ 16, 16, "10" }, - itob64Test{ -0x123456789abcdef, 16, "-123456789abcdef" }, - itob64Test{ 1<<63-1, 16, "7fffffffffffffff" }, - - itob64Test{ 16, 17, "g" }, - itob64Test{ 25, 25, "10" }, - itob64Test{ (((((17*35+24)*35+21)*35+34)*35+12)*35+24)*35+32, 35, "holycow" }, - itob64Test{ (((((17*36+24)*36+21)*36+34)*36+12)*36+24)*36+32, 36, "holycow" }, -} - -func TestItoa(t *testing.T) { - for i := 0; i < len(itob64tests); i++ { - test := itob64tests[i]; - - s := strconv.Itob64(test.in, test.base); - if s != test.out { - t.Errorf("strconv.Itob64(%v, %v) = %v want %v\n", - test.in, test.base, s, test.out); - } - - if int64(int(test.in)) == test.in { - s := strconv.Itob(int(test.in), test.base); - if s != test.out { - t.Errorf("strconv.Itob(%v, %v) = %v want %v\n", - test.in, test.base, s, test.out); - } - } - - if test.base == 10 { - s := strconv.Itoa64(test.in); - if s != test.out { - t.Errorf("strconv.Itoa64(%v) = %v want %v\n", - test.in, s, test.out); - } - - if int64(int(test.in)) == test.in { - s := strconv.Itoa(int(test.in)); - if s != test.out { - t.Errorf("strconv.Itoa(%v) = %v want %v\n", - test.in, s, test.out); - } - } - } - } -} - -// TODO: Use once there is a strconv.uitoa -type uitoa64Test struct { - in uint64; - out string; -} - -// TODO: should be able to call this atoui64tests. -var uitoa64tests = []uitoa64Test { - uitoa64Test{ 1<<63-1, "9223372036854775807" }, - uitoa64Test{ 1<<63, "9223372036854775808" }, - uitoa64Test{ 1<<63+1, "9223372036854775809" }, - uitoa64Test{ 1<<64-2, "18446744073709551614" }, - uitoa64Test{ 1<<64-1, "18446744073709551615" }, -} diff --git a/src/lib/strconv/quote.go b/src/lib/strconv/quote.go deleted file mode 100644 index 8d7900d1d..000000000 --- a/src/lib/strconv/quote.go +++ /dev/null @@ -1,229 +0,0 @@ -// Copyright 2009 The Go Authors. 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"; - "utf8"; -) - -const lowerhex = "0123456789abcdef" - -// Quote returns a double-quoted Go string literal -// representing s. The returned string s uses Go escape -// sequences (\t, \n, \xFF, \u0100) for control characters -// and non-ASCII characters. -func Quote(s string) string { - // TODO(rsc): String accumulation could be more efficient. - t := `"`; - for ; len(s) > 0; s = s[1:len(s)] { - switch c := s[0]; { - case c == '"': - t += `\"`; - case c == '\\': - t += `\\`; - case ' ' <= c && c <= '~': - t += string(c); - case c == '\a': - t += `\a`; - case c == '\b': - t += `\b`; - case c == '\f': - t += `\f`; - case c == '\n': - t += `\n`; - case c == '\r': - t += `\r`; - case c == '\t': - t += `\t`; - case c == '\v': - t += `\v`; - - case c < utf8.RuneSelf: - t += `\x` + string(lowerhex[c>>4]) + string(lowerhex[c&0xF]); - - case utf8.FullRuneInString(s): - r, size := utf8.DecodeRuneInString(s); - if r == utf8.RuneError && size == 1 { - goto EscX; - } - s = s[size-1:len(s)]; // next iteration will slice off 1 more - if r < 0x10000 { - t += `\u`; - for j:=uint(0); j<4; j++ { - t += string(lowerhex[(r>>(12-4*j))&0xF]); - } - } else { - t += `\U`; - for j:=uint(0); j<8; j++ { - t += string(lowerhex[(r>>(28-4*j))&0xF]); - } - } - - default: - EscX: - t += `\x`; - t += string(lowerhex[c>>4]); - t += string(lowerhex[c&0xF]); - } - } - t += `"`; - return t; -} - -// 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; -} - -func unquoteChar(s string, q byte) (t, ns string, err os.Error) { - err = os.EINVAL; // assume error for easy return - - // easy cases - switch c := s[0]; { - case c >= utf8.RuneSelf: - r, size := utf8.DecodeRuneInString(s); - return s[0:size], s[size:len(s)], nil; - case c == q: - return; - case c != '\\': - return s[0:1], s[1:len(s)], nil; - } - - // hard case: c is backslash - if len(s) <= 1 { - return; - } - c := s[1]; - s = s[2:len(s)]; - - switch c { - case 'a': - return "\a", s, nil; - case 'b': - return "\b", s, nil; - case 'f': - return "\f", s, nil; - case 'n': - return "\n", s, nil; - case 'r': - return "\r", s, nil; - case 't': - return "\t", s, nil; - case 'v': - return "\v", s, nil; - 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 { - return; - } - for j := 0; j < n; j++ { - x, ok := unhex(s[j]); - if !ok { - return; - } - v = v<<4 | x; - } - s = s[n:len(s)]; - if c == 'x' { - // single-byte string, possibly not UTF-8 - return string([]byte{byte(v)}), s, nil; - } - if v > utf8.RuneMax { - return; - } - return string(v), s, nil; - case '0', '1', '2', '3', '4', '5', '6', '7': - v := int(c) - '0'; - if len(s) < 2 { - 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:len(s)]; - if v > 255 { - return; - } - return string(v), s, nil; - - case '\\', q: - return string(c), s, nil; - } - 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) { - err = os.EINVAL; // assume error for easy return - n := len(s); - if n < 2 { - return; - } - quote := s[0]; - if quote != s[n-1] { - return; - } - s = s[1:n-1]; - - if quote == '`' { - return s, nil; - } - if quote != '"' && quote != '\'' { - return; - } - - // TODO(rsc): String accumulation could be more efficient. - var c, tt string; - var err1 os.Error; - for len(s) > 0 { - if c, s, err1 = unquoteChar(s, quote); err1 != nil { - err = err1; - return; - } - tt += c; - if quote == '\'' && len(s) != 0 { - // single-quoted must be single character - return; - } - } - return tt, nil -} diff --git a/src/lib/strconv/quote_test.go b/src/lib/strconv/quote_test.go deleted file mode 100644 index 0fc01ebae..000000000 --- a/src/lib/strconv/quote_test.go +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright 2009 The Go Authors. 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"; - "strconv"; - "testing"; -) - -type quoteTest struct { - in string; - out string; -} - -var quotetests = []quoteTest { - quoteTest{ "\a\b\f\r\n\t\v", `"\a\b\f\r\n\t\v"` }, - quoteTest{ "\\", `"\\"` }, - quoteTest{ "abc\xffdef", `"abc\xffdef"` }, - quoteTest{ "\u263a", `"\u263a"` }, - quoteTest{ "\U0010ffff", `"\U0010ffff"` }, - quoteTest{ "\x04", `"\x04"` }, -} - -func TestQuote(t *testing.T) { - for i := 0; i < len(quotetests); i++ { - tt := quotetests[i]; - if out := Quote(tt.in); out != tt.out { - t.Errorf("Quote(%s) = %s, want %s", tt.in, out, tt.out); - } - } -} - -type canBackquoteTest struct { - in string; - out bool; -} - -var canbackquotetests = []canBackquoteTest { - canBackquoteTest{ "`", false }, - canBackquoteTest{ string(0), false }, - canBackquoteTest{ string(1), false }, - canBackquoteTest{ string(2), false }, - canBackquoteTest{ string(3), false }, - canBackquoteTest{ string(4), false }, - canBackquoteTest{ string(5), false }, - canBackquoteTest{ string(6), false }, - canBackquoteTest{ string(7), false }, - canBackquoteTest{ string(8), false }, - canBackquoteTest{ string(9), true }, // \t - canBackquoteTest{ string(10), false }, - canBackquoteTest{ string(11), false }, - canBackquoteTest{ string(12), false }, - canBackquoteTest{ string(13), false }, - canBackquoteTest{ string(14), false }, - canBackquoteTest{ string(15), false }, - canBackquoteTest{ string(16), false }, - canBackquoteTest{ string(17), false }, - canBackquoteTest{ string(18), false }, - canBackquoteTest{ string(19), false }, - canBackquoteTest{ string(20), false }, - canBackquoteTest{ string(21), false }, - canBackquoteTest{ string(22), false }, - canBackquoteTest{ string(23), false }, - canBackquoteTest{ string(24), false }, - canBackquoteTest{ string(25), false }, - canBackquoteTest{ string(26), false }, - canBackquoteTest{ string(27), false }, - canBackquoteTest{ string(28), false }, - canBackquoteTest{ string(29), false }, - canBackquoteTest{ string(30), false }, - canBackquoteTest{ string(31), false }, - canBackquoteTest{ `' !"#$%&'()*+,-./:;<=>?@[\]^_{|}~`, true }, - canBackquoteTest{ `0123456789`, true }, - canBackquoteTest{ `ABCDEFGHIJKLMNOPQRSTUVWXYZ`, true }, - canBackquoteTest{ `abcdefghijklmnopqrstuvwxyz`, true }, - canBackquoteTest{ `☺`, true }, -} - -func TestCanBackquote(t *testing.T) { - for i := 0; i < len(canbackquotetests); i++ { - tt := canbackquotetests[i]; - if out := CanBackquote(tt.in); out != tt.out { - t.Errorf("CanBackquote(%q) = %v, want %v", tt.in, out, tt.out); - } - } -} - -var unquotetests = []quoteTest { - quoteTest{ `""`, "" }, - quoteTest{ `"a"`, "a" }, - quoteTest{ `"abc"`, "abc" }, - quoteTest{ `"☺"`, "☺" }, - quoteTest{ `"hello world"`, "hello world" }, - quoteTest{ `"\xFF"`, "\xFF" }, - quoteTest{ `"\377"`, "\377" }, - quoteTest{ `"\u1234"`, "\u1234" }, - quoteTest{ `"\U00010111"`, "\U00010111" }, - quoteTest{ `"\U0001011111"`, "\U0001011111" }, - quoteTest{ `"\a\b\f\n\r\t\v\\\""`, "\a\b\f\n\r\t\v\\\"" }, - quoteTest{ `"'"`, "'" }, - - quoteTest{ `'a'`, "a" }, - quoteTest{ `'☹'`, "☹" }, - quoteTest{ `'\a'`, "\a" }, - quoteTest{ `'\x10'`, "\x10" }, - quoteTest{ `'\377'`, "\377" }, - quoteTest{ `'\u1234'`, "\u1234" }, - quoteTest{ `'\U00010111'`, "\U00010111" }, - quoteTest{ `'\t'`, "\t" }, - quoteTest{ `' '`, " " }, - quoteTest{ `'\''`, "'" }, - quoteTest{ `'"'`, "\"" }, - - quoteTest{ "``", `` }, - quoteTest{ "`a`", `a` }, - quoteTest{ "`abc`", `abc` }, - quoteTest{ "`☺`", `☺` }, - quoteTest{ "`hello world`", `hello world` }, - quoteTest{ "`\\xFF`", `\xFF` }, - quoteTest{ "`\\377`", `\377` }, - quoteTest{ "`\\`", `\` }, - quoteTest{ "` `", ` ` }, - quoteTest{ "` `", ` ` }, -} - -var misquoted = []string { - ``, - `"`, - `"a`, - `"'`, - `b"`, - `"\"`, - `'\'`, - `'ab'`, - `"\x1!"`, - `"\U12345678"`, - `"\z"`, - "`", - "`xxx", - "`\"", - `"\'"`, - `'\"'`, -} - -func TestUnquote(t *testing.T) { - for i := 0; i < len(unquotetests); i++ { - tt := unquotetests[i]; - if out, err := Unquote(tt.in); err != nil && out != tt.out { - t.Errorf("Unquote(%s) = %q, %s want %q, nil", tt.in, out, err, tt.out); - } - } - - // run the quote tests too, backward - for i := 0; i < len(quotetests); i++ { - tt := quotetests[i]; - if in, err := Unquote(tt.out); in != tt.in { - t.Errorf("Unquote(%s) = %q, %s, want %q, nil", tt.out, in, err, tt.in); - } - } - - for i := 0; i < len(misquoted); i++ { - s := misquoted[i]; - if out, err := Unquote(s); out != "" || err != os.EINVAL { - t.Errorf("Unquote(%q) = %q, %s want %q, %s", s, out, err, "", os.EINVAL); - } - } -} diff --git a/src/lib/strconv/testfp.txt b/src/lib/strconv/testfp.txt deleted file mode 100644 index 08d3c4ef0..000000000 --- a/src/lib/strconv/testfp.txt +++ /dev/null @@ -1,181 +0,0 @@ -# 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/lib/strings/Makefile b/src/lib/strings/Makefile deleted file mode 100644 index b6660cfc7..000000000 --- a/src/lib/strings/Makefile +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m >Makefile - -D= - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - strings.$O\ - - -phases: a1 -_obj$D/strings.a: phases - -a1: $(O1) - $(AR) grc _obj$D/strings.a strings.$O - rm -f $(O1) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/strings.a - -$(O1): newpkg -$(O2): a1 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/strings.a - -packages: _obj$D/strings.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/strings.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/strings.a diff --git a/src/lib/strings/strings.go b/src/lib/strings/strings.go deleted file mode 100644 index 2e3dc0215..000000000 --- a/src/lib/strings/strings.go +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// A package of simple functions to manipulate strings. -package strings - -import "utf8" - -// Explode splits s into an array of UTF-8 sequences, one per Unicode character (still strings). -// Invalid UTF-8 sequences become correct encodings of U+FFF8. -func Explode(s string) []string { - a := make([]string, utf8.RuneCountInString(s)); - var size, rune int; - i := 0; - for len(s) > 0 { - rune, size = utf8.DecodeRuneInString(s); - s = s[size:len(s)]; - a[i] = string(rune); - i++; - } - 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]; - n := 0; - for i := 0; i+len(sep) <= len(s); i++ { - if s[i] == c && (len(sep) == 1 || 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 string) 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 || s[i:i+n] == sep) { - return i - } - } - return -1 -} - -// Split returns the array representing the substrings of s separated by string sep. Adjacent -// occurrences of sep produce empty substrings. If sep is empty, it is the same as Explode. -func Split(s, sep string) []string { - if sep == "" { - return Explode(s) - } - c := sep[0]; - start := 0; - n := Count(s, sep)+1; - a := make([]string, n); - na := 0; - for i := 0; i+len(sep) <= len(s); i++ { - if s[i] == c && (len(sep) == 1 || s[i:i+len(sep)] == sep) { - a[na] = s[start:i]; - na++; - start = i+len(sep); - i += len(sep)-1 - } - } - a[na] = s[start:len(s)]; - return a -} - -// Join concatenates the elements of a to create a single string. The separator string -// sep is placed between elements in the resulting string. -func Join(a []string, sep string) string { - if len(a) == 0 { - return "" - } - if len(a) == 1 { - return a[0] - } - n := len(sep) * (len(a)-1); - for i := 0; i < len(a); i++ { - n += len(a[i]) - } - - b := make([]byte, n); - bp := 0; - for i := 0; i < len(a); i++ { - s := a[i]; - for j := 0; j < len(s); j++ { - b[bp] = s[j]; - bp++ - } - if i + 1 < len(a) { - s = sep; - for j := 0; j < len(s); j++ { - b[bp] = s[j]; - bp++ - } - } - } - return string(b) -} - -// HasPrefix tests whether the string s begins with prefix. -func HasPrefix(s, prefix string) bool { - return len(s) >= len(prefix) && s[0:len(prefix)] == prefix -} - -// HasSuffix tests whether the string s ends with suffix. -func HasSuffix(s, suffix string) bool { - return len(s) >= len(suffix) && s[len(s)-len(suffix):len(s)] == suffix -} - -// Upper returns a copy of the string s, with all low ASCII lowercase letters -// converted to uppercase. -// TODO: full Unicode support -func UpperASCII(s string) string { - // Note, we can work byte-by-byte because UTF-8 multibyte characters - // don't use any low ASCII byte values. - b := make([]byte, len(s)); - for i := 0; i < len(s); i++ { - c := s[i]; - if 'a' <= c && c <= 'z' { - c -= 'a' - 'A'; - } - b[i] = c; - } - return string(b); -} - -// Upper returns a copy of the string s, with all low ASCII lowercase letters -// converted to lowercase. -// TODO: full Unicode support -func LowerASCII(s string) string { - // Note, we can work byte-by-byte because UTF-8 multibyte characters - // don't use any low ASCII byte values. - b := make([]byte, len(s)); - for i := 0; i < len(s); i++ { - c := s[i]; - if 'A' <= c && c <= 'Z' { - c += 'a' - 'A'; - } - b[i] = c; - } - return string(b); -} - -func isWhitespaceASCII(c byte) bool { - switch int(c) { - case ' ', '\t', '\r', '\n': - return true; - } - return false; -} - -// Trim returns a slice of the string s, with all leading and trailing whitespace -// removed. "Whitespace" for now defined as space, tab, CR, or LF. -// TODO: full Unicode whitespace support (need a unicode.IsWhitespace method) -func TrimSpaceASCII(s string) string { - // Note, we can work byte-by-byte because UTF-8 multibyte characters - // don't use any low ASCII byte values. - start, end := 0, len(s); - for start < end && isWhitespaceASCII(s[start]) { - start++; - } - for start < end && isWhitespaceASCII(s[end-1]) { - end--; - } - return s[start:end]; -} diff --git a/src/lib/strings/strings_test.go b/src/lib/strings/strings_test.go deleted file mode 100644 index 05e662032..000000000 --- a/src/lib/strings/strings_test.go +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright 2009 The Go Authors. 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 ( - "strings"; - "testing"; -) - -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 ExplodeTest struct { - s string; - a []string; -} -var explodetests = []ExplodeTest { - ExplodeTest{ abcd, []string{"a", "b", "c", "d"} }, - ExplodeTest{ faces, []string{"☺", "☻", "☹" } }, -} -func TestExplode(t *testing.T) { - for i := 0; i < len(explodetests); i++ { - tt := explodetests[i]; - a := Explode(tt.s); - if !eq(a, tt.a) { - t.Errorf("Explode(%q) = %v; want %v", tt.s, a, tt.a); - continue; - } - s := Join(a, ""); - if s != tt.s { - t.Errorf(`Join(Explode(%q), "") = %q`, tt.s, s); - } - } -} - -type SplitTest struct { - s string; - sep string; - a []string; -} -var splittests = []SplitTest { - SplitTest{ abcd, "a", []string{"", "bcd"} }, - SplitTest{ abcd, "z", []string{"abcd"} }, - SplitTest{ abcd, "", []string{"a", "b", "c", "d"} }, - SplitTest{ commas, ",", []string{"1", "2", "3", "4"} }, - SplitTest{ dots, "...", []string{"1", ".2", ".3", ".4"} }, - SplitTest{ faces, "☹", []string{"☺☻", ""} }, - SplitTest{ faces, "~", []string{faces} }, - SplitTest{ faces, "", []string{"☺", "☻", "☹"} }, -} -func TestSplit(t *testing.T) { - for i := 0; i < len(splittests); i++ { - tt := splittests[i]; - a := Split(tt.s, tt.sep); - if !eq(a, tt.a) { - t.Errorf("Split(%q, %q) = %v; want %v", tt.s, tt.sep, a, tt.a); - continue; - } - s := Join(a, tt.sep); - if s != tt.s { - t.Errorf("Join(Split(%q, %q), %q) = %q", tt.s, tt.sep, tt.sep, s); - } - } -} - -// 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 i, 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 upperASCIITests = []StringTest { - StringTest{"", ""}, - StringTest{"abc", "ABC"}, - StringTest{"AbC123", "ABC123"}, - StringTest{"azAZ09_", "AZAZ09_"} -} - -var lowerASCIITests = []StringTest { - StringTest{"", ""}, - StringTest{"abc", "abc"}, - StringTest{"AbC123", "abc123"}, - StringTest{"azAZ09_", "azaz09_"} -} - -var trimSpaceASCIITests = []StringTest { - StringTest{"", ""}, - StringTest{"abc", "abc"}, - StringTest{" ", ""}, - StringTest{" \t\r\n \t\t\r\r\n\n ", ""}, - StringTest{" \t\r\n x\t\t\r\r\n\n ", "x"}, - StringTest{" \t\r\n x\t\t\r\r\ny\n ", "x\t\t\r\r\ny"}, - StringTest{"1 \t\r\n2", "1 \t\r\n2"}, -} - -func TestUpperASCII(t *testing.T) { - runStringTests(t, UpperASCII, "UpperASCII", upperASCIITests); -} - -func TestLowerASCII(t *testing.T) { - runStringTests(t, LowerASCII, "LowerASCII", lowerASCIITests); -} - -func TestTrimSpaceASCII(t *testing.T) { - runStringTests(t, TrimSpaceASCII, "TrimSpaceASCII", trimSpaceASCIITests); -} - diff --git a/src/lib/sync/Makefile b/src/lib/sync/Makefile deleted file mode 100644 index 566853d57..000000000 --- a/src/lib/sync/Makefile +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m asm_${GOARCH}.s mutex.go >Makefile - -D= - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - asm_$(GOARCH).$O\ - mutex.$O\ - - -phases: a1 -_obj$D/sync.a: phases - -a1: $(O1) - $(AR) grc _obj$D/sync.a asm_$(GOARCH).$O mutex.$O - rm -f $(O1) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/sync.a - -$(O1): newpkg -$(O2): a1 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/sync.a - -packages: _obj$D/sync.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/sync.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/sync.a diff --git a/src/lib/sync/asm_386.s b/src/lib/sync/asm_386.s deleted file mode 100644 index f71182b75..000000000 --- a/src/lib/sync/asm_386.s +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// func cas(val *int32, old, new int32) bool -// Atomically: -// if *val == old { -// *val = new; -// return true; -// }else -// return false; -TEXT sync·cas(SB), 7, $0 - MOVL 4(SP), BX - MOVL 8(SP), AX - MOVL 12(SP), CX - LOCK - CMPXCHGL CX, 0(BX) - JZ ok - MOVL $0, 16(SP) - RET -ok: - MOVL $1, 16(SP) - RET diff --git a/src/lib/sync/asm_amd64.s b/src/lib/sync/asm_amd64.s deleted file mode 100644 index 07389dd3b..000000000 --- a/src/lib/sync/asm_amd64.s +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// func cas(val *int32, old, new int32) bool -// Atomically: -// if *val == old { -// *val = new; -// return true; -// }else -// return false; -TEXT sync·cas(SB), 7, $0 - MOVQ 8(SP), BX - MOVL 16(SP), AX - MOVL 20(SP), CX - LOCK - CMPXCHGL CX, 0(BX) - JZ ok - MOVL $0, 24(SP) - RET -ok: - MOVL $1, 24(SP) - RET diff --git a/src/lib/sync/mutex.go b/src/lib/sync/mutex.go deleted file mode 100644 index 5a6311a83..000000000 --- a/src/lib/sync/mutex.go +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// The sync package provides basic synchronization primitives -// such as mutual exclusion locks. These are intended for use -// by low-level library routines. Higher-level synchronization -// is better done via channels and communication. -package sync - -func cas(val *int32, old, new int32) bool -func semacquire(*int32) -func semrelease(*int32) - -// A Mutex is a mutual exclusion lock. -// Mutexes can be created as part of other structures; -// the zero value for a Mutex is an unlocked mutex. -type Mutex struct { - key int32; - sema int32; -} - -func xadd(val *int32, delta int32) (new int32) { - for { - v := *val; - if cas(val, v, v+delta) { - return v+delta; - } - } - panic("unreached") -} - -// Lock locks m. -// If the lock is already in use, the calling goroutine -// blocks until the mutex is available. -func (m *Mutex) Lock() { - if xadd(&m.key, 1) == 1 { - // changed from 0 to 1; we hold lock - return; - } - semacquire(&m.sema); -} - -// Unlock unlocks m. -// It is a run-time error if m is not locked on entry to Unlock. -// -// A locked Mutex is not associated with a particular goroutine. -// It is allowed for one goroutine to lock a Mutex and then -// arrange for another goroutine to unlock it. -func (m *Mutex) Unlock() { - if xadd(&m.key, -1) == 0 { - // changed from 1 to 0; no contention - return; - } - semrelease(&m.sema); -} - -// Stub implementation of r/w locks. -// This satisfies the semantics but -// is not terribly efficient. - -// The next comment goes in the BUGS section of the document, -// in its own paragraph, without the (rsc) tag. - -// BUG(rsc): RWMutex does not (yet) allow multiple readers; -// instead it behaves as if RLock and RUnlock were Lock and Unlock. - -// 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 { - m Mutex; -} - -// RLock locks rw for reading. -// If the lock is already locked for writing or there is a writer already waiting -// to acquire the lock, RLock blocks until the writer has released the lock. -func (rw *RWMutex) RLock() { - rw.m.Lock(); -} - -// 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() { - rw.m.Unlock(); -} - -// Lock locks rw for writing. -// If the lock is already locked for reading or writing, -// Lock blocks until the lock is available. -// To ensure that the lock eventually becomes available, -// a blocked Lock call excludes new readers from acquiring -// the lock. -func (rw *RWMutex) Lock() { - rw.m.Lock(); -} - -// Unlock unlocks rw for writing. -// It is a run-time error if rw is not locked for writing -// on entry to Unlock. -// -// Like for Mutexes, -// a locked RWMutex is not associated with a particular goroutine. -// It is allowed for one goroutine to RLock (Lock) an RWMutex and then -// arrange for another goroutine to RUnlock (Unlock) it. -func (rw *RWMutex) Unlock() { - rw.m.Unlock(); -} - diff --git a/src/lib/sync/mutex_test.go b/src/lib/sync/mutex_test.go deleted file mode 100644 index 819dbb9de..000000000 --- a/src/lib/sync/mutex_test.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2009 The Go 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 - -import ( - "sync"; - "testing" -) - -func HammerSemaphore(s *int32, cdone chan bool) { - for i := 0; i < 1000; i++ { - semacquire(s); - semrelease(s); - } - cdone <- true; -} - -func TestSemaphore(t *testing.T) { - s := new(int32); - *s = 1; - c := make(chan bool); - for i := 0; i < 10; i++ { - go HammerSemaphore(s, c); - } - for i := 0; i < 10; i++ { - <-c; - } -} - - -func HammerMutex(m *Mutex, cdone chan bool) { - for i := 0; i < 1000; 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, c); - } - for i := 0; i < 10; i++ { - <-c; - } -} - diff --git a/src/lib/syscall/Makefile b/src/lib/syscall/Makefile deleted file mode 100644 index a5cc042d7..000000000 --- a/src/lib/syscall/Makefile +++ /dev/null @@ -1,97 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m asm_${GOOS}_${GOARCH}.s errstr.go exec.go syscall.go syscall_${GOOS}.go syscall_${GOOS}_${GOARCH}.go zerrors_${GOOS}_${GOARCH}.go zsyscall_${GOOS}_${GOARCH}.go zsysnum_${GOOS}_${GOARCH}.go ztypes_${GOOS}_${GOARCH}.go >Makefile - -D= - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - asm_$(GOOS)_$(GOARCH).$O\ - syscall.$O\ - zerrors_$(GOOS)_$(GOARCH).$O\ - zsysnum_$(GOOS)_$(GOARCH).$O\ - ztypes_$(GOOS)_$(GOARCH).$O\ - -O2=\ - errstr.$O\ - zsyscall_$(GOOS)_$(GOARCH).$O\ - -O3=\ - syscall_$(GOOS)_$(GOARCH).$O\ - -O4=\ - syscall_$(GOOS).$O\ - -O5=\ - exec.$O\ - - -phases: a1 a2 a3 a4 a5 -_obj$D/syscall.a: phases - -a1: $(O1) - $(AR) grc _obj$D/syscall.a asm_$(GOOS)_$(GOARCH).$O syscall.$O zerrors_$(GOOS)_$(GOARCH).$O zsysnum_$(GOOS)_$(GOARCH).$O ztypes_$(GOOS)_$(GOARCH).$O - rm -f $(O1) - -a2: $(O2) - $(AR) grc _obj$D/syscall.a errstr.$O zsyscall_$(GOOS)_$(GOARCH).$O - rm -f $(O2) - -a3: $(O3) - $(AR) grc _obj$D/syscall.a syscall_$(GOOS)_$(GOARCH).$O - rm -f $(O3) - -a4: $(O4) - $(AR) grc _obj$D/syscall.a syscall_$(GOOS).$O - rm -f $(O4) - -a5: $(O5) - $(AR) grc _obj$D/syscall.a exec.$O - rm -f $(O5) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/syscall.a - -$(O1): newpkg -$(O2): a1 -$(O3): a2 -$(O4): a3 -$(O5): a4 -$(O6): a5 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/syscall.a - -packages: _obj$D/syscall.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/syscall.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/syscall.a diff --git a/src/lib/syscall/PORT b/src/lib/syscall/PORT deleted file mode 100755 index f3addcdb0..000000000 --- a/src/lib/syscall/PORT +++ /dev/null @@ -1,124 +0,0 @@ -#!/bin/sh -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# 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 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. -# -# * types_${GOOS}_${GOARCH}.c -# -# Same as types_${GOOS}_${GOARCH}.go except that it contains -# definitions specific to ${GOOS} one one particular architecture. -# -# * zerror_${GOOS}_${GOARCH}.go -# -# This machine-generated file defines the system's error numbers, -# error strings, and signal numbers. The generator is "mkerrors". -# Usually no arguments are needed, but mkerrors will pass its -# arguments on to godefs. -# -# * zsyscall_${GOOS}_${GOARCH}.go -# -# Generated by mksyscall; 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" -mkerrors="mkerrors" - -case "$GOOSARCH" in -_* | *_ | _) - echo 'undefined $GOOS_$GOARCH:' "$GOOSARCH" 1>&2 - exit 1 - ;; -darwin_386) - mksyscall="mksyscall -l32" - mksysnum="mksysnum_darwin /home/rsc/pub/xnu-1228/bsd/kern/syscalls.master" - mktypes="godefs -gsyscall -f-m32" - ;; -darwin_amd64) - mksysnum="mksysnum_darwin /home/rsc/pub/xnu-1228/bsd/kern/syscalls.master" - mktypes="godefs -gsyscall -f-m64" - mkerrors="mkerrors" - ;; -linux_386) - mksysnum="mksysnum_linux /usr/include/asm/unistd_32.h" - mktypes="godefs -gsyscall -f-m32" - ;; -linux_amd64) - mksysnum="mksysnum_linux /usr/include/asm/unistd_64.h" - mktypes="godefs -gsyscall -f-m64" - ;; -*) - echo 'unrecognized $GOOS_$GOARCH: ' "$GOOSARCH" 1>&2 - exit 1 - ;; -esac - -echo "$mkerrors >zerrors_$GOOSARCH.go" -echo "$mksyscall syscall_$GOOS.go syscall_$GOOSARCH.go >zsyscall_$GOOSARCH.go" -echo "$mksysnum >zsysnum_$GOOSARCH.go" -echo "$mktypes types_$GOOS.c types_$GOOSARCH.c >ztypes_$GOOSARCH.go" - -port=$(ls *.go | grep -v _) -arch=$(ls *_$GOOSARCH.s *_$GOOSARCH.go *_$GOOS.go) -all=$(ls $port $arch) # sort them -echo gobuild $all diff --git a/src/lib/syscall/asm_darwin_386.s b/src/lib/syscall/asm_darwin_386.s deleted file mode 100644 index a8ec5b00c..000000000 --- a/src/lib/syscall/asm_darwin_386.s +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2009 The Go 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·Syscall(SB),7,$0 - CALL sys·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 sys·exitsyscall(SB) - RET -ok: - MOVL AX, 20(SP) // r1 - MOVL DX, 24(SP) // r2 ??? - MOVL $0, 28(SP) // errno - CALL sys·exitsyscall(SB) - RET - -TEXT syscall·Syscall6(SB),7,$0 - CALL sys·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 sys·exitsyscall(SB) - RET -ok6: - MOVL AX, 32(SP) // r1 - MOVL DX, 36(SP) // r2 ??? - MOVL $0, 40(SP) // errno - CALL sys·exitsyscall(SB) - RET - -TEXT syscall·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 diff --git a/src/lib/syscall/asm_darwin_amd64.s b/src/lib/syscall/asm_darwin_amd64.s deleted file mode 100644 index e1527977f..000000000 --- a/src/lib/syscall/asm_darwin_amd64.s +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// -// 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·Syscall(SB),7,$0 - CALL sys·entersyscall(SB) - MOVQ 16(SP), DI - MOVQ 24(SP), SI - MOVQ 32(SP), DX - 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 sys·exitsyscall(SB) - RET -ok: - MOVQ AX, 40(SP) // r1 - MOVQ DX, 48(SP) // r2 - MOVQ $0, 56(SP) // errno - CALL sys·exitsyscall(SB) - RET - -TEXT syscall·Syscall6(SB),7,$0 - CALL sys·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 sys·exitsyscall(SB) - RET -ok6: - MOVQ AX, 64(SP) // r1 - MOVQ DX, 72(SP) // r2 - MOVQ $0, 80(SP) // errno - CALL sys·exitsyscall(SB) - RET - -TEXT syscall·RawSyscall(SB),7,$0 - MOVQ 16(SP), DI - MOVQ 24(SP), SI - MOVQ 32(SP), DX - 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 diff --git a/src/lib/syscall/asm_linux_386.s b/src/lib/syscall/asm_linux_386.s deleted file mode 100644 index c6b01792d..000000000 --- a/src/lib/syscall/asm_linux_386.s +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// -// System calls for 386, Linux -// - -// func Syscall(trap int64, a1, a2, a3 int64) (r1, r2, err int64); -// Trap # in AX, args in BX CX DX SI DI, return in AX - -TEXT syscall·Syscall(SB),7,$0 - CALL sys·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 sys·exitsyscall(SB) - RET -ok: - MOVL AX, 20(SP) // r1 - MOVL DX, 24(SP) // r2 - MOVL $0, 28(SP) // errno - CALL sys·exitsyscall(SB) - RET - -// Actually Syscall5 but the rest of the code expects it to be named Syscall6. -TEXT syscall·Syscall6(SB),7,$0 - CALL sys·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 - // 28(SP) is ignored - 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 sys·exitsyscall(SB) - RET -ok6: - MOVL AX, 32(SP) // r1 - MOVL DX, 36(SP) // r2 - MOVL $0, 40(SP) // errno - CALL sys·exitsyscall(SB) - RET - -TEXT syscall·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 - CALL sys·exitsyscall(SB) - RET -ok1: - MOVL AX, 20(SP) // r1 - MOVL DX, 24(SP) // r2 - MOVL $0, 28(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 syscall·socketcall(SB),7,$0 - CALL sys·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, 28(SP) // n - NEGL AX - MOVL AX, 32(SP) // errno - CALL sys·exitsyscall(SB) - RET -oksock: - MOVL AX, 28(SP) // n - MOVL $0, 32(SP) // errno - CALL sys·exitsyscall(SB) - RET diff --git a/src/lib/syscall/asm_linux_amd64.s b/src/lib/syscall/asm_linux_amd64.s deleted file mode 100644 index cb93b481a..000000000 --- a/src/lib/syscall/asm_linux_amd64.s +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// -// 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·Syscall(SB),7,$0 - CALL sys·entersyscall(SB) - MOVQ 16(SP), DI - MOVQ 24(SP), SI - MOVQ 32(SP), DX - 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 sys·exitsyscall(SB) - RET -ok: - MOVQ AX, 40(SP) // r1 - MOVQ DX, 48(SP) // r2 - MOVQ $0, 56(SP) // errno - CALL sys·exitsyscall(SB) - RET - -TEXT syscall·Syscall6(SB),7,$0 - CALL sys·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 sys·exitsyscall(SB) - RET -ok6: - MOVQ AX, 64(SP) // r1 - MOVQ DX, 72(SP) // r2 - MOVQ $0, 80(SP) // errno - CALL sys·exitsyscall(SB) - RET - -TEXT syscall·RawSyscall(SB),7,$0 - MOVQ 16(SP), DI - MOVQ 24(SP), SI - MOVQ 32(SP), DX - 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 diff --git a/src/lib/syscall/errstr.go b/src/lib/syscall/errstr.go deleted file mode 100644 index 67a529d34..000000000 --- a/src/lib/syscall/errstr.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package syscall - -import "syscall" - -func str(val int) string { // do it here rather than with fmt to avoid dependency - if val < 0 { - return "-" + str(-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:len(buf)]); -} - -func Errstr(errno int) string { - if errno < 0 || errno >= int(len(errors)) { - return "error " + str(errno) - } - return errors[errno] -} - diff --git a/src/lib/syscall/exec.go b/src/lib/syscall/exec.go deleted file mode 100644 index 58fb05863..000000000 --- a/src/lib/syscall/exec.go +++ /dev/null @@ -1,305 +0,0 @@ -// Copyright 2009 The Go 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"; - "syscall"; - "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 StringArrayPtr(ss []string) []*byte { - bb := make([]*byte, len(ss)+1); - for i := 0; i < len(ss); i++ { - bb[i] = StringBytePtr(ss[i]); - } - bb[len(ss)] = nil; - return bb; -} - -func CloseOnExec(fd int) { - fcntl(fd, F_SETFD, FD_CLOEXEC); -} - -func SetNonblock(fd int, nonblocking bool) (errno int) { - flag, err := fcntl(fd, F_GETFL, 0); - if err != 0 { - return err; - } - if nonblocking { - flag |= O_NONBLOCK; - } else { - flag &= ^O_NONBLOCK; - } - flag, err = fcntl(fd, F_SETFL, flag); - return err; -} - - -// 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 []*byte, envv []*byte, dir *byte, fd []int, pipe int) - (pid int, err int) -{ - // Declare all variables at top in case any - // declarations require heap allocation (e.g., err1). - var r1, r2, err1 uintptr; - var nextfd int; - var i int; - - darwin := OS == "darwin"; - - // About to call fork. - // No more allocation or calls of non-assembly functions. - 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. - - // Chdir - if dir != nil { - r1, r2, 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 { - r1, r2, 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) { - r1, r2, 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. - r1, r2, 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. - r1, r2, 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); - } - - // Time to exec. - r1, r2, 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)), uintptr(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"); -} - -// Combination of fork and exec, careful to be thread safe. -func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []int) - (pid int, err int) -{ - var p [2]int; - var r1 int; - var n int; - var err1 uintptr; - var wstatus WaitStatus; - - p[0] = -1; - p[1] = -1; - - // Convert args to C form. - argv0p := StringBytePtr(argv0); - argvp := StringArrayPtr(argv); - envvp := StringArrayPtr(envv); - var dirp *byte; - if len(dir) > 0 { - dirp = StringBytePtr(dir); - } - - // Acquire the fork lock so that no other threads - // create new fds that are not yet close-on-exec - // before we fork. - ForkLock.Lock(); - - // Allocate child status pipe close on exec. - if err = Pipe(&p); err != 0 { - goto error; - } - var val int; - if val, err = fcntl(p[0], F_SETFD, FD_CLOEXEC); err != 0 { - goto error; - } - if val, err = fcntl(p[1], F_SETFD, FD_CLOEXEC); err != 0 { - goto error; - } - - // Kick off child. - pid, err = forkAndExecInChild(argv0p, argvp, envvp, dirp, fd, p[1]); - if err != 0 { - error: - if p[0] >= 0 { - Close(p[0]); - Close(p[1]); - } - ForkLock.Unlock(); - return 0, err - } - ForkLock.Unlock(); - - // Read child error status from pipe. - Close(p[1]); - n, err = read(p[0], (*byte)(unsafe.Pointer(&err1)), unsafe.Sizeof(err1)); - Close(p[0]); - if err != 0 || n != 0 { - if n == unsafe.Sizeof(err1) { - err = int(err1); - } - if err == 0 { - err = EPIPE; - } - - // Child failed; wait for it to exit, to make sure - // the zombies don't accumulate. - pid1, err1 := Wait4(pid, &wstatus, 0, nil); - for err1 == EINTR { - pid1, err1 = Wait4(pid, &wstatus, 0, nil); - } - return 0, err - } - - // Read got EOF, so pipe closed on exec, so exec succeeded. - return pid, 0 -} - -// Ordinary exec. -func Exec(argv0 string, argv []string, envv []string) (err int) { - r1, r2, err1 := RawSyscall(SYS_EXECVE, - uintptr(unsafe.Pointer(StringBytePtr(argv0))), - uintptr(unsafe.Pointer(&StringArrayPtr(argv)[0])), - uintptr(unsafe.Pointer(&StringArrayPtr(envv)[0]))); - return int(err1); -} - diff --git a/src/lib/syscall/mkerrors b/src/lib/syscall/mkerrors deleted file mode 100755 index 015f02145..000000000 --- a/src/lib/syscall/mkerrors +++ /dev/null @@ -1,94 +0,0 @@ -#!/bin/sh -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - - -# Generate Go code listing error values (ENAMETOOLONG etc) -# and signal values (SIGALRM etc). They're unrelated except -# that we use the same method for finding them. - -errors=$( - echo '#include ' | - # The gcc command line prints all the #defines - # it encounters while processing the input - gcc -x c - -E -dM | - egrep -h '#define E[A-Z0-9_]+ ' $files | - sed 's/#define //; s/ .*//' -) - -signals=$( - echo '#include ' | - gcc -x c - -E -dM | - egrep -h '#define SIG[^_]' | - egrep -v '#define (SIGEV_|SIGSTKSZ|SIGRT(MIN|MAX))' | - sed 's/#define //; s/ .*//' -) - -# Write godefs input. -( - echo '#include ' - echo '#include ' - echo 'enum {' - for i in $errors $signals - do - echo '$'"$i = $i," - done - echo '};' -) >_errors.c - -echo '// mkerrors' "$@" -echo '// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT' -echo -godefs -gsyscall "$@" _errors.c - -# Run C program to print error strings. -( - echo " -#include -#include -#include -#include - -#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 - echo ' '$i, - done - - echo ' -}; - -int -main(void) -{ - int i, j, e; - char buf[1024]; - - printf("\n\n// Error table\n"); - printf("var errors = [...]string {\n"); - for(i=0; i bad, but STREAM -> STREAM. - if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z) - buf[0] += a - A; - printf("\t%d: \"%s\",\n", e, buf); - next:; - } - printf("}\n\n"); -} - -' -) >_errors.c - -gcc -o _errors _errors.c && ./_errors -rm -f _errors.c _errors diff --git a/src/lib/syscall/mksyscall b/src/lib/syscall/mksyscall deleted file mode 100755 index 850fc1e3f..000000000 --- a/src/lib/syscall/mksyscall +++ /dev/null @@ -1,170 +0,0 @@ -#!/usr/bin/perl -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# 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. - -$cmdline = "mksyscall " . join(' ', @ARGV); -$errors = 0; -$_32bit = ""; - -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 [-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); -} - -$text = ""; -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*(?:=\s*(SYS_[A-Z0-9_]+))?$/) { - print STDERR "$ARGV:$.: malformed //sys declaration\n"; - $errors = 1; - next; - } - my ($func, $in, $out, $sysname) = ($1, $2, $3, $4); - - # Split argument lists on comma. - my @in = parseparamlist($in); - my @out = parseparamlist($out); - - # Go function header. - $text .= sprintf "func %s(%s) (%s) {\n", $func, join(', ', @in), join(', ', @out); - - # 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 nil in that case. - $text .= "\tvar _p$n *$1;\n"; - $text .= "\tif len($name) > 0 { _p$n = \&${name}[0]; }\n"; - push @args, "uintptr(unsafe.Pointer(_p$n))", "uintptr(len($name))"; - $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(@args <= 3) { - while(@args < 3) { - push @args, "0"; - } - } elsif(@args <= 6) { - $asm = "Syscall6"; - while(@args < 6) { - 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); - $text .= "\tr0, r1, e1 := $asm($sysname, $args);\n"; - - # Assign return values. - for(my $i=0; $i<@out; $i++) { - my $p = $out[$i]; - my ($name, $type) = parseparam($p); - my $reg = ""; - if($name eq "errno") { - $reg = "e1"; - } else { - $reg = sprintf("r%d", $i); - } - if($type eq "bool") { - $reg = "$reg != 0"; - } - $text .= "\t$name = $type($reg);\n"; - } - - $text .= "\treturn;\n"; - $text .= "}\n\n"; -} - -if($errors) { - exit 1; -} - -print <){ - if(/^([0-9]+)\s+ALL\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"; - } - - print " $name = $num; // $proto\n"; - } -} - -print <){ - if(/^#define __NR_(\w+)\s+([0-9]+)/){ - my $name = "SYS_$1"; - my $num = $2; - $name =~ y/a-z/A-Z/; - print " $name = $num;\n"; - } -} - -print < 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]); -} - -// 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; -} - -//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; -} - -//sys 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(rsc): How does 386 return an int64 newoffset? -//sys lseek(fd int, offset int64, whence int) (newoffset uintptr, errno int) -func Seek(fd int, offset int64, whence int) (newoffset int64, errno int) { - n, e := lseek(fd, offset, whence); - return int64(n), e; -} - -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) -//sys socket(domain int, typ int, proto int) (fd int, errno int) -//sys setsockopt(s int, level int, name int, val uintptr, vallen 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; - 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); - 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 anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, int) { - switch rsa.Addr.Family { - 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 := (*[len(pp.Path)]byte)(unsafe.Pointer(&pp.Path[0])); - sa.Name = string(bytes[0:n]); - return sa, 0; - - case AF_INET: - pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa)); - sa := new(SockaddrInet4); - p := (*[2]byte)(unsafe.Pointer(&pp.Port)); - sa.Port = int(p[0])<<8 + int(p[1]); - for i := 0; i < len(sa.Addr); i++ { - sa.Addr[i] = pp.Addr[i]; - } - return sa, 0; - - case AF_INET6: - pp := (*RawSockaddrInet6)(unsafe.Pointer(rsa)); - sa := new(SockaddrInet6); - p := (*[2]byte)(unsafe.Pointer(&pp.Port)); - sa.Port = int(p[0])<<8 + int(p[1]); - for i := 0; i < len(sa.Addr); i++ { - sa.Addr[i] = pp.Addr[i]; - } - return sa, 0; - } - return nil, EAFNOSUPPORT; -} - -func 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 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 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)); -} - -//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); -} - -// TODO: wrap -// Acct(name nil-string) (errno int) -// Futimes(fd int, timeval *Timeval) (errno int) // Pointer to 2 timevals! -// Gethostuuid(uuid *byte, timeout *Timespec) (errno int) -// Getpeername(fd int, addr *Sockaddr, addrlen *int) (errno int) -// Getsockname(fd int, addr *Sockaddr, addrlen *int) (errno int) -// Getsockopt(s int, level int, name int, val *byte, vallen *int) (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) -// Munmap(addr *byte, len int) (errno int) -// Ptrace(req int, pid int, addr uintptr, data int) (ret uintptr, errno int) -// Recvfrom(s int, buf *byte, nbuf int, flags int, from *Sockaddr, fromlen *int) (n int, errno int) -// Recvmsg(s int, msg *Msghdr, flags int) (n int, errno int) -// Sendmsg(s int, msg *Msghdr, flags int) (n int, errno int) -// Sendto(s int, buf *byte, nbuf int, flags int, to *Sockaddr, addrlen int) (errno int) -// Utimes(path string, timeval *Timeval) (errno int) // Pointer to 2 timevals! -//sys fcntl(fd int, cmd int, arg int) (val int, errno int) - - -/* - * Exposed directly - */ -//sys Access(path string, flags int) (errno int) -//sys Adjtime(delta *Timeval, olddelta *Timeval) (errno int) -//sys Chdir(path string) (errno int) -//sys Chflags(path string, flags int) (errno int) -//sys Chmod(path string, mode int) (errno int) -//sys Chown(path string, uid int, gid int) (errno int) -//sys Chroot(path string) (errno int) -//sys Close(fd int) (errno int) -//sys Dup(fd int) (nfd int, errno int) -//sys 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 int) (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) -//sys Getegid() (egid int) -//sys Geteuid() (uid int) -//sys Getfsstat(buf []Statfs_t, flags int) (n int, errno int) = SYS_GETFSSTAT64 -//sys Getgid() (gid int) -//sys Getpgid(pid int) (pgid int, errno int) -//sys Getpgrp() (pgrp int) -//sys Getpid() (pid int) -//sys Getppid() (ppid int) -//sys Getpriority(which int, who int) (prio int, errno int) -//sys Getrlimit(which int, lim *Rlimit) (errno int) -//sys Getrusage(who int, rusage *Rusage) (errno int) -//sys Getsid(pid int) (sid int, errno int) -//sys Getuid() (uid int) -//sys Issetugid() (tainted bool) -//sys Kill(pid int, signum int, posix 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_LSTAT64 -//sys Mkdir(path string, mode int) (errno int) -//sys Mkfifo(path string, mode int) (errno int) -//sys Mknod(path string, mode int, dev int) (errno int) -//sys Open(path string, mode int, perm int) (fd int, errno int) -//sys 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 Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (errno int) -//sys Setegid(egid int) (errno int) -//sys Seteuid(euid int) (errno int) -//sys Setgid(gid int) (errno int) -//sys Setlogin(name string) (errno int) -//sys Setpgid(pid int, pgid int) (errno int) -//sys Setpriority(which int, who int, prio int) (errno int) -//sys Setprivexec(flag int) (errno int) -//sys Setregid(rgid int, egid int) (errno int) -//sys Setreuid(ruid int, euid int) (errno int) -//sys Setrlimit(which int, lim *Rlimit) (errno int) -//sys Setsid() (pid int, errno int) -//sys Settimeofday(tp *Timeval) (errno int) -//sys 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) (errno 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 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 -// __Sysctl -// 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/lib/syscall/syscall_darwin_386.go b/src/lib/syscall/syscall_darwin_386.go deleted file mode 100644 index 5633d7c03..000000000 --- a/src/lib/syscall/syscall_darwin_386.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2009 The Go Authors. 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 "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; -} - -//sys 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 = 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); -} diff --git a/src/lib/syscall/syscall_darwin_amd64.go b/src/lib/syscall/syscall_darwin_amd64.go deleted file mode 100644 index f7a93f121..000000000 --- a/src/lib/syscall/syscall_darwin_amd64.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2009 The Go Authors. 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 "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; -} - -//sys 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); -} diff --git a/src/lib/syscall/syscall_linux.go b/src/lib/syscall/syscall_linux.go deleted file mode 100644 index 50f3938d7..000000000 --- a/src/lib/syscall/syscall_linux.go +++ /dev/null @@ -1,636 +0,0 @@ -// Copyright 2009 The Go 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 ( - "syscall"; - "unsafe"; -) - -const OS = "linux" - -/* - * Wrapped - */ - -//sys 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 string, times *[2]Timeval) (errno int) -func Futimesat(dirfd int, path string, tv []Timeval) (errno int) { - if len(tv) != 2 { - return EINVAL; - } - return futimesat(dirfd, path, (*[2]Timeval)(unsafe.Pointer(&tv[0]))); -} - -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); - 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 -} - -//sys getgroups(n int, list *_Gid_t) (nn int, errno int) -//sys setgroups(n int, list *_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 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; -} - -//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); - n, err := Select(0, nil, nil, nil, &tv); - return err; -} - -// Implemented in syscall_linux_*.go -func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, errno int) -func bind(s int, addr uintptr, addrlen _Socklen) (errno int) -func connect(s int, addr uintptr, addrlen _Socklen) (errno int) -func socket(domain int, typ int, proto int) (fd int, errno int) -func setsockopt(s int, level int, name int, val uintptr, vallen int) (errno int) -func Listen(s int, n 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.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; - 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); - 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]); - } - if sa.raw.Path[0] == '@' { - sa.raw.Path[0] = 0; - } - - // length is family, name, NUL. - return uintptr(unsafe.Pointer(&sa.raw)), 1 + _Socklen(n) + 1, 0; -} - -func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, int) { - switch rsa.Addr.Family { - 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 := (*[len(pp.Path)]byte)(unsafe.Pointer(&pp.Path[0])); - sa.Name = string(bytes[0:n]); - return sa, 0; - - case AF_INET: - pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa)); - sa := new(SockaddrInet4); - p := (*[2]byte)(unsafe.Pointer(&pp.Port)); - sa.Port = int(p[0])<<8 + int(p[1]); - for i := 0; i < len(sa.Addr); i++ { - sa.Addr[i] = pp.Addr[i]; - } - return sa, 0; - - case AF_INET6: - pp := (*RawSockaddrInet6)(unsafe.Pointer(rsa)); - sa := new(SockaddrInet6); - p := (*[2]byte)(unsafe.Pointer(&pp.Port)); - sa.Port = int(p[0])<<8 + int(p[1]); - for i := 0; i < len(sa.Addr); i++ { - sa.Addr[i] = pp.Addr[i]; - } - return sa, 0; - } - return nil, EAFNOSUPPORT; -} - -func 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 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 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)); -} - -// Sendto -// Recvfrom -// Sendmsg -// Recvmsg -// Getsockname -// Getpeername -// Socketpair -// Getsockopt - -/* - * Direct access - */ -//sys Access(path string, mode int) (errno int) -//sys Acct(path string) (errno int) -//sys Adjtimex(buf *Timex) (state int, errno int) -//sys Chdir(path string) (errno int) -//sys Chmod(path string, mode int) (errno int) -//sys Chown(path string, uid int, gid int) (errno int) -//sys Chroot(path string) (errno int) -//sys Close(fd int) (errno int) -//sys Creat(path string, mode int) (fd int, errno int) -//sys Dup(oldfd int) (fd int, errno int) -//sys Dup2(oldfd int, newfd int) (fd int, errno int) -//sys EpollCreate(size int) (fd int, errno int) -//sys EpollCtl(epfd int, op int, fd int, event *EpollEvent) (errno int) -//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, errno int) -//sys Exit(code int) = SYS_EXIT_GROUP -//sys Faccessat(dirfd int, path string, mode int, flags int) (errno int) -//sys Fallocate(fd int, mode int, off int64, len int64) (errno int) -//sys Fchdir(fd int) (errno int) -//sys Fchmod(fd int, mode int) (errno int) -//sys Fchmodat(dirfd int, path string, mode int, flags int) (errno int) -//sys Fchown(fd int, uid int, gid 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 Fstat(fd int, stat *Stat_t) (errno int) -//sys Fstatfs(fd int, buf *Statfs_t) (errno int) -//sys Fsync(fd int) (errno int) -//sys Ftruncate(fd int, length int64) (errno int) -//sys Getdents(fd int, buf []byte) (n int, errno int) = SYS_GETDENTS64 -//sys Getegid() (egid int) -//sys Geteuid() (euid int) -//sys Getgid() (gid int) -//sys Getpgid(pid int) (pgid int, errno int) -//sys Getpgrp() (pid int) -//sys Getpid() (pid int) -//sys Getppid() (ppid int) -//sys Getrlimit(resource int, rlim *Rlimit) (errno int) -//sys Getrusage(who int, rusage *Rusage) (errno int) -//sys Gettid() (tid int) -//sys Gettimeofday(tv *Timeval) (errno int) -//sys Getuid() (uid int) -//sys Ioperm(from int, num int, on int) (errno int) -//sys Iopl(level int) (errno int) -//sys Kill(pid int, sig int) (errno int) -//sys Klogctl(typ int, buf []byte) (n int, errno int) = SYS_SYSLOG -//sys Lchown(path string, uid int, gid int) (errno int) -//sys Link(oldpath string, newpath string) (errno int) -//sys Lstat(path string, stat *Stat_t) (errno int) -//sys Mkdir(path string, mode int) (errno int) -//sys Mkdirat(dirfd int, path string, mode int) (errno int) -//sys Mknod(path string, mode int, dev int) (errno int) -//sys Mknodat(dirfd int, path string, mode int, dev int) (errno int) -//sys Nanosleep(time *Timespec, leftover *Timespec) (errno int) -//sys Open(path string, mode int, perm int) (fd int, errno int) -//sys Openat(dirfd int, path string, flags int, mode int) (fd int, errno int) -//sys Pause() (errno int) -//sys PivotRoot(newroot string, putold string) (errno int) = SYS_PIVOT_ROOT -//sys Pread(fd int, p []byte, offset int64) (n int, errno int) = SYS_PREAD64 -//sys Pwrite(fd int, p []byte, offset int64) (n int, errno int) = SYS_PWRITE64 -//sys Read(fd int, p []byte) (n int, errno int) -//sys Readlink(path string, buf []byte) (n int, errno int) -//sys Rename(oldpath string, newpath string) (errno int) -//sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (errno int) -//sys Rmdir(path string) (errno int) -//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 Setdomainname(p []byte) (errno int) -//sys Setfsgid(gid int) (errno int) -//sys Setfsuid(uid int) (errno int) -//sys Setgid(gid int) (errno int) -//sys Sethostname(p []byte) (errno int) -//sys Setpgid(pid int, pgid int) (errno int) -//sys Setregid(rgid int, egid int) (errno int) -//sys Setresgid(rgid int, egid int, sgid int) (errno int) -//sys Setresuid(ruid int, euid int, suid int) (errno int) -//sys Setreuid(ruid int, euid int) (errno int) -//sys Setrlimit(resource int, rlim *Rlimit) (errno int) -//sys Setsid() (pid int) -//sys Settimeofday(tv *Timeval) (errno int) -//sys Setuid(uid int) (errno int) -//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, errno int) -//sys Stat(path string, stat *Stat_t) (errno int) -//sys Statfs(path string, buf *Statfs_t) (errno int) -//sys Symlink(oldpath string, newpath string) (errno int) -//sys Sync() -//sys SyncFileRange(fd int, off int64, n int64, flags int) (errno int) -//sys Sysinfo(info *Sysinfo_t) (errno int) -//sys Tee(rfd int, wfd int, len int, flags int) (n int64, errno int) -//sys Tgkill(tgid int, tid int, sig int) (errno int) -//sys Time(t *Time_t) (tt Time_t, errno int) -//sys Times(tms *Tms) (ticks uintptr, errno int) -//sys Truncate(path string, length int64) (errno int) -//sys Umask(mask int) (oldmask int) -//sys Uname(buf *Utsname) (errno int) -//sys Unlink(path string) (errno int) -//sys Unlinkat(dirfd int, path string) (errno int) -//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) - -/* - * Unimplemented - */ -// AddKey -// AfsSyscall -// Alarm -// ArchPrctl -// Brk -// Capget -// Capset -// ClockGetres -// ClockGettime -// ClockNanosleep -// ClockSettime -// Clone -// CreateModule -// DeleteModule -// EpollCtlOld -// EpollPwait -// EpollWaitOld -// Eventfd -// Execve -// Fadvise64 -// Fgetxattr -// Flistxattr -// Flock -// Fork -// Fremovexattr -// Fsetxattr -// Futex -// GetKernelSyms -// GetMempolicy -// GetRobustList -// GetThreadArea -// Getitimer -// Getpmsg -// Getpriority -// Getxattr -// InotifyAddWatch -// InotifyInit -// InotifyRmWatch -// IoCancel -// IoDestroy -// IoGetevents -// IoSetup -// IoSubmit -// Ioctl -// IoprioGet -// IoprioSet -// KexecLoad -// Keyctl -// Lgetxattr -// Listxattr -// Llistxattr -// LookupDcookie -// Lremovexattr -// Lsetxattr -// Madvise -// Mbind -// MigratePages -// Mincore -// Mlock -// Mmap -// ModifyLdt -// Mount -// MovePages -// Mprotect -// MqGetsetattr -// MqNotify -// MqOpen -// MqTimedreceive -// MqTimedsend -// MqUnlink -// Mremap -// Msgctl -// Msgget -// Msgrcv -// Msgsnd -// Msync -// Munlock -// Munlockall -// Munmap -// Newfstatat -// Nfsservctl -// Personality -// Poll -// Ppoll -// Prctl -// Pselect6 -// Ptrace -// Putpmsg -// QueryModule -// Quotactl -// Readahead -// Readv -// Reboot -// 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 -// Sendfile -// 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/lib/syscall/syscall_linux_386.go b/src/lib/syscall/syscall_linux_386.go deleted file mode 100644 index 9bf3f9cf0..000000000 --- a/src/lib/syscall/syscall_linux_386.go +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package syscall - -import ( - "syscall"; - "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; -} - -// 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 accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, errno int) { - fd, errno = socketcall(_SOCKET, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0); - return; -} - -func bind(s int, addr uintptr, addrlen _Socklen) (errno int) { - var _ int; - _, errno = socketcall(_BIND, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0); - return; -} - -func connect(s int, addr uintptr, addrlen _Socklen) (errno int) { - var _ 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 = socketcall(_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto), 0, 0, 0); - return; -} - -func setsockopt(s int, level int, name int, val uintptr, vallen int) (errno int) { - var _ int; - _, errno = socketcall(_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0); - return; -} - -func Listen(s int, n int) (errno int) { - var _ int; - _, errno = socketcall(_LISTEN, uintptr(s), uintptr(n), 0, 0, 0, 0); - return; -} - diff --git a/src/lib/syscall/syscall_linux_amd64.go b/src/lib/syscall/syscall_linux_amd64.go deleted file mode 100644 index a2a58c35b..000000000 --- a/src/lib/syscall/syscall_linux_amd64.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package syscall - -import "syscall" - -//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) -//sys socket(domain int, typ int, proto int) (fd int, errno int) -//sys setsockopt(s int, level int, name int, val uintptr, vallen int) (errno int) -//sys Listen(s int, n int) (errno int) -//sys Shutdown(fd int, how int) (errno int) - -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.Sec = nsec/1e9; - tv.Usec = nsec%1e9 / 1e3; - return; -} - diff --git a/src/lib/syscall/types_darwin.c b/src/lib/syscall/types_darwin.c deleted file mode 100644 index 65afd6ca6..000000000 --- a/src/lib/syscall/types_darwin.c +++ /dev/null @@ -1,226 +0,0 @@ -// Copyright 2009 The Go 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 PORT. - */ - -#define __DARWIN_UNIX03 0 -#define KERNEL -#define _DARWIN_USE_64_BIT_INODE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Machine characteristics; for internal use. - -enum -{ - $sizeofPtr = sizeof(void*), - $sizeofShort = sizeof(short), - $sizeofInt = sizeof(int), - $sizeofLong = sizeof(long), - $sizeofLongLong = sizeof(long long), -}; - - -// Time - -typedef struct timespec $Timespec; -typedef struct timeval $Timeval; - -// Processes - -typedef struct rusage $Rusage; -typedef struct rlimit $Rlimit; - -typedef int $_C_int; -typedef gid_t $_Gid_t; - -// Files - -enum -{ - $O_RDONLY = O_RDONLY, - $O_WRONLY = O_WRONLY, - $O_RDWR = O_RDWR, - $O_APPEND = O_APPEND, - $O_ASYNC = O_ASYNC, - $O_CREAT = O_CREAT, - $O_NOCTTY = O_NOCTTY, - $O_NONBLOCK = O_NONBLOCK, - $O_SYNC = O_SYNC, - $O_TRUNC = O_TRUNC, - $O_CLOEXEC = 0, // not supported - - $F_GETFD = F_GETFD, - $F_SETFD = F_SETFD, - - $F_GETFL = F_GETFL, - $F_SETFL = F_SETFL, - - $FD_CLOEXEC = FD_CLOEXEC, - - $NAME_MAX = NAME_MAX -}; - -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_IFWHT = S_IFWHT, - $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 stat64 $Stat_t; -typedef struct statfs64 $Statfs_t; - -typedef struct dirent $Dirent; - -// Wait status. - -enum -{ - $WNOHANG = WNOHANG, - $WUNTRACED = WUNTRACED, - $WEXITED = WEXITED, - $WSTOPPED = WSTOPPED, - $WCONTINUED = WCONTINUED, - $WNOWAIT = WNOWAIT, -}; - -// Sockets - -enum -{ - $AF_UNIX = AF_UNIX, - $AF_INET = AF_INET, - $AF_DATAKIT = AF_DATAKIT, - $AF_INET6 = AF_INET6, - - $SOCK_STREAM = SOCK_STREAM, - $SOCK_DGRAM = SOCK_DGRAM, - $SOCK_RAW = SOCK_RAW, - $SOCK_SEQPACKET = SOCK_SEQPACKET, - - $SOL_SOCKET = SOL_SOCKET, - - $SO_REUSEADDR = SO_REUSEADDR, - $SO_KEEPALIVE = SO_KEEPALIVE, - $SO_DONTROUTE = SO_DONTROUTE, - $SO_BROADCAST = SO_BROADCAST, - $SO_USELOOPBACK = SO_USELOOPBACK, - $SO_LINGER = SO_LINGER, - $SO_REUSEPORT = SO_REUSEPORT, - $SO_SNDBUF = SO_SNDBUF, - $SO_RCVBUF = SO_RCVBUF, - $SO_SNDTIMEO = SO_SNDTIMEO, - $SO_RCVTIMEO = SO_RCVTIMEO, - $SO_NOSIGPIPE = SO_NOSIGPIPE, - - $IPPROTO_TCP = IPPROTO_TCP, - $IPPROTO_UDP = IPPROTO_UDP, - - $TCP_NODELAY = TCP_NODELAY, - - $SOMAXCONN = SOMAXCONN -}; - -typedef struct sockaddr_in $RawSockaddrInet4; -typedef struct sockaddr_in6 $RawSockaddrInet6; -typedef struct sockaddr_un $RawSockaddrUnix; -typedef struct sockaddr $RawSockaddr; - -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_any { - struct sockaddr addr; - char pad[sizeof(union sockaddr_all) - sizeof(struct sockaddr)]; -}; - -enum { - $SizeofSockaddrInet4 = sizeof(struct sockaddr_in), - $SizeofSockaddrInet6 = sizeof(struct sockaddr_in6), - $SizeofSockaddrAny = sizeof(struct sockaddr_any), - $SizeofSockaddrUnix = sizeof(struct sockaddr_un), -}; - -typedef struct sockaddr_any $RawSockaddrAny; -typedef socklen_t $_Socklen; -typedef struct linger $Linger; - -// Events (kqueue, kevent) - -enum { - // filters - $EVFILT_READ = EVFILT_READ, - $EVFILT_WRITE = EVFILT_WRITE, - $EVFILT_AIO = EVFILT_AIO, - $EVFILT_VNODE = EVFILT_VNODE, - $EVFILT_PROC = EVFILT_PROC, - $EVFILT_SIGNAL = EVFILT_SIGNAL, - $EVFILT_TIMER = EVFILT_TIMER, - $EVFILT_MACHPORT = EVFILT_MACHPORT, - $EVFILT_FS = EVFILT_FS, - - $EVFILT_SYSCOUNT = EVFILT_SYSCOUNT, - - // actions - $EV_ADD = EV_ADD, - $EV_DELETE = EV_DELETE, - $EV_DISABLE = EV_DISABLE, - $EV_RECEIPT = EV_RECEIPT, - - // flags - $EV_ONESHOT = EV_ONESHOT, - $EV_CLEAR = EV_CLEAR, - $EV_SYSFLAGS = EV_SYSFLAGS, - $EV_FLAG0 = EV_FLAG0, - $EV_FLAG1 = EV_FLAG1, - - // returned values - $EV_EOF = EV_EOF, - $EV_ERROR = EV_ERROR, -}; - -typedef struct kevent $Kevent_t; - -// Select - -typedef fd_set $FdSet; diff --git a/src/lib/syscall/types_darwin_386.c b/src/lib/syscall/types_darwin_386.c deleted file mode 100644 index 71f98e413..000000000 --- a/src/lib/syscall/types_darwin_386.c +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Nothing to see here. diff --git a/src/lib/syscall/types_darwin_amd64.c b/src/lib/syscall/types_darwin_amd64.c deleted file mode 100644 index 71f98e413..000000000 --- a/src/lib/syscall/types_darwin_amd64.c +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Nothing to see here. diff --git a/src/lib/syscall/types_linux.c b/src/lib/syscall/types_linux.c deleted file mode 100644 index 261772eac..000000000 --- a/src/lib/syscall/types_linux.c +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright 2009 The Go 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 PORT. - */ - -#define __DARWIN_UNIX03 0 -#define KERNEL - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// 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, -}; - - -// 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 int $_C_int; -typedef gid_t $_Gid_t; - -// Files - -enum -{ - $O_RDONLY = O_RDONLY, - $O_WRONLY = O_WRONLY, - $O_RDWR = O_RDWR, - $O_APPEND = O_APPEND, - $O_ASYNC = O_ASYNC, - $O_CREAT = O_CREAT, - $O_NOCTTY = O_NOCTTY, - $O_NONBLOCK = O_NONBLOCK, - $O_SYNC = O_SYNC, - $O_TRUNC = O_TRUNC, - $O_CLOEXEC = 0, // not supported - - $F_GETFD = F_GETFD, - $F_SETFD = F_SETFD, - - $F_GETFL = F_GETFL, - $F_SETFL = F_SETFL, - - $FD_CLOEXEC = FD_CLOEXEC, - - $NAME_MAX = NAME_MAX -}; - -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 dirent $Dirent; - -// Wait status. - -enum -{ - $WNOHANG = WNOHANG, - $WUNTRACED = WUNTRACED, - $WEXITED = WEXITED, - $WSTOPPED = WSTOPPED, - $WCONTINUED = WCONTINUED, - $WNOWAIT = WNOWAIT, -}; - -// Sockets - -enum -{ - $AF_UNIX = AF_UNIX, - $AF_INET = AF_INET, - $AF_INET6 = AF_INET6, - - $SOCK_STREAM = SOCK_STREAM, - $SOCK_DGRAM = SOCK_DGRAM, - $SOCK_RAW = SOCK_RAW, - $SOCK_SEQPACKET = SOCK_SEQPACKET, - - $SOL_SOCKET = SOL_SOCKET, - - $SO_REUSEADDR = SO_REUSEADDR, - $SO_KEEPALIVE = SO_KEEPALIVE, - $SO_DONTROUTE = SO_DONTROUTE, - $SO_BROADCAST = SO_BROADCAST, - $SO_LINGER = SO_LINGER, - $SO_SNDBUF = SO_SNDBUF, - $SO_RCVBUF = SO_RCVBUF, - $SO_SNDTIMEO = SO_SNDTIMEO, - $SO_RCVTIMEO = SO_RCVTIMEO, - - $IPPROTO_TCP = IPPROTO_TCP, - $IPPROTO_UDP = IPPROTO_UDP, - - $TCP_NODELAY = TCP_NODELAY, - - $SOMAXCONN = SOMAXCONN -}; - -typedef struct sockaddr_in $RawSockaddrInet4; -typedef struct sockaddr_in6 $RawSockaddrInet6; -typedef struct sockaddr_un $RawSockaddrUnix; -typedef struct sockaddr $RawSockaddr; - -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_any { - struct sockaddr addr; - char pad[sizeof(union sockaddr_all) - sizeof(struct sockaddr)]; -}; - -enum { - $SizeofSockaddrInet4 = sizeof(struct sockaddr_in), - $SizeofSockaddrInet6 = sizeof(struct sockaddr_in6), - $SizeofSockaddrAny = sizeof(struct sockaddr_any), - $SizeofSockaddrUnix = sizeof(struct sockaddr_un), -}; - -typedef struct sockaddr_any $RawSockaddrAny; -typedef socklen_t $_Socklen; -typedef struct linger $Linger; - -// Misc - -enum { - $EPOLLIN = EPOLLIN, - $EPOLLRDHUP = EPOLLRDHUP, - $EPOLLOUT = EPOLLOUT, - $EPOLLONESHOT = EPOLLONESHOT, - $EPOLL_CTL_MOD = EPOLL_CTL_MOD, - $EPOLL_CTL_ADD = EPOLL_CTL_ADD, - $EPOLL_CTL_DEL = EPOLL_CTL_DEL, -}; - -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/lib/syscall/types_linux_386.c b/src/lib/syscall/types_linux_386.c deleted file mode 100644 index 37ce7d76e..000000000 --- a/src/lib/syscall/types_linux_386.c +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Nothing to see here diff --git a/src/lib/syscall/types_linux_amd64.c b/src/lib/syscall/types_linux_amd64.c deleted file mode 100644 index 37ce7d76e..000000000 --- a/src/lib/syscall/types_linux_amd64.c +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Nothing to see here diff --git a/src/lib/syscall/zerrors_darwin_386.go b/src/lib/syscall/zerrors_darwin_386.go deleted file mode 100644 index bc2d17656..000000000 --- a/src/lib/syscall/zerrors_darwin_386.go +++ /dev/null @@ -1,260 +0,0 @@ -// mkerrors -// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT - -// godefs -gsyscall _errors.c - -// MACHINE GENERATED - DO NOT EDIT. - -package syscall - -// Constants -const ( - EMULTIHOP = 0x5f; - EAFNOSUPPORT = 0x2f; - EACCES = 0xd; - EDESTADDRREQ = 0x27; - EILSEQ = 0x5c; - ESPIPE = 0x1d; - EMLINK = 0x1f; - EPROGUNAVAIL = 0x4a; - ENOTTY = 0x19; - EBADF = 0x9; - ERANGE = 0x22; - ECANCELED = 0x59; - ETXTBSY = 0x1a; - ENOMEM = 0xc; - EINPROGRESS = 0x24; - ENOTEMPTY = 0x42; - ENOTBLK = 0xf; - EPROTOTYPE = 0x29; - ENOMSG = 0x5b; - ERPCMISMATCH = 0x49; - ENOTDIR = 0x14; - EALREADY = 0x25; - ETIMEDOUT = 0x3c; - ENEEDAUTH = 0x51; - ENODATA = 0x60; - EINTR = 0x4; - ENOLINK = 0x61; - EPERM = 0x1; - ENETDOWN = 0x32; - ESTALE = 0x46; - ENOTSOCK = 0x26; - ENOSR = 0x62; - EAUTH = 0x50; - ECHILD = 0xa; - EPIPE = 0x20; - ENOATTR = 0x5d; - EBADMSG = 0x5e; - EREMOTE = 0x47; - ETOOMANYREFS = 0x3b; - EPFNOSUPPORT = 0x2e; - EPROCUNAVAIL = 0x4c; - EADDRINUSE = 0x30; - ENETRESET = 0x34; - EISDIR = 0x15; - EIDRM = 0x5a; - EDEVERR = 0x53; - EINVAL = 0x16; - ESHUTDOWN = 0x3a; - EPWROFF = 0x52; - EOVERFLOW = 0x54; - EBUSY = 0x10; - EPROCLIM = 0x43; - EPROTO = 0x64; - ENODEV = 0x13; - EROFS = 0x1e; - E2BIG = 0x7; - EDEADLK = 0xb; - ECONNRESET = 0x36; - EBADMACHO = 0x58; - ENXIO = 0x6; - EBADRPC = 0x48; - ENAMETOOLONG = 0x3f; - ELAST = 0x67; - ESOCKTNOSUPPORT = 0x2c; - EADDRNOTAVAIL = 0x31; - ETIME = 0x65; - EPROTONOSUPPORT = 0x2b; - EIO = 0x5; - ENETUNREACH = 0x33; - EXDEV = 0x12; - EDQUOT = 0x45; - ENOSPC = 0x1c; - ENOEXEC = 0x8; - EMSGSIZE = 0x28; - EFTYPE = 0x4f; - EDOM = 0x21; - ENOSTR = 0x63; - EFBIG = 0x1b; - ESRCH = 0x3; - EHOSTDOWN = 0x40; - ENOLCK = 0x4d; - ENFILE = 0x17; - ENOSYS = 0x4e; - EBADARCH = 0x56; - ENOTCONN = 0x39; - ENOTSUP = 0x2d; - ECONNABORTED = 0x35; - EISCONN = 0x38; - ESHLIBVERS = 0x57; - EUSERS = 0x44; - ENOPROTOOPT = 0x2a; - EMFILE = 0x18; - ELOOP = 0x3e; - ENOBUFS = 0x37; - EFAULT = 0xe; - EWOULDBLOCK = 0x23; - EBADEXEC = 0x55; - ENOPOLICY = 0x67; - ECONNREFUSED = 0x3d; - EAGAIN = 0x23; - EEXIST = 0x11; - EPROGMISMATCH = 0x4b; - ENOENT = 0x2; - EHOSTUNREACH = 0x41; - EOPNOTSUPP = 0x66; - SIGBUS = 0xa; - SIGTTIN = 0x15; - SIGPROF = 0x1b; - SIGFPE = 0x8; - SIGHUP = 0x1; - SIGTTOU = 0x16; - SIGUSR1 = 0x1e; - SIGURG = 0x10; - SIGQUIT = 0x3; - SIGIO = 0x17; - SIGABRT = 0x6; - SIGINFO = 0x1d; - SIGUSR2 = 0x1f; - SIGTRAP = 0x5; - SIGVTALRM = 0x1a; - SIGSEGV = 0xb; - SIGCONT = 0x13; - SIGPIPE = 0xd; - SIGXFSZ = 0x19; - SIGCHLD = 0x14; - SIGSYS = 0xc; - SIGSTOP = 0x11; - SIGALRM = 0xe; - SIGTSTP = 0x12; - SIGEMT = 0x7; - SIGKILL = 0x9; - SIGXCPU = 0x18; - SIGILL = 0x4; - SIGINT = 0x2; - SIGIOT = 0x6; - SIGTERM = 0xf; - SIGWINCH = 0x1c; -) - -// Types - - -// Error table -var errors = [...]string { - 95: "EMULTIHOP (Reserved)", - 47: "address family not supported by protocol family", - 13: "permission denied", - 39: "destination address required", - 92: "illegal byte sequence", - 29: "illegal seek", - 31: "too many links", - 74: "RPC prog. not avail", - 25: "inappropriate ioctl for device", - 9: "bad file descriptor", - 34: "result too large", - 89: "operation canceled", - 26: "text file busy", - 12: "cannot allocate memory", - 36: "operation now in progress", - 66: "directory not empty", - 15: "block device required", - 41: "protocol wrong type for socket", - 91: "no message of desired type", - 73: "RPC version wrong", - 20: "not a directory", - 37: "operation already in progress", - 60: "operation timed out", - 81: "need authenticator", - 96: "no message available on STREAM", - 4: "interrupted system call", - 97: "ENOLINK (Reserved)", - 1: "operation not permitted", - 50: "network is down", - 70: "stale NFS file handle", - 38: "socket operation on non-socket", - 98: "no STREAM resources", - 80: "authentication error", - 10: "no child processes", - 32: "broken pipe", - 93: "attribute not found", - 94: "bad message", - 71: "too many levels of remote in path", - 59: "too many references: can't splice", - 46: "protocol family not supported", - 76: "bad procedure for program", - 48: "address already in use", - 52: "network dropped connection on reset", - 21: "is a directory", - 90: "identifier removed", - 83: "device error", - 22: "invalid argument", - 58: "can't send after socket shutdown", - 82: "device power is off", - 84: "value too large to be stored in data type", - 16: "resource busy", - 67: "too many processes", - 100: "protocol error", - 19: "operation not supported by device", - 30: "read-only file system", - 7: "argument list too long", - 11: "resource deadlock avoided", - 54: "connection reset by peer", - 88: "malformed Mach-o file", - 6: "device not configured", - 72: "RPC struct is bad", - 63: "file name too long", - 103: "policy not found", - 44: "socket type not supported", - 49: "can't assign requested address", - 101: "STREAM ioctl timeout", - 43: "protocol not supported", - 5: "input/output error", - 51: "network is unreachable", - 18: "cross-device link", - 69: "disc quota exceeded", - 28: "no space left on device", - 8: "exec format error", - 40: "message too long", - 79: "inappropriate file type or format", - 33: "numerical argument out of domain", - 99: "not a STREAM", - 27: "file too large", - 3: "no such process", - 64: "host is down", - 77: "no locks available", - 23: "too many open files in system", - 78: "function not implemented", - 86: "bad CPU type in executable", - 57: "socket is not connected", - 45: "operation not supported", - 53: "software caused connection abort", - 56: "socket is already connected", - 87: "shared library version mismatch", - 68: "too many users", - 42: "protocol not available", - 24: "too many open files", - 62: "too many levels of symbolic links", - 55: "no buffer space available", - 14: "bad address", - 35: "resource temporarily unavailable", - 85: "bad executable (or shared library)", - 61: "connection refused", - 17: "file exists", - 75: "program version wrong", - 2: "no such file or directory", - 65: "no route to host", - 102: "operation not supported on socket", -} - diff --git a/src/lib/syscall/zerrors_darwin_amd64.go b/src/lib/syscall/zerrors_darwin_amd64.go deleted file mode 100644 index bc2d17656..000000000 --- a/src/lib/syscall/zerrors_darwin_amd64.go +++ /dev/null @@ -1,260 +0,0 @@ -// mkerrors -// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT - -// godefs -gsyscall _errors.c - -// MACHINE GENERATED - DO NOT EDIT. - -package syscall - -// Constants -const ( - EMULTIHOP = 0x5f; - EAFNOSUPPORT = 0x2f; - EACCES = 0xd; - EDESTADDRREQ = 0x27; - EILSEQ = 0x5c; - ESPIPE = 0x1d; - EMLINK = 0x1f; - EPROGUNAVAIL = 0x4a; - ENOTTY = 0x19; - EBADF = 0x9; - ERANGE = 0x22; - ECANCELED = 0x59; - ETXTBSY = 0x1a; - ENOMEM = 0xc; - EINPROGRESS = 0x24; - ENOTEMPTY = 0x42; - ENOTBLK = 0xf; - EPROTOTYPE = 0x29; - ENOMSG = 0x5b; - ERPCMISMATCH = 0x49; - ENOTDIR = 0x14; - EALREADY = 0x25; - ETIMEDOUT = 0x3c; - ENEEDAUTH = 0x51; - ENODATA = 0x60; - EINTR = 0x4; - ENOLINK = 0x61; - EPERM = 0x1; - ENETDOWN = 0x32; - ESTALE = 0x46; - ENOTSOCK = 0x26; - ENOSR = 0x62; - EAUTH = 0x50; - ECHILD = 0xa; - EPIPE = 0x20; - ENOATTR = 0x5d; - EBADMSG = 0x5e; - EREMOTE = 0x47; - ETOOMANYREFS = 0x3b; - EPFNOSUPPORT = 0x2e; - EPROCUNAVAIL = 0x4c; - EADDRINUSE = 0x30; - ENETRESET = 0x34; - EISDIR = 0x15; - EIDRM = 0x5a; - EDEVERR = 0x53; - EINVAL = 0x16; - ESHUTDOWN = 0x3a; - EPWROFF = 0x52; - EOVERFLOW = 0x54; - EBUSY = 0x10; - EPROCLIM = 0x43; - EPROTO = 0x64; - ENODEV = 0x13; - EROFS = 0x1e; - E2BIG = 0x7; - EDEADLK = 0xb; - ECONNRESET = 0x36; - EBADMACHO = 0x58; - ENXIO = 0x6; - EBADRPC = 0x48; - ENAMETOOLONG = 0x3f; - ELAST = 0x67; - ESOCKTNOSUPPORT = 0x2c; - EADDRNOTAVAIL = 0x31; - ETIME = 0x65; - EPROTONOSUPPORT = 0x2b; - EIO = 0x5; - ENETUNREACH = 0x33; - EXDEV = 0x12; - EDQUOT = 0x45; - ENOSPC = 0x1c; - ENOEXEC = 0x8; - EMSGSIZE = 0x28; - EFTYPE = 0x4f; - EDOM = 0x21; - ENOSTR = 0x63; - EFBIG = 0x1b; - ESRCH = 0x3; - EHOSTDOWN = 0x40; - ENOLCK = 0x4d; - ENFILE = 0x17; - ENOSYS = 0x4e; - EBADARCH = 0x56; - ENOTCONN = 0x39; - ENOTSUP = 0x2d; - ECONNABORTED = 0x35; - EISCONN = 0x38; - ESHLIBVERS = 0x57; - EUSERS = 0x44; - ENOPROTOOPT = 0x2a; - EMFILE = 0x18; - ELOOP = 0x3e; - ENOBUFS = 0x37; - EFAULT = 0xe; - EWOULDBLOCK = 0x23; - EBADEXEC = 0x55; - ENOPOLICY = 0x67; - ECONNREFUSED = 0x3d; - EAGAIN = 0x23; - EEXIST = 0x11; - EPROGMISMATCH = 0x4b; - ENOENT = 0x2; - EHOSTUNREACH = 0x41; - EOPNOTSUPP = 0x66; - SIGBUS = 0xa; - SIGTTIN = 0x15; - SIGPROF = 0x1b; - SIGFPE = 0x8; - SIGHUP = 0x1; - SIGTTOU = 0x16; - SIGUSR1 = 0x1e; - SIGURG = 0x10; - SIGQUIT = 0x3; - SIGIO = 0x17; - SIGABRT = 0x6; - SIGINFO = 0x1d; - SIGUSR2 = 0x1f; - SIGTRAP = 0x5; - SIGVTALRM = 0x1a; - SIGSEGV = 0xb; - SIGCONT = 0x13; - SIGPIPE = 0xd; - SIGXFSZ = 0x19; - SIGCHLD = 0x14; - SIGSYS = 0xc; - SIGSTOP = 0x11; - SIGALRM = 0xe; - SIGTSTP = 0x12; - SIGEMT = 0x7; - SIGKILL = 0x9; - SIGXCPU = 0x18; - SIGILL = 0x4; - SIGINT = 0x2; - SIGIOT = 0x6; - SIGTERM = 0xf; - SIGWINCH = 0x1c; -) - -// Types - - -// Error table -var errors = [...]string { - 95: "EMULTIHOP (Reserved)", - 47: "address family not supported by protocol family", - 13: "permission denied", - 39: "destination address required", - 92: "illegal byte sequence", - 29: "illegal seek", - 31: "too many links", - 74: "RPC prog. not avail", - 25: "inappropriate ioctl for device", - 9: "bad file descriptor", - 34: "result too large", - 89: "operation canceled", - 26: "text file busy", - 12: "cannot allocate memory", - 36: "operation now in progress", - 66: "directory not empty", - 15: "block device required", - 41: "protocol wrong type for socket", - 91: "no message of desired type", - 73: "RPC version wrong", - 20: "not a directory", - 37: "operation already in progress", - 60: "operation timed out", - 81: "need authenticator", - 96: "no message available on STREAM", - 4: "interrupted system call", - 97: "ENOLINK (Reserved)", - 1: "operation not permitted", - 50: "network is down", - 70: "stale NFS file handle", - 38: "socket operation on non-socket", - 98: "no STREAM resources", - 80: "authentication error", - 10: "no child processes", - 32: "broken pipe", - 93: "attribute not found", - 94: "bad message", - 71: "too many levels of remote in path", - 59: "too many references: can't splice", - 46: "protocol family not supported", - 76: "bad procedure for program", - 48: "address already in use", - 52: "network dropped connection on reset", - 21: "is a directory", - 90: "identifier removed", - 83: "device error", - 22: "invalid argument", - 58: "can't send after socket shutdown", - 82: "device power is off", - 84: "value too large to be stored in data type", - 16: "resource busy", - 67: "too many processes", - 100: "protocol error", - 19: "operation not supported by device", - 30: "read-only file system", - 7: "argument list too long", - 11: "resource deadlock avoided", - 54: "connection reset by peer", - 88: "malformed Mach-o file", - 6: "device not configured", - 72: "RPC struct is bad", - 63: "file name too long", - 103: "policy not found", - 44: "socket type not supported", - 49: "can't assign requested address", - 101: "STREAM ioctl timeout", - 43: "protocol not supported", - 5: "input/output error", - 51: "network is unreachable", - 18: "cross-device link", - 69: "disc quota exceeded", - 28: "no space left on device", - 8: "exec format error", - 40: "message too long", - 79: "inappropriate file type or format", - 33: "numerical argument out of domain", - 99: "not a STREAM", - 27: "file too large", - 3: "no such process", - 64: "host is down", - 77: "no locks available", - 23: "too many open files in system", - 78: "function not implemented", - 86: "bad CPU type in executable", - 57: "socket is not connected", - 45: "operation not supported", - 53: "software caused connection abort", - 56: "socket is already connected", - 87: "shared library version mismatch", - 68: "too many users", - 42: "protocol not available", - 24: "too many open files", - 62: "too many levels of symbolic links", - 55: "no buffer space available", - 14: "bad address", - 35: "resource temporarily unavailable", - 85: "bad executable (or shared library)", - 61: "connection refused", - 17: "file exists", - 75: "program version wrong", - 2: "no such file or directory", - 65: "no route to host", - 102: "operation not supported on socket", -} - diff --git a/src/lib/syscall/zerrors_linux_386.go b/src/lib/syscall/zerrors_linux_386.go deleted file mode 100644 index f1e7e011d..000000000 --- a/src/lib/syscall/zerrors_linux_386.go +++ /dev/null @@ -1,316 +0,0 @@ -// mkerrors -// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT - -// godefs -gsyscall _errors.c - -// MACHINE GENERATED - DO NOT EDIT. - -package syscall - -// Constants -const ( - EMULTIHOP = 0x48; - EUNATCH = 0x31; - EAFNOSUPPORT = 0x61; - EREMCHG = 0x4e; - EACCES = 0xd; - EL3RST = 0x2f; - EDESTADDRREQ = 0x59; - EILSEQ = 0x54; - ESPIPE = 0x1d; - EMLINK = 0x1f; - EOWNERDEAD = 0x82; - ENOTTY = 0x19; - EBADE = 0x34; - EBADF = 0x9; - EBADR = 0x35; - EADV = 0x44; - ERANGE = 0x22; - ECANCELED = 0x7d; - ETXTBSY = 0x1a; - ENOMEM = 0xc; - EINPROGRESS = 0x73; - ENOTBLK = 0xf; - EPROTOTYPE = 0x5b; - ERESTART = 0x55; - EISNAM = 0x78; - ENOMSG = 0x2a; - EALREADY = 0x72; - ETIMEDOUT = 0x6e; - ENODATA = 0x3d; - EINTR = 0x4; - ENOLINK = 0x43; - EPERM = 0x1; - ELOOP = 0x28; - ENETDOWN = 0x64; - ESTALE = 0x74; - ENOTSOCK = 0x58; - ENOSR = 0x3f; - ECHILD = 0xa; - ELNRNG = 0x30; - EPIPE = 0x20; - EBADMSG = 0x4a; - EBFONT = 0x3b; - EREMOTE = 0x42; - ETOOMANYREFS = 0x6d; - EPFNOSUPPORT = 0x60; - ENONET = 0x40; - EXFULL = 0x36; - EBADSLT = 0x39; - ENOTNAM = 0x76; - ELIBEXEC = 0x53; - ENOCSI = 0x32; - ENOTEMPTY = 0x27; - EADDRINUSE = 0x62; - ENETRESET = 0x66; - EISDIR = 0x15; - EIDRM = 0x2b; - ECOMM = 0x46; - EBADFD = 0x4d; - EL2HLT = 0x33; - ENOKEY = 0x7e; - EINVAL = 0x16; - ESHUTDOWN = 0x6c; - EKEYREJECTED = 0x81; - ELIBSCN = 0x51; - ENAVAIL = 0x77; - ENOSTR = 0x3c; - EOVERFLOW = 0x4b; - EUCLEAN = 0x75; - ENOMEDIUM = 0x7b; - EBUSY = 0x10; - EPROTO = 0x47; - ENODEV = 0x13; - EKEYEXPIRED = 0x7f; - EROFS = 0x1e; - ELIBACC = 0x4f; - E2BIG = 0x7; - EDEADLK = 0x23; - ECONNRESET = 0x68; - ENXIO = 0x6; - EBADRQC = 0x38; - ENAMETOOLONG = 0x24; - ESOCKTNOSUPPORT = 0x5e; - EDOTDOT = 0x49; - EADDRNOTAVAIL = 0x63; - ETIME = 0x3e; - EPROTONOSUPPORT = 0x5d; - ENOTRECOVERABLE = 0x83; - EIO = 0x5; - ENETUNREACH = 0x65; - EXDEV = 0x12; - EDQUOT = 0x7a; - EREMOTEIO = 0x79; - ENOSPC = 0x1c; - ENOEXEC = 0x8; - EMSGSIZE = 0x5a; - EDOM = 0x21; - EFBIG = 0x1b; - ESRCH = 0x3; - ECHRNG = 0x2c; - EHOSTDOWN = 0x70; - ENOLCK = 0x25; - ENFILE = 0x17; - ENOSYS = 0x26; - ENOTCONN = 0x6b; - ENOTSUP = 0x5f; - ESRMNT = 0x45; - EDEADLOCK = 0x23; - ECONNABORTED = 0x67; - ENOANO = 0x37; - EISCONN = 0x6a; - EUSERS = 0x57; - ENOPROTOOPT = 0x5c; - EMFILE = 0x18; - ENOBUFS = 0x69; - EL3HLT = 0x2e; - EFAULT = 0xe; - EWOULDBLOCK = 0xb; - ELIBBAD = 0x50; - ESTRPIPE = 0x56; - ECONNREFUSED = 0x6f; - EAGAIN = 0xb; - ELIBMAX = 0x52; - EEXIST = 0x11; - EL2NSYNC = 0x2d; - ENOENT = 0x2; - ENOPKG = 0x41; - EKEYREVOKED = 0x80; - EHOSTUNREACH = 0x71; - ENOTUNIQ = 0x4c; - EOPNOTSUPP = 0x5f; - ENOTDIR = 0x14; - EMEDIUMTYPE = 0x7c; - SIGBUS = 0x7; - SIGTTIN = 0x15; - SIGPROF = 0x1b; - SIGFPE = 0x8; - SIGHUP = 0x1; - SIGTTOU = 0x16; - SIGSTKFLT = 0x10; - SIGUSR1 = 0xa; - SIGURG = 0x17; - SIGQUIT = 0x3; - SIGCLD = 0x11; - SIGIO = 0x1d; - SIGABRT = 0x6; - SIGUSR2 = 0xc; - SIGTRAP = 0x5; - SIGVTALRM = 0x1a; - SIGPOLL = 0x1d; - SIGSEGV = 0xb; - SIGCONT = 0x12; - SIGPIPE = 0xd; - SIGWINCH = 0x1c; - SIGXFSZ = 0x19; - SIGCHLD = 0x11; - SIGSYS = 0x1f; - SIGSTOP = 0x13; - SIGALRM = 0xe; - SIGTSTP = 0x14; - SIGKILL = 0x9; - SIGXCPU = 0x18; - SIGUNUSED = 0x1f; - SIGPWR = 0x1e; - SIGILL = 0x4; - SIGINT = 0x2; - SIGIOT = 0x6; - SIGTERM = 0xf; -) - -// Types - - -// Error table -var errors = [...]string { - 72: "multihop attempted", - 49: "protocol driver not attached", - 97: "address family not supported by protocol", - 78: "remote address changed", - 13: "permission denied", - 47: "level 3 reset", - 89: "destination address required", - 84: "invalid or incomplete multibyte or wide character", - 29: "illegal seek", - 31: "too many links", - 130: "owner died", - 25: "inappropriate ioctl for device", - 52: "invalid exchange", - 9: "bad file descriptor", - 53: "invalid request descriptor", - 68: "advertise error", - 34: "numerical result out of range", - 125: "operation canceled", - 26: "text file busy", - 12: "cannot allocate memory", - 115: "operation now in progress", - 15: "block device required", - 91: "protocol wrong type for socket", - 85: "interrupted system call should be restarted", - 120: "is a named type file", - 42: "no message of desired type", - 114: "operation already in progress", - 110: "connection timed out", - 61: "no data available", - 4: "interrupted system call", - 67: "link has been severed", - 1: "operation not permitted", - 40: "too many levels of symbolic links", - 100: "network is down", - 116: "stale NFS file handle", - 88: "socket operation on non-socket", - 63: "out of streams resources", - 10: "no child processes", - 48: "link number out of range", - 32: "broken pipe", - 74: "bad message", - 59: "bad font file format", - 66: "object is remote", - 109: "too many references: cannot splice", - 96: "protocol family not supported", - 64: "machine is not on the network", - 54: "exchange full", - 57: "invalid slot", - 118: "not a XENIX named type file", - 83: "cannot exec a shared library directly", - 50: "no CSI structure available", - 39: "directory not empty", - 98: "address already in use", - 102: "network dropped connection on reset", - 21: "is a directory", - 43: "identifier removed", - 70: "communication error on send", - 77: "file descriptor in bad state", - 51: "level 2 halted", - 126: "required key not available", - 22: "invalid argument", - 108: "cannot send after transport endpoint shutdown", - 129: "key was rejected by service", - 81: ".lib section in a.out corrupted", - 119: "no XENIX semaphores available", - 60: "device not a stream", - 75: "value too large for defined data type", - 117: "structure needs cleaning", - 123: "no medium found", - 16: "device or resource busy", - 71: "protocol error", - 19: "no such device", - 127: "key has expired", - 30: "read-only file system", - 79: "can not access a needed shared library", - 7: "argument list too long", - 35: "resource deadlock avoided", - 104: "connection reset by peer", - 6: "no such device or address", - 56: "invalid request code", - 36: "file name too long", - 94: "socket type not supported", - 73: "RFS specific error", - 99: "cannot assign requested address", - 62: "timer expired", - 93: "protocol not supported", - 131: "state not recoverable", - 5: "input/output error", - 101: "network is unreachable", - 18: "invalid cross-device link", - 122: "disk quota exceeded", - 121: "remote I/O error", - 28: "no space left on device", - 8: "exec format error", - 90: "message too long", - 33: "numerical argument out of domain", - 27: "file too large", - 3: "no such process", - 44: "channel number out of range", - 112: "host is down", - 37: "no locks available", - 23: "too many open files in system", - 38: "function not implemented", - 107: "transport endpoint is not connected", - 95: "operation not supported", - 69: "srmount error", - 103: "software caused connection abort", - 55: "no anode", - 106: "transport endpoint is already connected", - 87: "too many users", - 92: "protocol not available", - 24: "too many open files", - 105: "no buffer space available", - 46: "level 3 halted", - 14: "bad address", - 11: "resource temporarily unavailable", - 80: "accessing a corrupted shared library", - 86: "streams pipe error", - 111: "connection refused", - 82: "attempting to link in too many shared libraries", - 17: "file exists", - 45: "level 2 not synchronized", - 2: "no such file or directory", - 65: "package not installed", - 128: "key has been revoked", - 113: "no route to host", - 76: "name not unique on network", - 20: "not a directory", - 124: "wrong medium type", -} - diff --git a/src/lib/syscall/zerrors_linux_amd64.go b/src/lib/syscall/zerrors_linux_amd64.go deleted file mode 100644 index f1e7e011d..000000000 --- a/src/lib/syscall/zerrors_linux_amd64.go +++ /dev/null @@ -1,316 +0,0 @@ -// mkerrors -// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT - -// godefs -gsyscall _errors.c - -// MACHINE GENERATED - DO NOT EDIT. - -package syscall - -// Constants -const ( - EMULTIHOP = 0x48; - EUNATCH = 0x31; - EAFNOSUPPORT = 0x61; - EREMCHG = 0x4e; - EACCES = 0xd; - EL3RST = 0x2f; - EDESTADDRREQ = 0x59; - EILSEQ = 0x54; - ESPIPE = 0x1d; - EMLINK = 0x1f; - EOWNERDEAD = 0x82; - ENOTTY = 0x19; - EBADE = 0x34; - EBADF = 0x9; - EBADR = 0x35; - EADV = 0x44; - ERANGE = 0x22; - ECANCELED = 0x7d; - ETXTBSY = 0x1a; - ENOMEM = 0xc; - EINPROGRESS = 0x73; - ENOTBLK = 0xf; - EPROTOTYPE = 0x5b; - ERESTART = 0x55; - EISNAM = 0x78; - ENOMSG = 0x2a; - EALREADY = 0x72; - ETIMEDOUT = 0x6e; - ENODATA = 0x3d; - EINTR = 0x4; - ENOLINK = 0x43; - EPERM = 0x1; - ELOOP = 0x28; - ENETDOWN = 0x64; - ESTALE = 0x74; - ENOTSOCK = 0x58; - ENOSR = 0x3f; - ECHILD = 0xa; - ELNRNG = 0x30; - EPIPE = 0x20; - EBADMSG = 0x4a; - EBFONT = 0x3b; - EREMOTE = 0x42; - ETOOMANYREFS = 0x6d; - EPFNOSUPPORT = 0x60; - ENONET = 0x40; - EXFULL = 0x36; - EBADSLT = 0x39; - ENOTNAM = 0x76; - ELIBEXEC = 0x53; - ENOCSI = 0x32; - ENOTEMPTY = 0x27; - EADDRINUSE = 0x62; - ENETRESET = 0x66; - EISDIR = 0x15; - EIDRM = 0x2b; - ECOMM = 0x46; - EBADFD = 0x4d; - EL2HLT = 0x33; - ENOKEY = 0x7e; - EINVAL = 0x16; - ESHUTDOWN = 0x6c; - EKEYREJECTED = 0x81; - ELIBSCN = 0x51; - ENAVAIL = 0x77; - ENOSTR = 0x3c; - EOVERFLOW = 0x4b; - EUCLEAN = 0x75; - ENOMEDIUM = 0x7b; - EBUSY = 0x10; - EPROTO = 0x47; - ENODEV = 0x13; - EKEYEXPIRED = 0x7f; - EROFS = 0x1e; - ELIBACC = 0x4f; - E2BIG = 0x7; - EDEADLK = 0x23; - ECONNRESET = 0x68; - ENXIO = 0x6; - EBADRQC = 0x38; - ENAMETOOLONG = 0x24; - ESOCKTNOSUPPORT = 0x5e; - EDOTDOT = 0x49; - EADDRNOTAVAIL = 0x63; - ETIME = 0x3e; - EPROTONOSUPPORT = 0x5d; - ENOTRECOVERABLE = 0x83; - EIO = 0x5; - ENETUNREACH = 0x65; - EXDEV = 0x12; - EDQUOT = 0x7a; - EREMOTEIO = 0x79; - ENOSPC = 0x1c; - ENOEXEC = 0x8; - EMSGSIZE = 0x5a; - EDOM = 0x21; - EFBIG = 0x1b; - ESRCH = 0x3; - ECHRNG = 0x2c; - EHOSTDOWN = 0x70; - ENOLCK = 0x25; - ENFILE = 0x17; - ENOSYS = 0x26; - ENOTCONN = 0x6b; - ENOTSUP = 0x5f; - ESRMNT = 0x45; - EDEADLOCK = 0x23; - ECONNABORTED = 0x67; - ENOANO = 0x37; - EISCONN = 0x6a; - EUSERS = 0x57; - ENOPROTOOPT = 0x5c; - EMFILE = 0x18; - ENOBUFS = 0x69; - EL3HLT = 0x2e; - EFAULT = 0xe; - EWOULDBLOCK = 0xb; - ELIBBAD = 0x50; - ESTRPIPE = 0x56; - ECONNREFUSED = 0x6f; - EAGAIN = 0xb; - ELIBMAX = 0x52; - EEXIST = 0x11; - EL2NSYNC = 0x2d; - ENOENT = 0x2; - ENOPKG = 0x41; - EKEYREVOKED = 0x80; - EHOSTUNREACH = 0x71; - ENOTUNIQ = 0x4c; - EOPNOTSUPP = 0x5f; - ENOTDIR = 0x14; - EMEDIUMTYPE = 0x7c; - SIGBUS = 0x7; - SIGTTIN = 0x15; - SIGPROF = 0x1b; - SIGFPE = 0x8; - SIGHUP = 0x1; - SIGTTOU = 0x16; - SIGSTKFLT = 0x10; - SIGUSR1 = 0xa; - SIGURG = 0x17; - SIGQUIT = 0x3; - SIGCLD = 0x11; - SIGIO = 0x1d; - SIGABRT = 0x6; - SIGUSR2 = 0xc; - SIGTRAP = 0x5; - SIGVTALRM = 0x1a; - SIGPOLL = 0x1d; - SIGSEGV = 0xb; - SIGCONT = 0x12; - SIGPIPE = 0xd; - SIGWINCH = 0x1c; - SIGXFSZ = 0x19; - SIGCHLD = 0x11; - SIGSYS = 0x1f; - SIGSTOP = 0x13; - SIGALRM = 0xe; - SIGTSTP = 0x14; - SIGKILL = 0x9; - SIGXCPU = 0x18; - SIGUNUSED = 0x1f; - SIGPWR = 0x1e; - SIGILL = 0x4; - SIGINT = 0x2; - SIGIOT = 0x6; - SIGTERM = 0xf; -) - -// Types - - -// Error table -var errors = [...]string { - 72: "multihop attempted", - 49: "protocol driver not attached", - 97: "address family not supported by protocol", - 78: "remote address changed", - 13: "permission denied", - 47: "level 3 reset", - 89: "destination address required", - 84: "invalid or incomplete multibyte or wide character", - 29: "illegal seek", - 31: "too many links", - 130: "owner died", - 25: "inappropriate ioctl for device", - 52: "invalid exchange", - 9: "bad file descriptor", - 53: "invalid request descriptor", - 68: "advertise error", - 34: "numerical result out of range", - 125: "operation canceled", - 26: "text file busy", - 12: "cannot allocate memory", - 115: "operation now in progress", - 15: "block device required", - 91: "protocol wrong type for socket", - 85: "interrupted system call should be restarted", - 120: "is a named type file", - 42: "no message of desired type", - 114: "operation already in progress", - 110: "connection timed out", - 61: "no data available", - 4: "interrupted system call", - 67: "link has been severed", - 1: "operation not permitted", - 40: "too many levels of symbolic links", - 100: "network is down", - 116: "stale NFS file handle", - 88: "socket operation on non-socket", - 63: "out of streams resources", - 10: "no child processes", - 48: "link number out of range", - 32: "broken pipe", - 74: "bad message", - 59: "bad font file format", - 66: "object is remote", - 109: "too many references: cannot splice", - 96: "protocol family not supported", - 64: "machine is not on the network", - 54: "exchange full", - 57: "invalid slot", - 118: "not a XENIX named type file", - 83: "cannot exec a shared library directly", - 50: "no CSI structure available", - 39: "directory not empty", - 98: "address already in use", - 102: "network dropped connection on reset", - 21: "is a directory", - 43: "identifier removed", - 70: "communication error on send", - 77: "file descriptor in bad state", - 51: "level 2 halted", - 126: "required key not available", - 22: "invalid argument", - 108: "cannot send after transport endpoint shutdown", - 129: "key was rejected by service", - 81: ".lib section in a.out corrupted", - 119: "no XENIX semaphores available", - 60: "device not a stream", - 75: "value too large for defined data type", - 117: "structure needs cleaning", - 123: "no medium found", - 16: "device or resource busy", - 71: "protocol error", - 19: "no such device", - 127: "key has expired", - 30: "read-only file system", - 79: "can not access a needed shared library", - 7: "argument list too long", - 35: "resource deadlock avoided", - 104: "connection reset by peer", - 6: "no such device or address", - 56: "invalid request code", - 36: "file name too long", - 94: "socket type not supported", - 73: "RFS specific error", - 99: "cannot assign requested address", - 62: "timer expired", - 93: "protocol not supported", - 131: "state not recoverable", - 5: "input/output error", - 101: "network is unreachable", - 18: "invalid cross-device link", - 122: "disk quota exceeded", - 121: "remote I/O error", - 28: "no space left on device", - 8: "exec format error", - 90: "message too long", - 33: "numerical argument out of domain", - 27: "file too large", - 3: "no such process", - 44: "channel number out of range", - 112: "host is down", - 37: "no locks available", - 23: "too many open files in system", - 38: "function not implemented", - 107: "transport endpoint is not connected", - 95: "operation not supported", - 69: "srmount error", - 103: "software caused connection abort", - 55: "no anode", - 106: "transport endpoint is already connected", - 87: "too many users", - 92: "protocol not available", - 24: "too many open files", - 105: "no buffer space available", - 46: "level 3 halted", - 14: "bad address", - 11: "resource temporarily unavailable", - 80: "accessing a corrupted shared library", - 86: "streams pipe error", - 111: "connection refused", - 82: "attempting to link in too many shared libraries", - 17: "file exists", - 45: "level 2 not synchronized", - 2: "no such file or directory", - 65: "package not installed", - 128: "key has been revoked", - 113: "no route to host", - 76: "name not unique on network", - 20: "not a directory", - 124: "wrong medium type", -} - diff --git a/src/lib/syscall/zsyscall_darwin_386.go b/src/lib/syscall/zsyscall_darwin_386.go deleted file mode 100644 index 61f7c01db..000000000 --- a/src/lib/syscall/zsyscall_darwin_386.go +++ /dev/null @@ -1,624 +0,0 @@ -// mksyscall -l32 syscall_darwin.go syscall_darwin_386.go -// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT - -package syscall - -import ( - "syscall"; - "unsafe"; -) - -func getgroups(ngid int, gid *_Gid_t) (n int, errno int) { - r0, r1, e1 := Syscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0); - n = int(r0); - errno = int(e1); - return; -} - -func setgroups(ngid int, gid *_Gid_t) (errno int) { - r0, r1, e1 := Syscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0); - errno = int(e1); - return; -} - -func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, errno int) { - r0, r1, 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; -} - -func pipe() (r int, w int, errno int) { - r0, r1, e1 := Syscall(SYS_PIPE, 0, 0, 0); - r = int(r0); - w = int(r1); - errno = int(e1); - return; -} - -func lseek(fd int, offset int64, whence int) (newoffset uintptr, errno int) { - r0, r1, e1 := Syscall6(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(offset >> 32), uintptr(whence), 0, 0); - newoffset = uintptr(r0); - errno = int(e1); - return; -} - -func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, errno int) { - r0, r1, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))); - fd = int(r0); - errno = int(e1); - return; -} - -func bind(s int, addr uintptr, addrlen _Socklen) (errno int) { - r0, r1, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen)); - errno = int(e1); - return; -} - -func connect(s int, addr uintptr, addrlen _Socklen) (errno int) { - r0, r1, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen)); - errno = int(e1); - return; -} - -func socket(domain int, typ int, proto int) (fd int, errno int) { - r0, r1, e1 := Syscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto)); - fd = int(r0); - errno = int(e1); - return; -} - -func setsockopt(s int, level int, name int, val uintptr, vallen int) (errno int) { - r0, r1, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0); - errno = int(e1); - return; -} - -func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, errno int) { - r0, r1, 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; -} - -func fcntl(fd int, cmd int, arg int) (val int, errno int) { - r0, r1, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg)); - val = int(r0); - errno = int(e1); - return; -} - -func Access(path string, flags int) (errno int) { - r0, r1, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0); - errno = int(e1); - return; -} - -func Adjtime(delta *Timeval, olddelta *Timeval) (errno int) { - r0, r1, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0); - errno = int(e1); - return; -} - -func Chdir(path string) (errno int) { - r0, r1, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); - errno = int(e1); - return; -} - -func Chflags(path string, flags int) (errno int) { - r0, r1, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0); - errno = int(e1); - return; -} - -func Chmod(path string, mode int) (errno int) { - r0, r1, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0); - errno = int(e1); - return; -} - -func Chown(path string, uid int, gid int) (errno int) { - r0, r1, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid)); - errno = int(e1); - return; -} - -func Chroot(path string) (errno int) { - r0, r1, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); - errno = int(e1); - return; -} - -func Close(fd int) (errno int) { - r0, r1, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0); - errno = int(e1); - return; -} - -func Dup(fd int) (nfd int, errno int) { - r0, r1, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0); - nfd = int(r0); - errno = int(e1); - return; -} - -func Dup2(from int, to int) (errno int) { - r0, r1, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0); - errno = int(e1); - return; -} - -func Exchangedata(path1 string, path2 string, options int) (errno int) { - r0, r1, e1 := Syscall(SYS_EXCHANGEDATA, uintptr(unsafe.Pointer(StringBytePtr(path1))), uintptr(unsafe.Pointer(StringBytePtr(path2))), uintptr(options)); - errno = int(e1); - return; -} - -func Exit(code int) () { - r0, r1, e1 := Syscall(SYS_EXIT, uintptr(code), 0, 0); - return; -} - -func Fchdir(fd int) (errno int) { - r0, r1, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0); - errno = int(e1); - return; -} - -func Fchflags(path string, flags int) (errno int) { - r0, r1, e1 := Syscall(SYS_FCHFLAGS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0); - errno = int(e1); - return; -} - -func Fchmod(fd int, mode int) (errno int) { - r0, r1, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0); - errno = int(e1); - return; -} - -func Fchown(fd int, uid int, gid int) (errno int) { - r0, r1, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid)); - errno = int(e1); - return; -} - -func Flock(fd int, how int) (errno int) { - r0, r1, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0); - errno = int(e1); - return; -} - -func Fpathconf(fd int, name int) (val int, errno int) { - r0, r1, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0); - val = int(r0); - errno = int(e1); - return; -} - -func Fstat(fd int, stat *Stat_t) (errno int) { - r0, r1, e1 := Syscall(SYS_FSTAT64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0); - errno = int(e1); - return; -} - -func Fstatfs(fd int, stat *Statfs_t) (errno int) { - r0, r1, e1 := Syscall(SYS_FSTATFS64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0); - errno = int(e1); - return; -} - -func Fsync(fd int) (errno int) { - r0, r1, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0); - errno = int(e1); - return; -} - -func Ftruncate(fd int, length int64) (errno int) { - r0, r1, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), uintptr(length >> 32)); - errno = int(e1); - return; -} - -func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, errno int) { - var _p0 *byte; - if len(buf) > 0 { _p0 = &buf[0]; } - r0, r1, e1 := Syscall6(SYS_GETDIRENTRIES64, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0); - n = int(r0); - errno = int(e1); - return; -} - -func Getdtablesize() (size int) { - r0, r1, e1 := Syscall(SYS_GETDTABLESIZE, 0, 0, 0); - size = int(r0); - return; -} - -func Getegid() (egid int) { - r0, r1, e1 := Syscall(SYS_GETEGID, 0, 0, 0); - egid = int(r0); - return; -} - -func Geteuid() (uid int) { - r0, r1, e1 := Syscall(SYS_GETEUID, 0, 0, 0); - uid = int(r0); - return; -} - -func Getfsstat(buf []Statfs_t, flags int) (n int, errno int) { - var _p0 *Statfs_t; - if len(buf) > 0 { _p0 = &buf[0]; } - r0, r1, e1 := Syscall(SYS_GETFSSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(flags)); - n = int(r0); - errno = int(e1); - return; -} - -func Getgid() (gid int) { - r0, r1, e1 := Syscall(SYS_GETGID, 0, 0, 0); - gid = int(r0); - return; -} - -func Getpgid(pid int) (pgid int, errno int) { - r0, r1, e1 := Syscall(SYS_GETPGID, uintptr(pid), 0, 0); - pgid = int(r0); - errno = int(e1); - return; -} - -func Getpgrp() (pgrp int) { - r0, r1, e1 := Syscall(SYS_GETPGRP, 0, 0, 0); - pgrp = int(r0); - return; -} - -func Getpid() (pid int) { - r0, r1, e1 := Syscall(SYS_GETPID, 0, 0, 0); - pid = int(r0); - return; -} - -func Getppid() (ppid int) { - r0, r1, e1 := Syscall(SYS_GETPPID, 0, 0, 0); - ppid = int(r0); - return; -} - -func Getpriority(which int, who int) (prio int, errno int) { - r0, r1, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0); - prio = int(r0); - errno = int(e1); - return; -} - -func Getrlimit(which int, lim *Rlimit) (errno int) { - r0, r1, e1 := Syscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0); - errno = int(e1); - return; -} - -func Getrusage(who int, rusage *Rusage) (errno int) { - r0, r1, e1 := Syscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0); - errno = int(e1); - return; -} - -func Getsid(pid int) (sid int, errno int) { - r0, r1, e1 := Syscall(SYS_GETSID, uintptr(pid), 0, 0); - sid = int(r0); - errno = int(e1); - return; -} - -func Getuid() (uid int) { - r0, r1, e1 := Syscall(SYS_GETUID, 0, 0, 0); - uid = int(r0); - return; -} - -func Issetugid() (tainted bool) { - r0, r1, e1 := Syscall(SYS_ISSETUGID, 0, 0, 0); - tainted = bool(r0 != 0); - return; -} - -func Kill(pid int, signum int, posix int) (errno int) { - r0, r1, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), uintptr(posix)); - errno = int(e1); - return; -} - -func Kqueue() (fd int, errno int) { - r0, r1, e1 := Syscall(SYS_KQUEUE, 0, 0, 0); - fd = int(r0); - errno = int(e1); - return; -} - -func Lchown(path string, uid int, gid int) (errno int) { - r0, r1, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid)); - errno = int(e1); - return; -} - -func Link(path string, link string) (errno int) { - r0, r1, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(StringBytePtr(link))), 0); - errno = int(e1); - return; -} - -func Listen(s int, backlog int) (errno int) { - r0, r1, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0); - errno = int(e1); - return; -} - -func Lstat(path string, stat *Stat_t) (errno int) { - r0, r1, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0); - errno = int(e1); - return; -} - -func Mkdir(path string, mode int) (errno int) { - r0, r1, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0); - errno = int(e1); - return; -} - -func Mkfifo(path string, mode int) (errno int) { - r0, r1, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0); - errno = int(e1); - return; -} - -func Mknod(path string, mode int, dev int) (errno int) { - r0, r1, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(dev)); - errno = int(e1); - return; -} - -func Open(path string, mode int, perm int) (fd int, errno int) { - r0, r1, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(perm)); - fd = int(r0); - errno = int(e1); - return; -} - -func Pathconf(path string, name int) (val int, errno int) { - r0, r1, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(name), 0); - val = int(r0); - errno = int(e1); - return; -} - -func Pread(fd int, p []byte, offset int64) (n int, errno int) { - var _p0 *byte; - if len(p) > 0 { _p0 = &p[0]; } - r0, r1, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), uintptr(offset >> 32), 0); - n = int(r0); - errno = int(e1); - return; -} - -func Pwrite(fd int, p []byte, offset int64) (n int, errno int) { - var _p0 *byte; - if len(p) > 0 { _p0 = &p[0]; } - r0, r1, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), uintptr(offset >> 32), 0); - n = int(r0); - errno = int(e1); - return; -} - -func Read(fd int, p []byte) (n int, errno int) { - var _p0 *byte; - if len(p) > 0 { _p0 = &p[0]; } - r0, r1, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p))); - n = int(r0); - errno = int(e1); - return; -} - -func Readlink(path string, buf []byte) (n int, errno int) { - var _p0 *byte; - if len(buf) > 0 { _p0 = &buf[0]; } - r0, r1, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf))); - n = int(r0); - errno = int(e1); - return; -} - -func Rename(from string, to string) (errno int) { - r0, r1, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(StringBytePtr(from))), uintptr(unsafe.Pointer(StringBytePtr(to))), 0); - errno = int(e1); - return; -} - -func Revoke(path string) (errno int) { - r0, r1, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); - errno = int(e1); - return; -} - -func Rmdir(path string) (errno int) { - r0, r1, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); - errno = int(e1); - return; -} - -func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (errno int) { - r0, r1, 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; -} - -func Setegid(egid int) (errno int) { - r0, r1, e1 := Syscall(SYS_SETEGID, uintptr(egid), 0, 0); - errno = int(e1); - return; -} - -func Seteuid(euid int) (errno int) { - r0, r1, e1 := Syscall(SYS_SETEUID, uintptr(euid), 0, 0); - errno = int(e1); - return; -} - -func Setgid(gid int) (errno int) { - r0, r1, e1 := Syscall(SYS_SETGID, uintptr(gid), 0, 0); - errno = int(e1); - return; -} - -func Setlogin(name string) (errno int) { - r0, r1, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(StringBytePtr(name))), 0, 0); - errno = int(e1); - return; -} - -func Setpgid(pid int, pgid int) (errno int) { - r0, r1, e1 := Syscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0); - errno = int(e1); - return; -} - -func Setpriority(which int, who int, prio int) (errno int) { - r0, r1, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio)); - errno = int(e1); - return; -} - -func Setprivexec(flag int) (errno int) { - r0, r1, e1 := Syscall(SYS_SETPRIVEXEC, uintptr(flag), 0, 0); - errno = int(e1); - return; -} - -func Setregid(rgid int, egid int) (errno int) { - r0, r1, e1 := Syscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0); - errno = int(e1); - return; -} - -func Setreuid(ruid int, euid int) (errno int) { - r0, r1, e1 := Syscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0); - errno = int(e1); - return; -} - -func Setrlimit(which int, lim *Rlimit) (errno int) { - r0, r1, e1 := Syscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0); - errno = int(e1); - return; -} - -func Setsid() (pid int, errno int) { - r0, r1, e1 := Syscall(SYS_SETSID, 0, 0, 0); - pid = int(r0); - errno = int(e1); - return; -} - -func Settimeofday(tp *Timeval) (errno int) { - r0, r1, e1 := Syscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0); - errno = int(e1); - return; -} - -func Setuid(uid int) (errno int) { - r0, r1, e1 := Syscall(SYS_SETUID, uintptr(uid), 0, 0); - errno = int(e1); - return; -} - -func Stat(path string, stat *Stat_t) (errno int) { - r0, r1, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0); - errno = int(e1); - return; -} - -func Statfs(path string, stat *Statfs_t) (errno int) { - r0, r1, e1 := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0); - errno = int(e1); - return; -} - -func Symlink(path string, link string) (errno int) { - r0, r1, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(StringBytePtr(link))), 0); - errno = int(e1); - return; -} - -func Sync() (errno int) { - r0, r1, e1 := Syscall(SYS_SYNC, 0, 0, 0); - errno = int(e1); - return; -} - -func Truncate(path string, length int64) (errno int) { - r0, r1, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(length), uintptr(length >> 32)); - errno = int(e1); - return; -} - -func Umask(newmask int) (errno int) { - r0, r1, e1 := Syscall(SYS_UMASK, uintptr(newmask), 0, 0); - errno = int(e1); - return; -} - -func Undelete(path string) (errno int) { - r0, r1, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); - errno = int(e1); - return; -} - -func Unlink(path string) (errno int) { - r0, r1, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); - errno = int(e1); - return; -} - -func Unmount(path string, flags int) (errno int) { - r0, r1, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0); - errno = int(e1); - return; -} - -func Write(fd int, p []byte) (n int, errno int) { - var _p0 *byte; - if len(p) > 0 { _p0 = &p[0]; } - r0, r1, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p))); - n = int(r0); - errno = int(e1); - return; -} - -func read(fd int, buf *byte, nbuf int) (n int, errno int) { - r0, r1, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)); - n = int(r0); - errno = int(e1); - return; -} - -func write(fd int, buf *byte, nbuf int) (n int, errno int) { - r0, r1, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)); - n = int(r0); - errno = int(e1); - return; -} - -func gettimeofday(tp *Timeval) (sec int64, usec int32, errno int) { - r0, r1, e1 := Syscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0); - sec = int64(r0); - usec = int32(r1); - errno = int(e1); - return; -} - - - diff --git a/src/lib/syscall/zsyscall_darwin_amd64.go b/src/lib/syscall/zsyscall_darwin_amd64.go deleted file mode 100644 index c8a0b10a7..000000000 --- a/src/lib/syscall/zsyscall_darwin_amd64.go +++ /dev/null @@ -1,624 +0,0 @@ -// mksyscall syscall_darwin.go syscall_darwin_amd64.go -// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT - -package syscall - -import ( - "syscall"; - "unsafe"; -) - -func getgroups(ngid int, gid *_Gid_t) (n int, errno int) { - r0, r1, e1 := Syscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0); - n = int(r0); - errno = int(e1); - return; -} - -func setgroups(ngid int, gid *_Gid_t) (errno int) { - r0, r1, e1 := Syscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0); - errno = int(e1); - return; -} - -func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, errno int) { - r0, r1, 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; -} - -func pipe() (r int, w int, errno int) { - r0, r1, e1 := Syscall(SYS_PIPE, 0, 0, 0); - r = int(r0); - w = int(r1); - errno = int(e1); - return; -} - -func lseek(fd int, offset int64, whence int) (newoffset uintptr, errno int) { - r0, r1, e1 := Syscall(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence)); - newoffset = uintptr(r0); - errno = int(e1); - return; -} - -func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, errno int) { - r0, r1, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))); - fd = int(r0); - errno = int(e1); - return; -} - -func bind(s int, addr uintptr, addrlen _Socklen) (errno int) { - r0, r1, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen)); - errno = int(e1); - return; -} - -func connect(s int, addr uintptr, addrlen _Socklen) (errno int) { - r0, r1, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen)); - errno = int(e1); - return; -} - -func socket(domain int, typ int, proto int) (fd int, errno int) { - r0, r1, e1 := Syscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto)); - fd = int(r0); - errno = int(e1); - return; -} - -func setsockopt(s int, level int, name int, val uintptr, vallen int) (errno int) { - r0, r1, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0); - errno = int(e1); - return; -} - -func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, errno int) { - r0, r1, 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; -} - -func fcntl(fd int, cmd int, arg int) (val int, errno int) { - r0, r1, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg)); - val = int(r0); - errno = int(e1); - return; -} - -func Access(path string, flags int) (errno int) { - r0, r1, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0); - errno = int(e1); - return; -} - -func Adjtime(delta *Timeval, olddelta *Timeval) (errno int) { - r0, r1, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0); - errno = int(e1); - return; -} - -func Chdir(path string) (errno int) { - r0, r1, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); - errno = int(e1); - return; -} - -func Chflags(path string, flags int) (errno int) { - r0, r1, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0); - errno = int(e1); - return; -} - -func Chmod(path string, mode int) (errno int) { - r0, r1, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0); - errno = int(e1); - return; -} - -func Chown(path string, uid int, gid int) (errno int) { - r0, r1, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid)); - errno = int(e1); - return; -} - -func Chroot(path string) (errno int) { - r0, r1, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); - errno = int(e1); - return; -} - -func Close(fd int) (errno int) { - r0, r1, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0); - errno = int(e1); - return; -} - -func Dup(fd int) (nfd int, errno int) { - r0, r1, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0); - nfd = int(r0); - errno = int(e1); - return; -} - -func Dup2(from int, to int) (errno int) { - r0, r1, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0); - errno = int(e1); - return; -} - -func Exchangedata(path1 string, path2 string, options int) (errno int) { - r0, r1, e1 := Syscall(SYS_EXCHANGEDATA, uintptr(unsafe.Pointer(StringBytePtr(path1))), uintptr(unsafe.Pointer(StringBytePtr(path2))), uintptr(options)); - errno = int(e1); - return; -} - -func Exit(code int) () { - r0, r1, e1 := Syscall(SYS_EXIT, uintptr(code), 0, 0); - return; -} - -func Fchdir(fd int) (errno int) { - r0, r1, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0); - errno = int(e1); - return; -} - -func Fchflags(path string, flags int) (errno int) { - r0, r1, e1 := Syscall(SYS_FCHFLAGS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0); - errno = int(e1); - return; -} - -func Fchmod(fd int, mode int) (errno int) { - r0, r1, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0); - errno = int(e1); - return; -} - -func Fchown(fd int, uid int, gid int) (errno int) { - r0, r1, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid)); - errno = int(e1); - return; -} - -func Flock(fd int, how int) (errno int) { - r0, r1, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0); - errno = int(e1); - return; -} - -func Fpathconf(fd int, name int) (val int, errno int) { - r0, r1, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0); - val = int(r0); - errno = int(e1); - return; -} - -func Fstat(fd int, stat *Stat_t) (errno int) { - r0, r1, e1 := Syscall(SYS_FSTAT64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0); - errno = int(e1); - return; -} - -func Fstatfs(fd int, stat *Statfs_t) (errno int) { - r0, r1, e1 := Syscall(SYS_FSTATFS64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0); - errno = int(e1); - return; -} - -func Fsync(fd int) (errno int) { - r0, r1, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0); - errno = int(e1); - return; -} - -func Ftruncate(fd int, length int64) (errno int) { - r0, r1, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), 0); - errno = int(e1); - return; -} - -func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, errno int) { - var _p0 *byte; - if len(buf) > 0 { _p0 = &buf[0]; } - r0, r1, e1 := Syscall6(SYS_GETDIRENTRIES64, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0); - n = int(r0); - errno = int(e1); - return; -} - -func Getdtablesize() (size int) { - r0, r1, e1 := Syscall(SYS_GETDTABLESIZE, 0, 0, 0); - size = int(r0); - return; -} - -func Getegid() (egid int) { - r0, r1, e1 := Syscall(SYS_GETEGID, 0, 0, 0); - egid = int(r0); - return; -} - -func Geteuid() (uid int) { - r0, r1, e1 := Syscall(SYS_GETEUID, 0, 0, 0); - uid = int(r0); - return; -} - -func Getfsstat(buf []Statfs_t, flags int) (n int, errno int) { - var _p0 *Statfs_t; - if len(buf) > 0 { _p0 = &buf[0]; } - r0, r1, e1 := Syscall(SYS_GETFSSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(flags)); - n = int(r0); - errno = int(e1); - return; -} - -func Getgid() (gid int) { - r0, r1, e1 := Syscall(SYS_GETGID, 0, 0, 0); - gid = int(r0); - return; -} - -func Getpgid(pid int) (pgid int, errno int) { - r0, r1, e1 := Syscall(SYS_GETPGID, uintptr(pid), 0, 0); - pgid = int(r0); - errno = int(e1); - return; -} - -func Getpgrp() (pgrp int) { - r0, r1, e1 := Syscall(SYS_GETPGRP, 0, 0, 0); - pgrp = int(r0); - return; -} - -func Getpid() (pid int) { - r0, r1, e1 := Syscall(SYS_GETPID, 0, 0, 0); - pid = int(r0); - return; -} - -func Getppid() (ppid int) { - r0, r1, e1 := Syscall(SYS_GETPPID, 0, 0, 0); - ppid = int(r0); - return; -} - -func Getpriority(which int, who int) (prio int, errno int) { - r0, r1, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0); - prio = int(r0); - errno = int(e1); - return; -} - -func Getrlimit(which int, lim *Rlimit) (errno int) { - r0, r1, e1 := Syscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0); - errno = int(e1); - return; -} - -func Getrusage(who int, rusage *Rusage) (errno int) { - r0, r1, e1 := Syscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0); - errno = int(e1); - return; -} - -func Getsid(pid int) (sid int, errno int) { - r0, r1, e1 := Syscall(SYS_GETSID, uintptr(pid), 0, 0); - sid = int(r0); - errno = int(e1); - return; -} - -func Getuid() (uid int) { - r0, r1, e1 := Syscall(SYS_GETUID, 0, 0, 0); - uid = int(r0); - return; -} - -func Issetugid() (tainted bool) { - r0, r1, e1 := Syscall(SYS_ISSETUGID, 0, 0, 0); - tainted = bool(r0 != 0); - return; -} - -func Kill(pid int, signum int, posix int) (errno int) { - r0, r1, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), uintptr(posix)); - errno = int(e1); - return; -} - -func Kqueue() (fd int, errno int) { - r0, r1, e1 := Syscall(SYS_KQUEUE, 0, 0, 0); - fd = int(r0); - errno = int(e1); - return; -} - -func Lchown(path string, uid int, gid int) (errno int) { - r0, r1, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid)); - errno = int(e1); - return; -} - -func Link(path string, link string) (errno int) { - r0, r1, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(StringBytePtr(link))), 0); - errno = int(e1); - return; -} - -func Listen(s int, backlog int) (errno int) { - r0, r1, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0); - errno = int(e1); - return; -} - -func Lstat(path string, stat *Stat_t) (errno int) { - r0, r1, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0); - errno = int(e1); - return; -} - -func Mkdir(path string, mode int) (errno int) { - r0, r1, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0); - errno = int(e1); - return; -} - -func Mkfifo(path string, mode int) (errno int) { - r0, r1, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0); - errno = int(e1); - return; -} - -func Mknod(path string, mode int, dev int) (errno int) { - r0, r1, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(dev)); - errno = int(e1); - return; -} - -func Open(path string, mode int, perm int) (fd int, errno int) { - r0, r1, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(perm)); - fd = int(r0); - errno = int(e1); - return; -} - -func Pathconf(path string, name int) (val int, errno int) { - r0, r1, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(name), 0); - val = int(r0); - errno = int(e1); - return; -} - -func Pread(fd int, p []byte, offset int64) (n int, errno int) { - var _p0 *byte; - if len(p) > 0 { _p0 = &p[0]; } - r0, r1, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), 0, 0); - n = int(r0); - errno = int(e1); - return; -} - -func Pwrite(fd int, p []byte, offset int64) (n int, errno int) { - var _p0 *byte; - if len(p) > 0 { _p0 = &p[0]; } - r0, r1, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), 0, 0); - n = int(r0); - errno = int(e1); - return; -} - -func Read(fd int, p []byte) (n int, errno int) { - var _p0 *byte; - if len(p) > 0 { _p0 = &p[0]; } - r0, r1, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p))); - n = int(r0); - errno = int(e1); - return; -} - -func Readlink(path string, buf []byte) (n int, errno int) { - var _p0 *byte; - if len(buf) > 0 { _p0 = &buf[0]; } - r0, r1, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf))); - n = int(r0); - errno = int(e1); - return; -} - -func Rename(from string, to string) (errno int) { - r0, r1, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(StringBytePtr(from))), uintptr(unsafe.Pointer(StringBytePtr(to))), 0); - errno = int(e1); - return; -} - -func Revoke(path string) (errno int) { - r0, r1, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); - errno = int(e1); - return; -} - -func Rmdir(path string) (errno int) { - r0, r1, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); - errno = int(e1); - return; -} - -func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (errno int) { - r0, r1, 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; -} - -func Setegid(egid int) (errno int) { - r0, r1, e1 := Syscall(SYS_SETEGID, uintptr(egid), 0, 0); - errno = int(e1); - return; -} - -func Seteuid(euid int) (errno int) { - r0, r1, e1 := Syscall(SYS_SETEUID, uintptr(euid), 0, 0); - errno = int(e1); - return; -} - -func Setgid(gid int) (errno int) { - r0, r1, e1 := Syscall(SYS_SETGID, uintptr(gid), 0, 0); - errno = int(e1); - return; -} - -func Setlogin(name string) (errno int) { - r0, r1, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(StringBytePtr(name))), 0, 0); - errno = int(e1); - return; -} - -func Setpgid(pid int, pgid int) (errno int) { - r0, r1, e1 := Syscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0); - errno = int(e1); - return; -} - -func Setpriority(which int, who int, prio int) (errno int) { - r0, r1, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio)); - errno = int(e1); - return; -} - -func Setprivexec(flag int) (errno int) { - r0, r1, e1 := Syscall(SYS_SETPRIVEXEC, uintptr(flag), 0, 0); - errno = int(e1); - return; -} - -func Setregid(rgid int, egid int) (errno int) { - r0, r1, e1 := Syscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0); - errno = int(e1); - return; -} - -func Setreuid(ruid int, euid int) (errno int) { - r0, r1, e1 := Syscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0); - errno = int(e1); - return; -} - -func Setrlimit(which int, lim *Rlimit) (errno int) { - r0, r1, e1 := Syscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0); - errno = int(e1); - return; -} - -func Setsid() (pid int, errno int) { - r0, r1, e1 := Syscall(SYS_SETSID, 0, 0, 0); - pid = int(r0); - errno = int(e1); - return; -} - -func Settimeofday(tp *Timeval) (errno int) { - r0, r1, e1 := Syscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0); - errno = int(e1); - return; -} - -func Setuid(uid int) (errno int) { - r0, r1, e1 := Syscall(SYS_SETUID, uintptr(uid), 0, 0); - errno = int(e1); - return; -} - -func Stat(path string, stat *Stat_t) (errno int) { - r0, r1, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0); - errno = int(e1); - return; -} - -func Statfs(path string, stat *Statfs_t) (errno int) { - r0, r1, e1 := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0); - errno = int(e1); - return; -} - -func Symlink(path string, link string) (errno int) { - r0, r1, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(StringBytePtr(link))), 0); - errno = int(e1); - return; -} - -func Sync() (errno int) { - r0, r1, e1 := Syscall(SYS_SYNC, 0, 0, 0); - errno = int(e1); - return; -} - -func Truncate(path string, length int64) (errno int) { - r0, r1, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(length), 0); - errno = int(e1); - return; -} - -func Umask(newmask int) (errno int) { - r0, r1, e1 := Syscall(SYS_UMASK, uintptr(newmask), 0, 0); - errno = int(e1); - return; -} - -func Undelete(path string) (errno int) { - r0, r1, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); - errno = int(e1); - return; -} - -func Unlink(path string) (errno int) { - r0, r1, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); - errno = int(e1); - return; -} - -func Unmount(path string, flags int) (errno int) { - r0, r1, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0); - errno = int(e1); - return; -} - -func Write(fd int, p []byte) (n int, errno int) { - var _p0 *byte; - if len(p) > 0 { _p0 = &p[0]; } - r0, r1, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p))); - n = int(r0); - errno = int(e1); - return; -} - -func read(fd int, buf *byte, nbuf int) (n int, errno int) { - r0, r1, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)); - n = int(r0); - errno = int(e1); - return; -} - -func write(fd int, buf *byte, nbuf int) (n int, errno int) { - r0, r1, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)); - n = int(r0); - errno = int(e1); - return; -} - -func gettimeofday(tp *Timeval) (sec int64, usec int32, errno int) { - r0, r1, e1 := Syscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0); - sec = int64(r0); - usec = int32(r1); - errno = int(e1); - return; -} - - - diff --git a/src/lib/syscall/zsyscall_linux_386.go b/src/lib/syscall/zsyscall_linux_386.go deleted file mode 100644 index ef323b088..000000000 --- a/src/lib/syscall/zsyscall_linux_386.go +++ /dev/null @@ -1,720 +0,0 @@ -// mksyscall syscall_linux.go syscall_linux_386.go -// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT - -package syscall - -import ( - "syscall"; - "unsafe"; -) - -func pipe(p *[2]_C_int) (errno int) { - r0, r1, e1 := Syscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0); - errno = int(e1); - return; -} - -func utimes(path string, times *[2]Timeval) (errno int) { - r0, r1, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(times)), 0); - errno = int(e1); - return; -} - -func futimesat(dirfd int, path string, times *[2]Timeval) (errno int) { - r0, r1, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(times))); - errno = int(e1); - return; -} - -func Getcwd(buf []byte) (n int, errno int) { - var _p0 *byte; - if len(buf) > 0 { _p0 = &buf[0]; } - r0, r1, e1 := Syscall(SYS_GETCWD, uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), 0); - n = int(r0); - errno = int(e1); - return; -} - -func getgroups(n int, list *_Gid_t) (nn int, errno int) { - r0, r1, e1 := Syscall(SYS_GETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0); - nn = int(r0); - errno = int(e1); - return; -} - -func setgroups(n int, list *_Gid_t) (errno int) { - r0, r1, e1 := Syscall(SYS_SETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0); - errno = int(e1); - return; -} - -func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, errno int) { - r0, r1, 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; -} - -func Access(path string, mode int) (errno int) { - r0, r1, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0); - errno = int(e1); - return; -} - -func Acct(path string) (errno int) { - r0, r1, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); - errno = int(e1); - return; -} - -func Adjtimex(buf *Timex) (state int, errno int) { - r0, r1, e1 := Syscall(SYS_ADJTIMEX, uintptr(unsafe.Pointer(buf)), 0, 0); - state = int(r0); - errno = int(e1); - return; -} - -func Chdir(path string) (errno int) { - r0, r1, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); - errno = int(e1); - return; -} - -func Chmod(path string, mode int) (errno int) { - r0, r1, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0); - errno = int(e1); - return; -} - -func Chown(path string, uid int, gid int) (errno int) { - r0, r1, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid)); - errno = int(e1); - return; -} - -func Chroot(path string) (errno int) { - r0, r1, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); - errno = int(e1); - return; -} - -func Close(fd int) (errno int) { - r0, r1, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0); - errno = int(e1); - return; -} - -func Creat(path string, mode int) (fd int, errno int) { - r0, r1, e1 := Syscall(SYS_CREAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0); - fd = int(r0); - errno = int(e1); - return; -} - -func Dup(oldfd int) (fd int, errno int) { - r0, r1, e1 := Syscall(SYS_DUP, uintptr(oldfd), 0, 0); - fd = int(r0); - errno = int(e1); - return; -} - -func Dup2(oldfd int, newfd int) (fd int, errno int) { - r0, r1, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0); - fd = int(r0); - errno = int(e1); - return; -} - -func EpollCreate(size int) (fd int, errno int) { - r0, r1, e1 := Syscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0); - fd = int(r0); - errno = int(e1); - return; -} - -func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (errno int) { - r0, r1, e1 := Syscall6(SYS_EPOLL_CTL, uintptr(epfd), uintptr(op), uintptr(fd), uintptr(unsafe.Pointer(event)), 0, 0); - errno = int(e1); - return; -} - -func EpollWait(epfd int, events []EpollEvent, msec int) (n int, errno int) { - var _p0 *EpollEvent; - if len(events) > 0 { _p0 = &events[0]; } - r0, r1, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(unsafe.Pointer(_p0)), uintptr(len(events)), uintptr(msec), 0, 0); - n = int(r0); - errno = int(e1); - return; -} - -func Exit(code int) () { - r0, r1, e1 := Syscall(SYS_EXIT_GROUP, uintptr(code), 0, 0); - return; -} - -func Faccessat(dirfd int, path string, mode int, flags int) (errno int) { - r0, r1, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(flags), 0, 0); - errno = int(e1); - return; -} - -func Fallocate(fd int, mode int, off int64, len int64) (errno int) { - r0, r1, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(off >> 32), uintptr(len), uintptr(len >> 32)); - errno = int(e1); - return; -} - -func Fchdir(fd int) (errno int) { - r0, r1, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0); - errno = int(e1); - return; -} - -func Fchmod(fd int, mode int) (errno int) { - r0, r1, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0); - errno = int(e1); - return; -} - -func Fchmodat(dirfd int, path string, mode int, flags int) (errno int) { - r0, r1, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(flags), 0, 0); - errno = int(e1); - return; -} - -func Fchown(fd int, uid int, gid int) (errno int) { - r0, r1, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid)); - errno = int(e1); - return; -} - -func Fchownat(dirfd int, path string, uid int, gid int, flags int) (errno int) { - r0, r1, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid), uintptr(flags), 0); - errno = int(e1); - return; -} - -func fcntl(fd int, cmd int, arg int) (val int, errno int) { - r0, r1, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg)); - val = int(r0); - errno = int(e1); - return; -} - -func Fdatasync(fd int) (errno int) { - r0, r1, e1 := Syscall(SYS_FDATASYNC, uintptr(fd), 0, 0); - errno = int(e1); - return; -} - -func Fstat(fd int, stat *Stat_t) (errno int) { - r0, r1, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0); - errno = int(e1); - return; -} - -func Fstatfs(fd int, buf *Statfs_t) (errno int) { - r0, r1, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(buf)), 0); - errno = int(e1); - return; -} - -func Fsync(fd int) (errno int) { - r0, r1, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0); - errno = int(e1); - return; -} - -func Ftruncate(fd int, length int64) (errno int) { - r0, r1, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), uintptr(length >> 32)); - errno = int(e1); - return; -} - -func Getdents(fd int, buf []byte) (n int, errno int) { - var _p0 *byte; - if len(buf) > 0 { _p0 = &buf[0]; } - r0, r1, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf))); - n = int(r0); - errno = int(e1); - return; -} - -func Getegid() (egid int) { - r0, r1, e1 := Syscall(SYS_GETEGID, 0, 0, 0); - egid = int(r0); - return; -} - -func Geteuid() (euid int) { - r0, r1, e1 := Syscall(SYS_GETEUID, 0, 0, 0); - euid = int(r0); - return; -} - -func Getgid() (gid int) { - r0, r1, e1 := Syscall(SYS_GETGID, 0, 0, 0); - gid = int(r0); - return; -} - -func Getpgid(pid int) (pgid int, errno int) { - r0, r1, e1 := Syscall(SYS_GETPGID, uintptr(pid), 0, 0); - pgid = int(r0); - errno = int(e1); - return; -} - -func Getpgrp() (pid int) { - r0, r1, e1 := Syscall(SYS_GETPGRP, 0, 0, 0); - pid = int(r0); - return; -} - -func Getpid() (pid int) { - r0, r1, e1 := Syscall(SYS_GETPID, 0, 0, 0); - pid = int(r0); - return; -} - -func Getppid() (ppid int) { - r0, r1, e1 := Syscall(SYS_GETPPID, 0, 0, 0); - ppid = int(r0); - return; -} - -func Getrlimit(resource int, rlim *Rlimit) (errno int) { - r0, r1, e1 := Syscall(SYS_GETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0); - errno = int(e1); - return; -} - -func Getrusage(who int, rusage *Rusage) (errno int) { - r0, r1, e1 := Syscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0); - errno = int(e1); - return; -} - -func Gettid() (tid int) { - r0, r1, e1 := Syscall(SYS_GETTID, 0, 0, 0); - tid = int(r0); - return; -} - -func Gettimeofday(tv *Timeval) (errno int) { - r0, r1, e1 := Syscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0); - errno = int(e1); - return; -} - -func Getuid() (uid int) { - r0, r1, e1 := Syscall(SYS_GETUID, 0, 0, 0); - uid = int(r0); - return; -} - -func Ioperm(from int, num int, on int) (errno int) { - r0, r1, e1 := Syscall(SYS_IOPERM, uintptr(from), uintptr(num), uintptr(on)); - errno = int(e1); - return; -} - -func Iopl(level int) (errno int) { - r0, r1, e1 := Syscall(SYS_IOPL, uintptr(level), 0, 0); - errno = int(e1); - return; -} - -func Kill(pid int, sig int) (errno int) { - r0, r1, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(sig), 0); - errno = int(e1); - return; -} - -func Klogctl(typ int, buf []byte) (n int, errno int) { - var _p0 *byte; - if len(buf) > 0 { _p0 = &buf[0]; } - r0, r1, e1 := Syscall(SYS_SYSLOG, uintptr(typ), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf))); - n = int(r0); - errno = int(e1); - return; -} - -func Lchown(path string, uid int, gid int) (errno int) { - r0, r1, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid)); - errno = int(e1); - return; -} - -func Link(oldpath string, newpath string) (errno int) { - r0, r1, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(StringBytePtr(oldpath))), uintptr(unsafe.Pointer(StringBytePtr(newpath))), 0); - errno = int(e1); - return; -} - -func Lstat(path string, stat *Stat_t) (errno int) { - r0, r1, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0); - errno = int(e1); - return; -} - -func Mkdir(path string, mode int) (errno int) { - r0, r1, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0); - errno = int(e1); - return; -} - -func Mkdirat(dirfd int, path string, mode int) (errno int) { - r0, r1, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode)); - errno = int(e1); - return; -} - -func Mknod(path string, mode int, dev int) (errno int) { - r0, r1, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(dev)); - errno = int(e1); - return; -} - -func Mknodat(dirfd int, path string, mode int, dev int) (errno int) { - r0, r1, e1 := Syscall6(SYS_MKNODAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(dev), 0, 0); - errno = int(e1); - return; -} - -func Nanosleep(time *Timespec, leftover *Timespec) (errno int) { - r0, r1, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0); - errno = int(e1); - return; -} - -func Open(path string, mode int, perm int) (fd int, errno int) { - r0, r1, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(perm)); - fd = int(r0); - errno = int(e1); - return; -} - -func Openat(dirfd int, path string, flags int, mode int) (fd int, errno int) { - r0, r1, e1 := Syscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), uintptr(mode), 0, 0); - fd = int(r0); - errno = int(e1); - return; -} - -func Pause() (errno int) { - r0, r1, e1 := Syscall(SYS_PAUSE, 0, 0, 0); - errno = int(e1); - return; -} - -func PivotRoot(newroot string, putold string) (errno int) { - r0, r1, e1 := Syscall(SYS_PIVOT_ROOT, uintptr(unsafe.Pointer(StringBytePtr(newroot))), uintptr(unsafe.Pointer(StringBytePtr(putold))), 0); - errno = int(e1); - return; -} - -func Pread(fd int, p []byte, offset int64) (n int, errno int) { - var _p0 *byte; - if len(p) > 0 { _p0 = &p[0]; } - r0, r1, e1 := Syscall6(SYS_PREAD64, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), uintptr(offset >> 32), 0); - n = int(r0); - errno = int(e1); - return; -} - -func Pwrite(fd int, p []byte, offset int64) (n int, errno int) { - var _p0 *byte; - if len(p) > 0 { _p0 = &p[0]; } - r0, r1, e1 := Syscall6(SYS_PWRITE64, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), uintptr(offset >> 32), 0); - n = int(r0); - errno = int(e1); - return; -} - -func Read(fd int, p []byte) (n int, errno int) { - var _p0 *byte; - if len(p) > 0 { _p0 = &p[0]; } - r0, r1, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p))); - n = int(r0); - errno = int(e1); - return; -} - -func Readlink(path string, buf []byte) (n int, errno int) { - var _p0 *byte; - if len(buf) > 0 { _p0 = &buf[0]; } - r0, r1, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf))); - n = int(r0); - errno = int(e1); - return; -} - -func Rename(oldpath string, newpath string) (errno int) { - r0, r1, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(StringBytePtr(oldpath))), uintptr(unsafe.Pointer(StringBytePtr(newpath))), 0); - errno = int(e1); - return; -} - -func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (errno int) { - r0, r1, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(StringBytePtr(oldpath))), uintptr(newdirfd), uintptr(unsafe.Pointer(StringBytePtr(newpath))), 0, 0); - errno = int(e1); - return; -} - -func Rmdir(path string) (errno int) { - r0, r1, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); - errno = int(e1); - return; -} - -func Seek(fd int, offset int64, whence int) (off int64, errno int) { - r0, r1, e1 := Syscall6(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(offset >> 32), uintptr(whence), 0, 0); - off = int64(r0); - errno = int(e1); - return; -} - -func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, errno int) { - r0, r1, 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; -} - -func Setdomainname(p []byte) (errno int) { - var _p0 *byte; - if len(p) > 0 { _p0 = &p[0]; } - r0, r1, e1 := Syscall(SYS_SETDOMAINNAME, uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), 0); - errno = int(e1); - return; -} - -func Setfsgid(gid int) (errno int) { - r0, r1, e1 := Syscall(SYS_SETFSGID, uintptr(gid), 0, 0); - errno = int(e1); - return; -} - -func Setfsuid(uid int) (errno int) { - r0, r1, e1 := Syscall(SYS_SETFSUID, uintptr(uid), 0, 0); - errno = int(e1); - return; -} - -func Setgid(gid int) (errno int) { - r0, r1, e1 := Syscall(SYS_SETGID, uintptr(gid), 0, 0); - errno = int(e1); - return; -} - -func Sethostname(p []byte) (errno int) { - var _p0 *byte; - if len(p) > 0 { _p0 = &p[0]; } - r0, r1, e1 := Syscall(SYS_SETHOSTNAME, uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), 0); - errno = int(e1); - return; -} - -func Setpgid(pid int, pgid int) (errno int) { - r0, r1, e1 := Syscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0); - errno = int(e1); - return; -} - -func Setregid(rgid int, egid int) (errno int) { - r0, r1, e1 := Syscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0); - errno = int(e1); - return; -} - -func Setresgid(rgid int, egid int, sgid int) (errno int) { - r0, r1, e1 := Syscall(SYS_SETRESGID, uintptr(rgid), uintptr(egid), uintptr(sgid)); - errno = int(e1); - return; -} - -func Setresuid(ruid int, euid int, suid int) (errno int) { - r0, r1, e1 := Syscall(SYS_SETRESUID, uintptr(ruid), uintptr(euid), uintptr(suid)); - errno = int(e1); - return; -} - -func Setreuid(ruid int, euid int) (errno int) { - r0, r1, e1 := Syscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0); - errno = int(e1); - return; -} - -func Setrlimit(resource int, rlim *Rlimit) (errno int) { - r0, r1, e1 := Syscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0); - errno = int(e1); - return; -} - -func Setsid() (pid int) { - r0, r1, e1 := Syscall(SYS_SETSID, 0, 0, 0); - pid = int(r0); - return; -} - -func Settimeofday(tv *Timeval) (errno int) { - r0, r1, e1 := Syscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0); - errno = int(e1); - return; -} - -func Setuid(uid int) (errno int) { - r0, r1, e1 := Syscall(SYS_SETUID, uintptr(uid), 0, 0); - errno = int(e1); - return; -} - -func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, errno int) { - r0, r1, e1 := Syscall6(SYS_SPLICE, uintptr(rfd), uintptr(unsafe.Pointer(roff)), uintptr(wfd), uintptr(unsafe.Pointer(woff)), uintptr(len), uintptr(flags)); - n = int64(r0); - errno = int(e1); - return; -} - -func Stat(path string, stat *Stat_t) (errno int) { - r0, r1, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0); - errno = int(e1); - return; -} - -func Statfs(path string, buf *Statfs_t) (errno int) { - r0, r1, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(buf)), 0); - errno = int(e1); - return; -} - -func Symlink(oldpath string, newpath string) (errno int) { - r0, r1, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(StringBytePtr(oldpath))), uintptr(unsafe.Pointer(StringBytePtr(newpath))), 0); - errno = int(e1); - return; -} - -func Sync() () { - r0, r1, e1 := Syscall(SYS_SYNC, 0, 0, 0); - return; -} - -func SyncFileRange(fd int, off int64, n int64, flags int) (errno int) { - r0, r1, e1 := Syscall6(SYS_SYNC_FILE_RANGE, uintptr(fd), uintptr(off), uintptr(off >> 32), uintptr(n), uintptr(n >> 32), uintptr(flags)); - errno = int(e1); - return; -} - -func Sysinfo(info *Sysinfo_t) (errno int) { - r0, r1, e1 := Syscall(SYS_SYSINFO, uintptr(unsafe.Pointer(info)), 0, 0); - errno = int(e1); - return; -} - -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(r0); - errno = int(e1); - return; -} - -func Tgkill(tgid int, tid int, sig int) (errno int) { - r0, r1, e1 := Syscall(SYS_TGKILL, uintptr(tgid), uintptr(tid), uintptr(sig)); - errno = int(e1); - return; -} - -func Time(t *Time_t) (tt Time_t, errno int) { - r0, r1, e1 := Syscall(SYS_TIME, uintptr(unsafe.Pointer(t)), 0, 0); - tt = Time_t(r0); - errno = int(e1); - return; -} - -func Times(tms *Tms) (ticks uintptr, errno int) { - r0, r1, e1 := Syscall(SYS_TIMES, uintptr(unsafe.Pointer(tms)), 0, 0); - ticks = uintptr(r0); - errno = int(e1); - return; -} - -func Truncate(path string, length int64) (errno int) { - r0, r1, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(length), uintptr(length >> 32)); - errno = int(e1); - return; -} - -func Umask(mask int) (oldmask int) { - r0, r1, e1 := Syscall(SYS_UMASK, uintptr(mask), 0, 0); - oldmask = int(r0); - return; -} - -func Uname(buf *Utsname) (errno int) { - r0, r1, e1 := Syscall(SYS_UNAME, uintptr(unsafe.Pointer(buf)), 0, 0); - errno = int(e1); - return; -} - -func Unlink(path string) (errno int) { - r0, r1, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); - errno = int(e1); - return; -} - -func Unlinkat(dirfd int, path string) (errno int) { - r0, r1, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), 0); - errno = int(e1); - return; -} - -func Unshare(flags int) (errno int) { - r0, r1, e1 := Syscall(SYS_UNSHARE, uintptr(flags), 0, 0); - errno = int(e1); - return; -} - -func Ustat(dev int, ubuf *Ustat_t) (errno int) { - r0, r1, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0); - errno = int(e1); - return; -} - -func Utime(path string, buf *Utimbuf) (errno int) { - r0, r1, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(buf)), 0); - errno = int(e1); - return; -} - -func Write(fd int, p []byte) (n int, errno int) { - var _p0 *byte; - if len(p) > 0 { _p0 = &p[0]; } - r0, r1, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p))); - n = int(r0); - errno = int(e1); - return; -} - -func exitThread(code int) (errno int) { - r0, r1, e1 := Syscall(SYS_EXIT, uintptr(code), 0, 0); - errno = int(e1); - return; -} - -func read(fd int, p *byte, np int) (n int, errno int) { - r0, r1, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np)); - n = int(r0); - errno = int(e1); - return; -} - -func write(fd int, p *byte, np int) (n int, errno int) { - r0, r1, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np)); - n = int(r0); - errno = int(e1); - return; -} - - - diff --git a/src/lib/syscall/zsyscall_linux_amd64.go b/src/lib/syscall/zsyscall_linux_amd64.go deleted file mode 100644 index 490ffc392..000000000 --- a/src/lib/syscall/zsyscall_linux_amd64.go +++ /dev/null @@ -1,764 +0,0 @@ -// mksyscall syscall_linux.go syscall_linux_amd64.go -// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT - -package syscall - -import ( - "syscall"; - "unsafe"; -) - -func pipe(p *[2]_C_int) (errno int) { - r0, r1, e1 := Syscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0); - errno = int(e1); - return; -} - -func utimes(path string, times *[2]Timeval) (errno int) { - r0, r1, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(times)), 0); - errno = int(e1); - return; -} - -func futimesat(dirfd int, path string, times *[2]Timeval) (errno int) { - r0, r1, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(times))); - errno = int(e1); - return; -} - -func Getcwd(buf []byte) (n int, errno int) { - var _p0 *byte; - if len(buf) > 0 { _p0 = &buf[0]; } - r0, r1, e1 := Syscall(SYS_GETCWD, uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), 0); - n = int(r0); - errno = int(e1); - return; -} - -func getgroups(n int, list *_Gid_t) (nn int, errno int) { - r0, r1, e1 := Syscall(SYS_GETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0); - nn = int(r0); - errno = int(e1); - return; -} - -func setgroups(n int, list *_Gid_t) (errno int) { - r0, r1, e1 := Syscall(SYS_SETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0); - errno = int(e1); - return; -} - -func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, errno int) { - r0, r1, 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; -} - -func Access(path string, mode int) (errno int) { - r0, r1, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0); - errno = int(e1); - return; -} - -func Acct(path string) (errno int) { - r0, r1, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); - errno = int(e1); - return; -} - -func Adjtimex(buf *Timex) (state int, errno int) { - r0, r1, e1 := Syscall(SYS_ADJTIMEX, uintptr(unsafe.Pointer(buf)), 0, 0); - state = int(r0); - errno = int(e1); - return; -} - -func Chdir(path string) (errno int) { - r0, r1, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); - errno = int(e1); - return; -} - -func Chmod(path string, mode int) (errno int) { - r0, r1, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0); - errno = int(e1); - return; -} - -func Chown(path string, uid int, gid int) (errno int) { - r0, r1, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid)); - errno = int(e1); - return; -} - -func Chroot(path string) (errno int) { - r0, r1, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); - errno = int(e1); - return; -} - -func Close(fd int) (errno int) { - r0, r1, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0); - errno = int(e1); - return; -} - -func Creat(path string, mode int) (fd int, errno int) { - r0, r1, e1 := Syscall(SYS_CREAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0); - fd = int(r0); - errno = int(e1); - return; -} - -func Dup(oldfd int) (fd int, errno int) { - r0, r1, e1 := Syscall(SYS_DUP, uintptr(oldfd), 0, 0); - fd = int(r0); - errno = int(e1); - return; -} - -func Dup2(oldfd int, newfd int) (fd int, errno int) { - r0, r1, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0); - fd = int(r0); - errno = int(e1); - return; -} - -func EpollCreate(size int) (fd int, errno int) { - r0, r1, e1 := Syscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0); - fd = int(r0); - errno = int(e1); - return; -} - -func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (errno int) { - r0, r1, e1 := Syscall6(SYS_EPOLL_CTL, uintptr(epfd), uintptr(op), uintptr(fd), uintptr(unsafe.Pointer(event)), 0, 0); - errno = int(e1); - return; -} - -func EpollWait(epfd int, events []EpollEvent, msec int) (n int, errno int) { - var _p0 *EpollEvent; - if len(events) > 0 { _p0 = &events[0]; } - r0, r1, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(unsafe.Pointer(_p0)), uintptr(len(events)), uintptr(msec), 0, 0); - n = int(r0); - errno = int(e1); - return; -} - -func Exit(code int) () { - r0, r1, e1 := Syscall(SYS_EXIT_GROUP, uintptr(code), 0, 0); - return; -} - -func Faccessat(dirfd int, path string, mode int, flags int) (errno int) { - r0, r1, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(flags), 0, 0); - errno = int(e1); - return; -} - -func Fallocate(fd int, mode int, off int64, len int64) (errno int) { - r0, r1, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(len), 0, 0); - errno = int(e1); - return; -} - -func Fchdir(fd int) (errno int) { - r0, r1, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0); - errno = int(e1); - return; -} - -func Fchmod(fd int, mode int) (errno int) { - r0, r1, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0); - errno = int(e1); - return; -} - -func Fchmodat(dirfd int, path string, mode int, flags int) (errno int) { - r0, r1, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(flags), 0, 0); - errno = int(e1); - return; -} - -func Fchown(fd int, uid int, gid int) (errno int) { - r0, r1, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid)); - errno = int(e1); - return; -} - -func Fchownat(dirfd int, path string, uid int, gid int, flags int) (errno int) { - r0, r1, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid), uintptr(flags), 0); - errno = int(e1); - return; -} - -func fcntl(fd int, cmd int, arg int) (val int, errno int) { - r0, r1, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg)); - val = int(r0); - errno = int(e1); - return; -} - -func Fdatasync(fd int) (errno int) { - r0, r1, e1 := Syscall(SYS_FDATASYNC, uintptr(fd), 0, 0); - errno = int(e1); - return; -} - -func Fstat(fd int, stat *Stat_t) (errno int) { - r0, r1, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0); - errno = int(e1); - return; -} - -func Fstatfs(fd int, buf *Statfs_t) (errno int) { - r0, r1, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(buf)), 0); - errno = int(e1); - return; -} - -func Fsync(fd int) (errno int) { - r0, r1, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0); - errno = int(e1); - return; -} - -func Ftruncate(fd int, length int64) (errno int) { - r0, r1, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), 0); - errno = int(e1); - return; -} - -func Getdents(fd int, buf []byte) (n int, errno int) { - var _p0 *byte; - if len(buf) > 0 { _p0 = &buf[0]; } - r0, r1, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf))); - n = int(r0); - errno = int(e1); - return; -} - -func Getegid() (egid int) { - r0, r1, e1 := Syscall(SYS_GETEGID, 0, 0, 0); - egid = int(r0); - return; -} - -func Geteuid() (euid int) { - r0, r1, e1 := Syscall(SYS_GETEUID, 0, 0, 0); - euid = int(r0); - return; -} - -func Getgid() (gid int) { - r0, r1, e1 := Syscall(SYS_GETGID, 0, 0, 0); - gid = int(r0); - return; -} - -func Getpgid(pid int) (pgid int, errno int) { - r0, r1, e1 := Syscall(SYS_GETPGID, uintptr(pid), 0, 0); - pgid = int(r0); - errno = int(e1); - return; -} - -func Getpgrp() (pid int) { - r0, r1, e1 := Syscall(SYS_GETPGRP, 0, 0, 0); - pid = int(r0); - return; -} - -func Getpid() (pid int) { - r0, r1, e1 := Syscall(SYS_GETPID, 0, 0, 0); - pid = int(r0); - return; -} - -func Getppid() (ppid int) { - r0, r1, e1 := Syscall(SYS_GETPPID, 0, 0, 0); - ppid = int(r0); - return; -} - -func Getrlimit(resource int, rlim *Rlimit) (errno int) { - r0, r1, e1 := Syscall(SYS_GETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0); - errno = int(e1); - return; -} - -func Getrusage(who int, rusage *Rusage) (errno int) { - r0, r1, e1 := Syscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0); - errno = int(e1); - return; -} - -func Gettid() (tid int) { - r0, r1, e1 := Syscall(SYS_GETTID, 0, 0, 0); - tid = int(r0); - return; -} - -func Gettimeofday(tv *Timeval) (errno int) { - r0, r1, e1 := Syscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0); - errno = int(e1); - return; -} - -func Getuid() (uid int) { - r0, r1, e1 := Syscall(SYS_GETUID, 0, 0, 0); - uid = int(r0); - return; -} - -func Ioperm(from int, num int, on int) (errno int) { - r0, r1, e1 := Syscall(SYS_IOPERM, uintptr(from), uintptr(num), uintptr(on)); - errno = int(e1); - return; -} - -func Iopl(level int) (errno int) { - r0, r1, e1 := Syscall(SYS_IOPL, uintptr(level), 0, 0); - errno = int(e1); - return; -} - -func Kill(pid int, sig int) (errno int) { - r0, r1, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(sig), 0); - errno = int(e1); - return; -} - -func Klogctl(typ int, buf []byte) (n int, errno int) { - var _p0 *byte; - if len(buf) > 0 { _p0 = &buf[0]; } - r0, r1, e1 := Syscall(SYS_SYSLOG, uintptr(typ), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf))); - n = int(r0); - errno = int(e1); - return; -} - -func Lchown(path string, uid int, gid int) (errno int) { - r0, r1, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid)); - errno = int(e1); - return; -} - -func Link(oldpath string, newpath string) (errno int) { - r0, r1, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(StringBytePtr(oldpath))), uintptr(unsafe.Pointer(StringBytePtr(newpath))), 0); - errno = int(e1); - return; -} - -func Lstat(path string, stat *Stat_t) (errno int) { - r0, r1, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0); - errno = int(e1); - return; -} - -func Mkdir(path string, mode int) (errno int) { - r0, r1, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0); - errno = int(e1); - return; -} - -func Mkdirat(dirfd int, path string, mode int) (errno int) { - r0, r1, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode)); - errno = int(e1); - return; -} - -func Mknod(path string, mode int, dev int) (errno int) { - r0, r1, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(dev)); - errno = int(e1); - return; -} - -func Mknodat(dirfd int, path string, mode int, dev int) (errno int) { - r0, r1, e1 := Syscall6(SYS_MKNODAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(dev), 0, 0); - errno = int(e1); - return; -} - -func Nanosleep(time *Timespec, leftover *Timespec) (errno int) { - r0, r1, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0); - errno = int(e1); - return; -} - -func Open(path string, mode int, perm int) (fd int, errno int) { - r0, r1, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(perm)); - fd = int(r0); - errno = int(e1); - return; -} - -func Openat(dirfd int, path string, flags int, mode int) (fd int, errno int) { - r0, r1, e1 := Syscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), uintptr(mode), 0, 0); - fd = int(r0); - errno = int(e1); - return; -} - -func Pause() (errno int) { - r0, r1, e1 := Syscall(SYS_PAUSE, 0, 0, 0); - errno = int(e1); - return; -} - -func PivotRoot(newroot string, putold string) (errno int) { - r0, r1, e1 := Syscall(SYS_PIVOT_ROOT, uintptr(unsafe.Pointer(StringBytePtr(newroot))), uintptr(unsafe.Pointer(StringBytePtr(putold))), 0); - errno = int(e1); - return; -} - -func Pread(fd int, p []byte, offset int64) (n int, errno int) { - var _p0 *byte; - if len(p) > 0 { _p0 = &p[0]; } - r0, r1, e1 := Syscall6(SYS_PREAD64, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), 0, 0); - n = int(r0); - errno = int(e1); - return; -} - -func Pwrite(fd int, p []byte, offset int64) (n int, errno int) { - var _p0 *byte; - if len(p) > 0 { _p0 = &p[0]; } - r0, r1, e1 := Syscall6(SYS_PWRITE64, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), 0, 0); - n = int(r0); - errno = int(e1); - return; -} - -func Read(fd int, p []byte) (n int, errno int) { - var _p0 *byte; - if len(p) > 0 { _p0 = &p[0]; } - r0, r1, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p))); - n = int(r0); - errno = int(e1); - return; -} - -func Readlink(path string, buf []byte) (n int, errno int) { - var _p0 *byte; - if len(buf) > 0 { _p0 = &buf[0]; } - r0, r1, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf))); - n = int(r0); - errno = int(e1); - return; -} - -func Rename(oldpath string, newpath string) (errno int) { - r0, r1, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(StringBytePtr(oldpath))), uintptr(unsafe.Pointer(StringBytePtr(newpath))), 0); - errno = int(e1); - return; -} - -func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (errno int) { - r0, r1, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(StringBytePtr(oldpath))), uintptr(newdirfd), uintptr(unsafe.Pointer(StringBytePtr(newpath))), 0, 0); - errno = int(e1); - return; -} - -func Rmdir(path string) (errno int) { - r0, r1, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); - errno = int(e1); - return; -} - -func Seek(fd int, offset int64, whence int) (off int64, errno int) { - r0, r1, e1 := Syscall(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence)); - off = int64(r0); - errno = int(e1); - return; -} - -func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, errno int) { - r0, r1, 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; -} - -func Setdomainname(p []byte) (errno int) { - var _p0 *byte; - if len(p) > 0 { _p0 = &p[0]; } - r0, r1, e1 := Syscall(SYS_SETDOMAINNAME, uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), 0); - errno = int(e1); - return; -} - -func Setfsgid(gid int) (errno int) { - r0, r1, e1 := Syscall(SYS_SETFSGID, uintptr(gid), 0, 0); - errno = int(e1); - return; -} - -func Setfsuid(uid int) (errno int) { - r0, r1, e1 := Syscall(SYS_SETFSUID, uintptr(uid), 0, 0); - errno = int(e1); - return; -} - -func Setgid(gid int) (errno int) { - r0, r1, e1 := Syscall(SYS_SETGID, uintptr(gid), 0, 0); - errno = int(e1); - return; -} - -func Sethostname(p []byte) (errno int) { - var _p0 *byte; - if len(p) > 0 { _p0 = &p[0]; } - r0, r1, e1 := Syscall(SYS_SETHOSTNAME, uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), 0); - errno = int(e1); - return; -} - -func Setpgid(pid int, pgid int) (errno int) { - r0, r1, e1 := Syscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0); - errno = int(e1); - return; -} - -func Setregid(rgid int, egid int) (errno int) { - r0, r1, e1 := Syscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0); - errno = int(e1); - return; -} - -func Setresgid(rgid int, egid int, sgid int) (errno int) { - r0, r1, e1 := Syscall(SYS_SETRESGID, uintptr(rgid), uintptr(egid), uintptr(sgid)); - errno = int(e1); - return; -} - -func Setresuid(ruid int, euid int, suid int) (errno int) { - r0, r1, e1 := Syscall(SYS_SETRESUID, uintptr(ruid), uintptr(euid), uintptr(suid)); - errno = int(e1); - return; -} - -func Setreuid(ruid int, euid int) (errno int) { - r0, r1, e1 := Syscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0); - errno = int(e1); - return; -} - -func Setrlimit(resource int, rlim *Rlimit) (errno int) { - r0, r1, e1 := Syscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0); - errno = int(e1); - return; -} - -func Setsid() (pid int) { - r0, r1, e1 := Syscall(SYS_SETSID, 0, 0, 0); - pid = int(r0); - return; -} - -func Settimeofday(tv *Timeval) (errno int) { - r0, r1, e1 := Syscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0); - errno = int(e1); - return; -} - -func Setuid(uid int) (errno int) { - r0, r1, e1 := Syscall(SYS_SETUID, uintptr(uid), 0, 0); - errno = int(e1); - return; -} - -func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, errno int) { - r0, r1, e1 := Syscall6(SYS_SPLICE, uintptr(rfd), uintptr(unsafe.Pointer(roff)), uintptr(wfd), uintptr(unsafe.Pointer(woff)), uintptr(len), uintptr(flags)); - n = int64(r0); - errno = int(e1); - return; -} - -func Stat(path string, stat *Stat_t) (errno int) { - r0, r1, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0); - errno = int(e1); - return; -} - -func Statfs(path string, buf *Statfs_t) (errno int) { - r0, r1, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(buf)), 0); - errno = int(e1); - return; -} - -func Symlink(oldpath string, newpath string) (errno int) { - r0, r1, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(StringBytePtr(oldpath))), uintptr(unsafe.Pointer(StringBytePtr(newpath))), 0); - errno = int(e1); - return; -} - -func Sync() () { - r0, r1, e1 := Syscall(SYS_SYNC, 0, 0, 0); - return; -} - -func SyncFileRange(fd int, off int64, n int64, flags int) (errno int) { - r0, r1, e1 := Syscall6(SYS_SYNC_FILE_RANGE, uintptr(fd), uintptr(off), uintptr(n), uintptr(flags), 0, 0); - errno = int(e1); - return; -} - -func Sysinfo(info *Sysinfo_t) (errno int) { - r0, r1, e1 := Syscall(SYS_SYSINFO, uintptr(unsafe.Pointer(info)), 0, 0); - errno = int(e1); - return; -} - -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(r0); - errno = int(e1); - return; -} - -func Tgkill(tgid int, tid int, sig int) (errno int) { - r0, r1, e1 := Syscall(SYS_TGKILL, uintptr(tgid), uintptr(tid), uintptr(sig)); - errno = int(e1); - return; -} - -func Time(t *Time_t) (tt Time_t, errno int) { - r0, r1, e1 := Syscall(SYS_TIME, uintptr(unsafe.Pointer(t)), 0, 0); - tt = Time_t(r0); - errno = int(e1); - return; -} - -func Times(tms *Tms) (ticks uintptr, errno int) { - r0, r1, e1 := Syscall(SYS_TIMES, uintptr(unsafe.Pointer(tms)), 0, 0); - ticks = uintptr(r0); - errno = int(e1); - return; -} - -func Truncate(path string, length int64) (errno int) { - r0, r1, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(length), 0); - errno = int(e1); - return; -} - -func Umask(mask int) (oldmask int) { - r0, r1, e1 := Syscall(SYS_UMASK, uintptr(mask), 0, 0); - oldmask = int(r0); - return; -} - -func Uname(buf *Utsname) (errno int) { - r0, r1, e1 := Syscall(SYS_UNAME, uintptr(unsafe.Pointer(buf)), 0, 0); - errno = int(e1); - return; -} - -func Unlink(path string) (errno int) { - r0, r1, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); - errno = int(e1); - return; -} - -func Unlinkat(dirfd int, path string) (errno int) { - r0, r1, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), 0); - errno = int(e1); - return; -} - -func Unshare(flags int) (errno int) { - r0, r1, e1 := Syscall(SYS_UNSHARE, uintptr(flags), 0, 0); - errno = int(e1); - return; -} - -func Ustat(dev int, ubuf *Ustat_t) (errno int) { - r0, r1, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0); - errno = int(e1); - return; -} - -func Utime(path string, buf *Utimbuf) (errno int) { - r0, r1, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(buf)), 0); - errno = int(e1); - return; -} - -func Write(fd int, p []byte) (n int, errno int) { - var _p0 *byte; - if len(p) > 0 { _p0 = &p[0]; } - r0, r1, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p))); - n = int(r0); - errno = int(e1); - return; -} - -func exitThread(code int) (errno int) { - r0, r1, e1 := Syscall(SYS_EXIT, uintptr(code), 0, 0); - errno = int(e1); - return; -} - -func read(fd int, p *byte, np int) (n int, errno int) { - r0, r1, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np)); - n = int(r0); - errno = int(e1); - return; -} - -func write(fd int, p *byte, np int) (n int, errno int) { - r0, r1, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np)); - n = int(r0); - errno = int(e1); - return; -} - -func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, errno int) { - r0, r1, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))); - fd = int(r0); - errno = int(e1); - return; -} - -func bind(s int, addr uintptr, addrlen _Socklen) (errno int) { - r0, r1, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen)); - errno = int(e1); - return; -} - -func connect(s int, addr uintptr, addrlen _Socklen) (errno int) { - r0, r1, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen)); - errno = int(e1); - return; -} - -func socket(domain int, typ int, proto int) (fd int, errno int) { - r0, r1, e1 := Syscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto)); - fd = int(r0); - errno = int(e1); - return; -} - -func setsockopt(s int, level int, name int, val uintptr, vallen int) (errno int) { - r0, r1, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0); - errno = int(e1); - return; -} - -func Listen(s int, n int) (errno int) { - r0, r1, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(n), 0); - errno = int(e1); - return; -} - -func Shutdown(fd int, how int) (errno int) { - r0, r1, e1 := Syscall(SYS_SHUTDOWN, uintptr(fd), uintptr(how), 0); - errno = int(e1); - return; -} - - - diff --git a/src/lib/syscall/zsysnum_darwin_386.go b/src/lib/syscall/zsysnum_darwin_386.go deleted file mode 100644 index c4c48c2a2..000000000 --- a/src/lib/syscall/zsysnum_darwin_386.go +++ /dev/null @@ -1,485 +0,0 @@ -// mksysnum_darwin /home/rsc/pub/xnu-1228/bsd/kern/syscalls.master -// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT - -package syscall - -const ( - // SYS_NOSYS = 0; // { int nosys(void); } { indirect syscall } - SYS_EXIT = 1; // { void exit(int rval); } - SYS_FORK = 2; // { int fork(void); } - SYS_READ = 3; // { user_ssize_t read(int fd, user_addr_t cbuf, user_size_t nbyte); } - SYS_WRITE = 4; // { user_ssize_t write(int fd, user_addr_t cbuf, user_size_t nbyte); } - SYS_OPEN = 5; // { int open(user_addr_t path, int flags, int mode); } - SYS_CLOSE = 6; // { int close(int fd); } - SYS_WAIT4 = 7; // { int wait4(int pid, user_addr_t status, int options, user_addr_t rusage); } - // SYS_NOSYS = 8; // { int nosys(void); } { old creat } - SYS_LINK = 9; // { int link(user_addr_t path, user_addr_t link); } - SYS_UNLINK = 10; // { int unlink(user_addr_t path); } - // SYS_NOSYS = 11; // { int nosys(void); } { old execv } - SYS_CHDIR = 12; // { int chdir(user_addr_t path); } - SYS_FCHDIR = 13; // { int fchdir(int fd); } - SYS_MKNOD = 14; // { int mknod(user_addr_t path, int mode, int dev); } - SYS_CHMOD = 15; // { int chmod(user_addr_t path, int mode); } - SYS_CHOWN = 16; // { int chown(user_addr_t path, int uid, int gid); } - SYS_OGETFSSTAT = 18; // { int ogetfsstat(user_addr_t buf, int bufsize, int flags); } - SYS_GETFSSTAT = 18; // { int getfsstat(user_addr_t buf, int bufsize, int flags); } - // SYS_NOSYS = 19; // { int nosys(void); } { old lseek } - SYS_GETPID = 20; // { int getpid(void); } - // SYS_NOSYS = 21; // { int nosys(void); } { old mount } - // SYS_NOSYS = 22; // { int nosys(void); } { old umount } - SYS_SETUID = 23; // { int setuid(uid_t uid); } - SYS_GETUID = 24; // { int getuid(void); } - SYS_GETEUID = 25; // { int geteuid(void); } - SYS_PTRACE = 26; // { int ptrace(int req, pid_t pid, caddr_t addr, int data); } - SYS_RECVMSG = 27; // { int recvmsg(int s, struct msghdr *msg, int flags); } - SYS_SENDMSG = 28; // { int sendmsg(int s, caddr_t msg, int flags); } - SYS_RECVFROM = 29; // { int recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, int *fromlenaddr); } - SYS_ACCEPT = 30; // { int accept(int s, caddr_t name, socklen_t *anamelen); } - SYS_GETPEERNAME = 31; // { int getpeername(int fdes, caddr_t asa, socklen_t *alen); } - SYS_GETSOCKNAME = 32; // { int getsockname(int fdes, caddr_t asa, socklen_t *alen); } - // SYS_NOSYS = 27; // { int nosys(void); } - // SYS_NOSYS = 28; // { int nosys(void); } - // SYS_NOSYS = 29; // { int nosys(void); } - // SYS_NOSYS = 30; // { int nosys(void); } - // SYS_NOSYS = 31; // { int nosys(void); } - // SYS_NOSYS = 32; // { int nosys(void); } - SYS_ACCESS = 33; // { int access(user_addr_t 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, int posix); } - // SYS_NOSYS = 38; // { int nosys(void); } { old stat } - SYS_GETPPID = 39; // { int getppid(void); } - // SYS_NOSYS = 40; // { int nosys(void); } { old lstat } - SYS_DUP = 41; // { int dup(u_int fd); } - SYS_PIPE = 42; // { int pipe(void); } - SYS_GETEGID = 43; // { int getegid(void); } - SYS_PROFIL = 44; // { int profil(short *bufbase, size_t bufsize, u_long pcoffset, u_int pcscale); } - // SYS_NOSYS = 45; // { int nosys(void); } { old ktrace } - SYS_SIGACTION = 46; // { int sigaction(int signum, struct __sigaction *nsa, struct sigaction *osa); } - SYS_GETGID = 47; // { int getgid(void); } - SYS_SIGPROCMASK = 48; // { int sigprocmask(int how, user_addr_t mask, user_addr_t omask); } - SYS_GETLOGIN = 49; // { int getlogin(char *namebuf, u_int namelen); } - SYS_SETLOGIN = 50; // { int setlogin(char *namebuf); } - SYS_ACCT = 51; // { int acct(char *path); } - SYS_SIGPENDING = 52; // { int sigpending(struct sigvec *osv); } - SYS_SIGALTSTACK = 53; // { int sigaltstack(struct sigaltstack *nss, struct sigaltstack *oss); } - SYS_IOCTL = 54; // { int ioctl(int fd, u_long com, caddr_t data); } - SYS_REBOOT = 55; // { int reboot(int opt, char *command); } - SYS_REVOKE = 56; // { int revoke(char *path); } - SYS_SYMLINK = 57; // { int symlink(char *path, char *link); } - SYS_READLINK = 58; // { int readlink(char *path, char *buf, int count); } - SYS_EXECVE = 59; // { int execve(char *fname, char **argp, char **envp); } - SYS_UMASK = 60; // { int umask(int newmask); } - SYS_CHROOT = 61; // { int chroot(user_addr_t path); } - // SYS_NOSYS = 62; // { int nosys(void); } { old fstat } - // SYS_NOSYS = 63; // { int nosys(void); } { used internally, reserved } - // SYS_NOSYS = 64; // { int nosys(void); } { old getpagesize } - SYS_MSYNC = 65; // { int msync(caddr_t addr, size_t len, int flags); } - SYS_VFORK = 66; // { int vfork(void); } - // SYS_NOSYS = 67; // { int nosys(void); } { old vread } - // SYS_NOSYS = 68; // { int nosys(void); } { old vwrite } - SYS_SBRK = 69; // { int sbrk(int incr) NO_SYSCALL_STUB; } - SYS_SSTK = 70; // { int sstk(int incr) NO_SYSCALL_STUB; } - // SYS_NOSYS = 71; // { int nosys(void); } { old mmap } - SYS_OVADVISE = 72; // { int ovadvise(void) NO_SYSCALL_STUB; } { old vadvise } - SYS_MUNMAP = 73; // { int munmap(caddr_t addr, size_t len); } - SYS_MPROTECT = 74; // { int mprotect(caddr_t addr, size_t len, int prot); } - SYS_MADVISE = 75; // { int madvise(caddr_t addr, size_t len, int behav); } - // SYS_NOSYS = 76; // { int nosys(void); } { old vhangup } - // SYS_NOSYS = 77; // { int nosys(void); } { old vlimit } - SYS_MINCORE = 78; // { int mincore(user_addr_t addr, user_size_t len, user_addr_t vec); } - SYS_GETGROUPS = 79; // { int getgroups(u_int gidsetsize, gid_t *gidset); } - SYS_SETGROUPS = 80; // { int setgroups(u_int gidsetsize, gid_t *gidset); } - SYS_GETPGRP = 81; // { int getpgrp(void); } - SYS_SETPGID = 82; // { int setpgid(int pid, int pgid); } - SYS_SETITIMER = 83; // { int setitimer(u_int which, struct itimerval *itv, struct itimerval *oitv); } - // SYS_NOSYS = 84; // { int nosys(void); } { old wait } - SYS_SWAPON = 85; // { int swapon(void); } - SYS_GETITIMER = 86; // { int getitimer(u_int which, struct itimerval *itv); } - // SYS_NOSYS = 87; // { int nosys(void); } { old gethostname } - // SYS_NOSYS = 88; // { int nosys(void); } { old sethostname } - SYS_GETDTABLESIZE = 89; // { int getdtablesize(void); } - SYS_DUP2 = 90; // { int dup2(u_int from, u_int to); } - // SYS_NOSYS = 91; // { int nosys(void); } { old getdopt } - SYS_FCNTL = 92; // { int fcntl(int fd, int cmd, long arg); } - SYS_SELECT = 93; // { int select(int nd, u_int32_t *in, u_int32_t *ou, u_int32_t *ex, struct timeval *tv); } - // SYS_NOSYS = 94; // { int nosys(void); } { old setdopt } - SYS_FSYNC = 95; // { int fsync(int fd); } - SYS_SETPRIORITY = 96; // { int setpriority(int which, id_t who, int prio); } - SYS_SOCKET = 97; // { int socket(int domain, int type, int protocol); } - SYS_CONNECT = 98; // { int connect(int s, caddr_t name, socklen_t namelen); } - // SYS_NOSYS = 97; // { int nosys(void); } - // SYS_NOSYS = 98; // { int nosys(void); } - // SYS_NOSYS = 99; // { int nosys(void); } { old accept } - SYS_GETPRIORITY = 100; // { int getpriority(int which, id_t who); } - // SYS_NOSYS = 101; // { int nosys(void); } { old send } - // SYS_NOSYS = 102; // { int nosys(void); } { old recv } - // SYS_NOSYS = 103; // { int nosys(void); } { old sigreturn } - SYS_BIND = 104; // { int bind(int s, caddr_t name, socklen_t namelen); } - SYS_SETSOCKOPT = 105; // { int setsockopt(int s, int level, int name, caddr_t val, socklen_t valsize); } - SYS_LISTEN = 106; // { int listen(int s, int backlog); } - // SYS_NOSYS = 104; // { int nosys(void); } - // SYS_NOSYS = 105; // { int nosys(void); } - // SYS_NOSYS = 106; // { int nosys(void); } - // SYS_NOSYS = 107; // { int nosys(void); } { old vtimes } - // SYS_NOSYS = 108; // { int nosys(void); } { old sigvec } - // SYS_NOSYS = 109; // { int nosys(void); } { old sigblock } - // SYS_NOSYS = 110; // { int nosys(void); } { old sigsetmask } - SYS_SIGSUSPEND = 111; // { int sigsuspend(sigset_t mask); } - // SYS_NOSYS = 112; // { int nosys(void); } { old sigstack } - // SYS_NOSYS = 113; // { int nosys(void); } { old recvmsg } - // SYS_NOSYS = 114; // { int nosys(void); } { old sendmsg } - // SYS_NOSYS = 113; // { int nosys(void); } - // SYS_NOSYS = 114; // { int nosys(void); } - // SYS_NOSYS = 115; // { int nosys(void); } { old vtrace } - SYS_GETTIMEOFDAY = 116; // { int gettimeofday(struct timeval *tp, struct timezone *tzp); } - SYS_GETRUSAGE = 117; // { int getrusage(int who, struct rusage *rusage); } - SYS_GETSOCKOPT = 118; // { int getsockopt(int s, int level, int name, caddr_t val, socklen_t *avalsize); } - // SYS_NOSYS = 118; // { int nosys(void); } - // SYS_NOSYS = 119; // { int nosys(void); } { old resuba } - SYS_READV = 120; // { user_ssize_t readv(int fd, struct iovec *iovp, u_int iovcnt); } - SYS_WRITEV = 121; // { user_ssize_t writev(int fd, struct iovec *iovp, u_int iovcnt); } - SYS_SETTIMEOFDAY = 122; // { int settimeofday(struct timeval *tv, struct timezone *tzp); } - SYS_FCHOWN = 123; // { int fchown(int fd, int uid, int gid); } - SYS_FCHMOD = 124; // { int fchmod(int fd, int mode); } - // SYS_NOSYS = 125; // { int nosys(void); } { old recvfrom } - SYS_SETREUID = 126; // { int setreuid(uid_t ruid, uid_t euid); } - SYS_SETREGID = 127; // { int setregid(gid_t rgid, gid_t egid); } - SYS_RENAME = 128; // { int rename(char *from, char *to); } - // SYS_NOSYS = 129; // { int nosys(void); } { old truncate } - // SYS_NOSYS = 130; // { int nosys(void); } { old ftruncate } - SYS_FLOCK = 131; // { int flock(int fd, int how); } - SYS_MKFIFO = 132; // { int mkfifo(user_addr_t path, int mode); } - SYS_SENDTO = 133; // { int sendto(int s, caddr_t buf, size_t len, int flags, caddr_t to, socklen_t tolen); } - SYS_SHUTDOWN = 134; // { int shutdown(int s, int how); } - SYS_SOCKETPAIR = 135; // { int socketpair(int domain, int type, int protocol, int *rsv); } - // SYS_NOSYS = 133; // { int nosys(void); } - // SYS_NOSYS = 134; // { int nosys(void); } - // SYS_NOSYS = 135; // { int nosys(void); } - SYS_MKDIR = 136; // { int mkdir(user_addr_t path, int mode); } - SYS_RMDIR = 137; // { int rmdir(char *path); } - SYS_UTIMES = 138; // { int utimes(char *path, struct timeval *tptr); } - SYS_FUTIMES = 139; // { int futimes(int fd, struct timeval *tptr); } - SYS_ADJTIME = 140; // { int adjtime(struct timeval *delta, struct timeval *olddelta); } - // SYS_NOSYS = 141; // { int nosys(void); } { old getpeername } - SYS_GETHOSTUUID = 142; // { int gethostuuid(unsigned char *uuid_buf, const struct timespec *timeoutp); } - // SYS_NOSYS = 143; // { int nosys(void); } { old sethostid } - // SYS_NOSYS = 144; // { int nosys(void); } { old getrlimit } - // SYS_NOSYS = 145; // { int nosys(void); } { old setrlimit } - // SYS_NOSYS = 146; // { int nosys(void); } { old killpg } - SYS_SETSID = 147; // { int setsid(void); } - // SYS_NOSYS = 148; // { int nosys(void); } { old setquota } - // SYS_NOSYS = 149; // { int nosys(void); } { old qquota } - // SYS_NOSYS = 150; // { int nosys(void); } { old getsockname } - SYS_GETPGID = 151; // { int getpgid(pid_t pid); } - SYS_SETPRIVEXEC = 152; // { int setprivexec(int flag); } - SYS_PREAD = 153; // { user_ssize_t pread(int fd, user_addr_t buf, user_size_t nbyte, off_t offset); } - SYS_PWRITE = 154; // { user_ssize_t pwrite(int fd, user_addr_t buf, user_size_t nbyte, off_t offset); } - SYS_NFSSVC = 155; // { int nfssvc(int flag, caddr_t argp); } - // SYS_NOSYS = 155; // { int nosys(void); } - // SYS_NOSYS = 156; // { int nosys(void); } { old getdirentries } - SYS_STATFS = 157; // { int statfs(char *path, struct statfs *buf); } - SYS_FSTATFS = 158; // { int fstatfs(int fd, struct statfs *buf); } - SYS_UNMOUNT = 159; // { int unmount(user_addr_t path, int flags); } - // SYS_NOSYS = 160; // { int nosys(void); } { old async_daemon } - SYS_GETFH = 161; // { int getfh(char *fname, fhandle_t *fhp); } - // SYS_NOSYS = 161; // { int nosys(void); } - // SYS_NOSYS = 162; // { int nosys(void); } { old getdomainname } - // SYS_NOSYS = 163; // { int nosys(void); } { old setdomainname } - // SYS_NOSYS = 164; // { int nosys(void); } - SYS_QUOTACTL = 165; // { int quotactl(const char *path, int cmd, int uid, caddr_t arg); } - // SYS_NOSYS = 166; // { int nosys(void); } { old exportfs } - SYS_MOUNT = 167; // { int mount(char *type, char *path, int flags, caddr_t data); } - // SYS_NOSYS = 168; // { int nosys(void); } { old ustat } - SYS_CSOPS = 169; // { int csops(pid_t pid, uint32_t ops, user_addr_t useraddr, user_size_t usersize); } - // SYS_NOSYS = 171; // { int nosys(void); } { old wait3 } - // SYS_NOSYS = 172; // { int nosys(void); } { old rpause } - SYS_WAITID = 173; // { int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options); } - // SYS_NOSYS = 174; // { int nosys(void); } { old getdents } - // SYS_NOSYS = 175; // { int nosys(void); } { old gc_control } - SYS_ADD_PROFIL = 176; // { int add_profil(short *bufbase, size_t bufsize, u_long pcoffset, u_int pcscale); } - // SYS_NOSYS = 177; // { int nosys(void); } - // SYS_NOSYS = 178; // { int nosys(void); } - // SYS_NOSYS = 179; // { int nosys(void); } - SYS_KDEBUG_TRACE = 180; // { int kdebug_trace(int code, int arg1, int arg2, int arg3, int arg4, int arg5) NO_SYSCALL_STUB; } - 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_SIGRETURN = 184; // { int sigreturn(struct ucontext *uctx, int infostyle); } - // SYS_NOSYS = 186; // { int nosys(void); } - // SYS_NOSYS = 187; // { int nosys(void); } - SYS_STAT = 188; // { int stat(user_addr_t path, user_addr_t ub); } - SYS_FSTAT = 189; // { int fstat(int fd, user_addr_t ub); } - SYS_LSTAT = 190; // { int lstat(user_addr_t path, user_addr_t ub); } - SYS_PATHCONF = 191; // { int pathconf(char *path, int name); } - SYS_FPATHCONF = 192; // { int fpathconf(int fd, int name); } - // SYS_NOSYS = 193; // { int nosys(void); } - SYS_GETRLIMIT = 194; // { int getrlimit(u_int which, struct rlimit *rlp); } - SYS_SETRLIMIT = 195; // { int setrlimit(u_int which, struct rlimit *rlp); } - SYS_GETDIRENTRIES = 196; // { int getdirentries(int fd, char *buf, u_int count, long *basep); } - SYS_MMAP = 197; // { user_addr_t mmap(caddr_t addr, size_t len, int prot, int flags, int fd, off_t pos); } - // SYS_NOSYS = 198; // { int nosys(void); } { __syscall } - SYS_LSEEK = 199; // { off_t lseek(int fd, off_t offset, int whence); } - SYS_TRUNCATE = 200; // { int truncate(char *path, off_t length); } - SYS_FTRUNCATE = 201; // { int ftruncate(int fd, off_t length); } - SYS___SYSCTL = 202; // { int __sysctl(int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen); } - SYS_MLOCK = 203; // { int mlock(caddr_t addr, size_t len); } - SYS_MUNLOCK = 204; // { int munlock(caddr_t addr, size_t len); } - SYS_UNDELETE = 205; // { int undelete(user_addr_t path); } - SYS_ATSOCKET = 206; // { int ATsocket(int proto); } - // SYS_NOSYS = 213; // { int nosys(void); } { Reserved for AppleTalk } - // SYS_NOSYS = 206; // { int nosys(void); } - // SYS_NOSYS = 207; // { int nosys(void); } - // SYS_NOSYS = 208; // { int nosys(void); } - // SYS_NOSYS = 209; // { int nosys(void); } - // SYS_NOSYS = 210; // { int nosys(void); } - // SYS_NOSYS = 211; // { int nosys(void); } - // SYS_NOSYS = 212; // { int nosys(void); } - // SYS_NOSYS = 213; // { int nosys(void); } { Reserved for AppleTalk } - SYS_KQUEUE_FROM_PORTSET_NP = 214; // { int kqueue_from_portset_np(int portset); } - SYS_KQUEUE_PORTSET_NP = 215; // { int kqueue_portset_np(int fd); } - SYS_GETATTRLIST = 220; // { int getattrlist(const char *path, struct attrlist *alist, void *attributeBuffer, size_t bufferSize, u_long options); } - SYS_SETATTRLIST = 221; // { int setattrlist(const char *path, struct attrlist *alist, void *attributeBuffer, size_t bufferSize, u_long options); } - SYS_GETDIRENTRIESATTR = 222; // { int getdirentriesattr(int fd, struct attrlist *alist, void *buffer, size_t buffersize, u_long *count, u_long *basep, u_long *newstate, u_long options); } - SYS_EXCHANGEDATA = 223; // { int exchangedata(const char *path1, const char *path2, u_long options); } - // SYS_NOSYS = 224; // { int nosys(void); } { was checkuseraccess } - SYS_SEARCHFS = 225; // { int searchfs(const char *path, struct fssearchblock *searchblock, u_long *nummatches, u_long scriptcode, u_long options, struct searchstate *state); } - SYS_DELETE = 226; // { int delete(user_addr_t path) NO_SYSCALL_STUB; } { private delete (Carbon semantics) } - SYS_COPYFILE = 227; // { int copyfile(char *from, char *to, int mode, int flags) NO_SYSCALL_STUB; } - // SYS_NOSYS = 228; // { int nosys(void); } - // SYS_NOSYS = 229; // { int nosys(void); } - SYS_POLL = 230; // { int poll(struct pollfd *fds, u_int nfds, int timeout); } - SYS_WATCHEVENT = 231; // { int watchevent(struct eventreq *u_req, int u_eventmask); } - SYS_WAITEVENT = 232; // { int waitevent(struct eventreq *u_req, struct timeval *tv); } - SYS_MODWATCH = 233; // { int modwatch(struct eventreq *u_req, int u_eventmask); } - SYS_GETXATTR = 234; // { user_ssize_t getxattr(user_addr_t path, user_addr_t attrname, user_addr_t value, size_t size, uint32_t position, int options); } - SYS_FGETXATTR = 235; // { user_ssize_t fgetxattr(int fd, user_addr_t attrname, user_addr_t value, size_t size, uint32_t position, int options); } - SYS_SETXATTR = 236; // { int setxattr(user_addr_t path, user_addr_t attrname, user_addr_t value, size_t size, uint32_t position, int options); } - SYS_FSETXATTR = 237; // { int fsetxattr(int fd, user_addr_t attrname, user_addr_t value, size_t size, uint32_t position, int options); } - SYS_REMOVEXATTR = 238; // { int removexattr(user_addr_t path, user_addr_t attrname, int options); } - SYS_FREMOVEXATTR = 239; // { int fremovexattr(int fd, user_addr_t attrname, int options); } - SYS_LISTXATTR = 240; // { user_ssize_t listxattr(user_addr_t path, user_addr_t namebuf, size_t bufsize, int options); } - SYS_FLISTXATTR = 241; // { user_ssize_t flistxattr(int fd, user_addr_t namebuf, size_t bufsize, int options); } - SYS_FSCTL = 242; // { int fsctl(const char *path, u_long cmd, caddr_t data, u_long options); } - SYS_INITGROUPS = 243; // { int initgroups(u_int gidsetsize, gid_t *gidset, int gmuid); } - SYS_POSIX_SPAWN = 244; // { int posix_spawn(pid_t *pid, const char *path, const struct _posix_spawn_args_desc *adesc, char **argv, char **envp); } - // SYS_NOSYS = 245; // { int nosys(void); } - // SYS_NOSYS = 246; // { int nosys(void); } - SYS_NFSCLNT = 247; // { int nfsclnt(int flag, caddr_t argp); } - // SYS_NOSYS = 247; // { int nosys(void); } - SYS_FHOPEN = 248; // { int fhopen(const struct fhandle *u_fhp, int flags); } - // SYS_NOSYS = 248; // { int nosys(void); } - // SYS_NOSYS = 249; // { int nosys(void); } - SYS_MINHERIT = 250; // { int minherit(void *addr, size_t len, int inherit); } - SYS_SEMSYS = 251; // { int semsys(u_int which, int a2, int a3, int a4, int a5); } - // SYS_NOSYS = 251; // { int nosys(void); } - SYS_MSGSYS = 252; // { int msgsys(u_int which, int a2, int a3, int a4, int a5); } - // SYS_NOSYS = 252; // { int nosys(void); } - SYS_SHMSYS = 253; // { int shmsys(u_int which, int a2, int a3, int a4); } - // SYS_NOSYS = 253; // { int nosys(void); } - SYS_SEMCTL = 254; // { int semctl(int semid, int semnum, int cmd, semun_t arg); } - SYS_SEMGET = 255; // { int semget(key_t key, int nsems, int semflg); } - SYS_SEMOP = 256; // { int semop(int semid, struct sembuf *sops, int nsops); } - // SYS_NOSYS = 257; // { int nosys(void); } - // SYS_NOSYS = 254; // { int nosys(void); } - // SYS_NOSYS = 255; // { int nosys(void); } - // SYS_NOSYS = 256; // { int nosys(void); } - // SYS_NOSYS = 257; // { int nosys(void); } - SYS_MSGCTL = 258; // { int msgctl(int msqid, int cmd, struct msqid_ds *buf); } - SYS_MSGGET = 259; // { int msgget(key_t key, int msgflg); } - SYS_MSGSND = 260; // { int msgsnd(int msqid, void *msgp, size_t msgsz, int msgflg); } - SYS_MSGRCV = 261; // { user_ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg); } - // SYS_NOSYS = 258; // { int nosys(void); } - // SYS_NOSYS = 259; // { int nosys(void); } - // SYS_NOSYS = 260; // { int nosys(void); } - // SYS_NOSYS = 261; // { int nosys(void); } - SYS_SHMAT = 262; // { user_addr_t shmat(int shmid, void *shmaddr, int shmflg); } - SYS_SHMCTL = 263; // { int shmctl(int shmid, int cmd, struct shmid_ds *buf); } - SYS_SHMDT = 264; // { int shmdt(void *shmaddr); } - SYS_SHMGET = 265; // { int shmget(key_t key, size_t size, int shmflg); } - // SYS_NOSYS = 262; // { int nosys(void); } - // SYS_NOSYS = 263; // { int nosys(void); } - // SYS_NOSYS = 264; // { int nosys(void); } - // SYS_NOSYS = 265; // { int nosys(void); } - SYS_SHM_OPEN = 266; // { int shm_open(const char *name, int oflag, int mode); } - SYS_SHM_UNLINK = 267; // { int shm_unlink(const char *name); } - SYS_SEM_OPEN = 268; // { user_addr_t sem_open(const char *name, int oflag, int mode, int value); } - SYS_SEM_CLOSE = 269; // { int sem_close(sem_t *sem); } - SYS_SEM_UNLINK = 270; // { int sem_unlink(const char *name); } - SYS_SEM_WAIT = 271; // { int sem_wait(sem_t *sem); } - SYS_SEM_TRYWAIT = 272; // { int sem_trywait(sem_t *sem); } - SYS_SEM_POST = 273; // { int sem_post(sem_t *sem); } - SYS_SEM_GETVALUE = 274; // { int sem_getvalue(sem_t *sem, int *sval); } - SYS_SEM_INIT = 275; // { int sem_init(sem_t *sem, int phsared, u_int value); } - SYS_SEM_DESTROY = 276; // { int sem_destroy(sem_t *sem); } - SYS_OPEN_EXTENDED = 277; // { int open_extended(user_addr_t path, int flags, uid_t uid, gid_t gid, int mode, user_addr_t xsecurity) NO_SYSCALL_STUB; } - SYS_UMASK_EXTENDED = 278; // { int umask_extended(int newmask, user_addr_t xsecurity) NO_SYSCALL_STUB; } - SYS_STAT_EXTENDED = 279; // { int stat_extended(user_addr_t path, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size) NO_SYSCALL_STUB; } - SYS_LSTAT_EXTENDED = 280; // { int lstat_extended(user_addr_t path, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size) NO_SYSCALL_STUB; } - SYS_FSTAT_EXTENDED = 281; // { int fstat_extended(int fd, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size) NO_SYSCALL_STUB; } - SYS_CHMOD_EXTENDED = 282; // { int chmod_extended(user_addr_t path, uid_t uid, gid_t gid, int mode, user_addr_t xsecurity) NO_SYSCALL_STUB; } - SYS_FCHMOD_EXTENDED = 283; // { int fchmod_extended(int fd, uid_t uid, gid_t gid, int mode, user_addr_t xsecurity) NO_SYSCALL_STUB; } - SYS_ACCESS_EXTENDED = 284; // { int access_extended(user_addr_t entries, size_t size, user_addr_t results, uid_t uid) NO_SYSCALL_STUB; } - SYS_SETTID = 285; // { int settid(uid_t uid, gid_t gid) NO_SYSCALL_STUB; } - SYS_GETTID = 286; // { int gettid(uid_t *uidp, gid_t *gidp) NO_SYSCALL_STUB; } - SYS_SETSGROUPS = 287; // { int setsgroups(int setlen, user_addr_t guidset) NO_SYSCALL_STUB; } - SYS_GETSGROUPS = 288; // { int getsgroups(user_addr_t setlen, user_addr_t guidset) NO_SYSCALL_STUB; } - SYS_SETWGROUPS = 289; // { int setwgroups(int setlen, user_addr_t guidset) NO_SYSCALL_STUB; } - SYS_GETWGROUPS = 290; // { int getwgroups(user_addr_t setlen, user_addr_t guidset) NO_SYSCALL_STUB; } - SYS_MKFIFO_EXTENDED = 291; // { int mkfifo_extended(user_addr_t path, uid_t uid, gid_t gid, int mode, user_addr_t xsecurity) NO_SYSCALL_STUB; } - SYS_MKDIR_EXTENDED = 292; // { int mkdir_extended(user_addr_t path, uid_t uid, gid_t gid, int mode, user_addr_t xsecurity) NO_SYSCALL_STUB; } - SYS_IDENTITYSVC = 293; // { int identitysvc(int opcode, user_addr_t message) NO_SYSCALL_STUB; } - SYS_SHARED_REGION_CHECK_NP = 294; // { int shared_region_check_np(uint64_t *start_address) NO_SYSCALL_STUB; } - SYS_SHARED_REGION_MAP_NP = 295; // { int shared_region_map_np(int fd, uint32_t count, const struct shared_file_mapping_np *mappings) NO_SYSCALL_STUB; } - // SYS_NOSYS = 296; // { int nosys(void); } { old load_shared_file } - // SYS_NOSYS = 297; // { int nosys(void); } { old reset_shared_file } - // SYS_NOSYS = 298; // { int nosys(void); } { old new_system_shared_regions } - // SYS_ENOSYS = 299; // { int enosys(void); } { old shared_region_map_file_np } - // SYS_ENOSYS = 300; // { int enosys(void); } { old shared_region_make_private_np } - SYS___PTHREAD_MUTEX_DESTROY = 301; // { int __pthread_mutex_destroy(int mutexid); } - SYS___PTHREAD_MUTEX_INIT = 302; // { int __pthread_mutex_init(user_addr_t mutex, user_addr_t attr); } - SYS___PTHREAD_MUTEX_LOCK = 303; // { int __pthread_mutex_lock(int mutexid); } - SYS___PTHREAD_MUTEX_TRYLOCK = 304; // { int __pthread_mutex_trylock(int mutexid); } - SYS___PTHREAD_MUTEX_UNLOCK = 305; // { int __pthread_mutex_unlock(int mutexid); } - SYS___PTHREAD_COND_INIT = 306; // { int __pthread_cond_init(user_addr_t cond, user_addr_t attr); } - SYS___PTHREAD_COND_DESTROY = 307; // { int __pthread_cond_destroy(int condid); } - SYS___PTHREAD_COND_BROADCAST = 308; // { int __pthread_cond_broadcast(int condid); } - SYS___PTHREAD_COND_SIGNAL = 309; // { int __pthread_cond_signal(int condid); } - SYS_GETSID = 310; // { int getsid(pid_t pid); } - SYS_SETTID_WITH_PID = 311; // { int settid_with_pid(pid_t pid, int assume) NO_SYSCALL_STUB; } - SYS___PTHREAD_COND_TIMEDWAIT = 312; // { int __pthread_cond_timedwait(int condid, int mutexid, user_addr_t abstime); } - SYS_AIO_FSYNC = 313; // { int aio_fsync(int op, user_addr_t aiocbp); } - SYS_AIO_RETURN = 314; // { user_ssize_t aio_return(user_addr_t aiocbp); } - SYS_AIO_SUSPEND = 315; // { int aio_suspend(user_addr_t aiocblist, int nent, user_addr_t timeoutp); } - SYS_AIO_CANCEL = 316; // { int aio_cancel(int fd, user_addr_t aiocbp); } - SYS_AIO_ERROR = 317; // { int aio_error(user_addr_t aiocbp); } - SYS_AIO_READ = 318; // { int aio_read(user_addr_t aiocbp); } - SYS_AIO_WRITE = 319; // { int aio_write(user_addr_t aiocbp); } - SYS_LIO_LISTIO = 320; // { int lio_listio(int mode, user_addr_t aiocblist, int nent, user_addr_t sigp); } - SYS___PTHREAD_COND_WAIT = 321; // { int __pthread_cond_wait(int condid, int mutexid); } - SYS_IOPOLICYSYS = 322; // { int iopolicysys(int cmd, void *arg) NO_SYSCALL_STUB; } - // SYS_NOSYS = 323; // { int nosys(void); } - SYS_MLOCKALL = 324; // { int mlockall(int how); } - SYS_MUNLOCKALL = 325; // { int munlockall(int how); } - // SYS_NOSYS = 326; // { int nosys(void); } - SYS_ISSETUGID = 327; // { int issetugid(void); } - SYS___PTHREAD_KILL = 328; // { int __pthread_kill(int thread_port, int sig); } - SYS___PTHREAD_SIGMASK = 329; // { int __pthread_sigmask(int how, user_addr_t set, user_addr_t oset); } - SYS___SIGWAIT = 330; // { int __sigwait(user_addr_t set, user_addr_t sig); } - SYS___DISABLE_THREADSIGNAL = 331; // { int __disable_threadsignal(int value); } - SYS___PTHREAD_MARKCANCEL = 332; // { int __pthread_markcancel(int thread_port); } - SYS___PTHREAD_CANCELED = 333; // { int __pthread_canceled(int action); } - SYS___SEMWAIT_SIGNAL = 334; // { int __semwait_signal(int cond_sem, int mutex_sem, int timeout, int relative, time_t tv_sec, int32_t tv_nsec); } - // SYS_NOSYS = 335; // { int nosys(void); } { old utrace } - SYS_PROC_INFO = 336; // { int proc_info(int32_t callnum,int32_t pid,uint32_t flavor, uint64_t arg,user_addr_t buffer,int32_t buffersize) NO_SYSCALL_STUB; } - SYS_SENDFILE = 337; // { int sendfile(int fd, int s, off_t offset, off_t *nbytes, struct sf_hdtr *hdtr, int flags); } - // SYS_NOSYS = 337; // { int nosys(void); } - SYS_STAT64 = 338; // { int stat64(user_addr_t path, user_addr_t ub); } - SYS_FSTAT64 = 339; // { int fstat64(int fd, user_addr_t ub); } - SYS_LSTAT64 = 340; // { int lstat64(user_addr_t path, user_addr_t ub); } - SYS_STAT64_EXTENDED = 341; // { int stat64_extended(user_addr_t path, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size) NO_SYSCALL_STUB; } - SYS_LSTAT64_EXTENDED = 342; // { int lstat64_extended(user_addr_t path, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size) NO_SYSCALL_STUB; } - SYS_FSTAT64_EXTENDED = 343; // { int fstat64_extended(int fd, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size) NO_SYSCALL_STUB; } - SYS_GETDIRENTRIES64 = 344; // { user_ssize_t getdirentries64(int fd, void *buf, user_size_t bufsize, off_t *position) NO_SYSCALL_STUB; } - SYS_STATFS64 = 345; // { int statfs64(char *path, struct statfs64 *buf); } - SYS_FSTATFS64 = 346; // { int fstatfs64(int fd, struct statfs64 *buf); } - SYS_GETFSSTAT64 = 347; // { int getfsstat64(user_addr_t buf, int bufsize, int flags); } - SYS___PTHREAD_CHDIR = 348; // { int __pthread_chdir(user_addr_t path); } - SYS___PTHREAD_FCHDIR = 349; // { int __pthread_fchdir(int fd); } - SYS_AUDIT = 350; // { int audit(void *record, int length); } - SYS_AUDITON = 351; // { int auditon(int cmd, void *data, int length); } - // SYS_NOSYS = 352; // { int nosys(void); } - SYS_GETAUID = 353; // { int getauid(au_id_t *auid); } - SYS_SETAUID = 354; // { int setauid(au_id_t *auid); } - SYS_GETAUDIT = 355; // { int getaudit(struct auditinfo *auditinfo); } - SYS_SETAUDIT = 356; // { int setaudit(struct auditinfo *auditinfo); } - SYS_GETAUDIT_ADDR = 357; // { int getaudit_addr(struct auditinfo_addr *auditinfo_addr, int length); } - SYS_SETAUDIT_ADDR = 358; // { int setaudit_addr(struct auditinfo_addr *auditinfo_addr, int length); } - SYS_AUDITCTL = 359; // { int auditctl(char *path); } - // SYS_NOSYS = 350; // { int nosys(void); } - // SYS_NOSYS = 351; // { int nosys(void); } - // SYS_NOSYS = 352; // { int nosys(void); } - // SYS_NOSYS = 353; // { int nosys(void); } - // SYS_NOSYS = 354; // { int nosys(void); } - // SYS_NOSYS = 355; // { int nosys(void); } - // SYS_NOSYS = 356; // { int nosys(void); } - // SYS_NOSYS = 357; // { int nosys(void); } - // SYS_NOSYS = 358; // { int nosys(void); } - // SYS_NOSYS = 359; // { int nosys(void); } - SYS_BSDTHREAD_CREATE = 360; // { user_addr_t bsdthread_create(user_addr_t func, user_addr_t func_arg, user_addr_t stack, user_addr_t pthread, uint32_t flags) NO_SYSCALL_STUB; } - SYS_BSDTHREAD_TERMINATE = 361; // { int bsdthread_terminate(user_addr_t stackaddr, size_t freesize, uint32_t port, uint32_t sem) NO_SYSCALL_STUB; } - SYS_KQUEUE = 362; // { int kqueue(void); } - SYS_KEVENT = 363; // { int kevent(int fd, const struct kevent *changelist, int nchanges, struct kevent *eventlist, int nevents, const struct timespec *timeout); } - SYS_LCHOWN = 364; // { int lchown(user_addr_t path, uid_t owner, gid_t group); } - SYS_STACK_SNAPSHOT = 365; // { int stack_snapshot(pid_t pid, user_addr_t tracebuf, uint32_t tracebuf_size, uint32_t options) NO_SYSCALL_STUB; } - SYS_BSDTHREAD_REGISTER = 366; // { int bsdthread_register(user_addr_t threadstart, user_addr_t wqthread, int pthsize) NO_SYSCALL_STUB; } - SYS_WORKQ_OPEN = 367; // { int workq_open(void) NO_SYSCALL_STUB; } - SYS_WORKQ_OPS = 368; // { int workq_ops(int options, user_addr_t item, int prio) NO_SYSCALL_STUB; } - // SYS_NOSYS = 369; // { int nosys(void); } - // SYS_NOSYS = 370; // { int nosys(void); } - // SYS_NOSYS = 371; // { int nosys(void); } - // SYS_NOSYS = 372; // { int nosys(void); } - // SYS_NOSYS = 373; // { int nosys(void); } - // SYS_NOSYS = 374; // { int nosys(void); } - // SYS_NOSYS = 375; // { int nosys(void); } - // SYS_NOSYS = 376; // { int nosys(void); } - // SYS_NOSYS = 377; // { int nosys(void); } - // SYS_NOSYS = 378; // { int nosys(void); } - // SYS_NOSYS = 379; // { int nosys(void); } - SYS___MAC_EXECVE = 380; // { int __mac_execve(char *fname, char **argp, char **envp, struct mac *mac_p); } - SYS___MAC_SYSCALL = 381; // { int __mac_syscall(char *policy, int call, user_addr_t arg); } - SYS___MAC_GET_FILE = 382; // { int __mac_get_file(char *path_p, struct mac *mac_p); } - SYS___MAC_SET_FILE = 383; // { int __mac_set_file(char *path_p, struct mac *mac_p); } - SYS___MAC_GET_LINK = 384; // { int __mac_get_link(char *path_p, struct mac *mac_p); } - SYS___MAC_SET_LINK = 385; // { int __mac_set_link(char *path_p, struct mac *mac_p); } - SYS___MAC_GET_PROC = 386; // { int __mac_get_proc(struct mac *mac_p); } - SYS___MAC_SET_PROC = 387; // { int __mac_set_proc(struct mac *mac_p); } - SYS___MAC_GET_FD = 388; // { int __mac_get_fd(int fd, struct mac *mac_p); } - SYS___MAC_SET_FD = 389; // { int __mac_set_fd(int fd, struct mac *mac_p); } - SYS___MAC_GET_PID = 390; // { int __mac_get_pid(pid_t pid, struct mac *mac_p); } - SYS___MAC_GET_LCID = 391; // { int __mac_get_lcid(pid_t lcid, struct mac *mac_p); } - SYS___MAC_GET_LCTX = 392; // { int __mac_get_lctx(struct mac *mac_p); } - SYS___MAC_SET_LCTX = 393; // { int __mac_set_lctx(struct mac *mac_p); } - SYS_SETLCID = 394; // { int setlcid(pid_t pid, pid_t lcid) NO_SYSCALL_STUB; } - SYS_GETLCID = 395; // { int getlcid(pid_t pid) NO_SYSCALL_STUB; } - SYS_READ_NOCANCEL = 396; // { user_ssize_t read_nocancel(int fd, user_addr_t cbuf, user_size_t nbyte) NO_SYSCALL_STUB; } - SYS_WRITE_NOCANCEL = 397; // { user_ssize_t write_nocancel(int fd, user_addr_t cbuf, user_size_t nbyte) NO_SYSCALL_STUB; } - SYS_OPEN_NOCANCEL = 398; // { int open_nocancel(user_addr_t path, int flags, int mode) NO_SYSCALL_STUB; } - SYS_CLOSE_NOCANCEL = 399; // { int close_nocancel(int fd) NO_SYSCALL_STUB; } - SYS_WAIT4_NOCANCEL = 400; // { int wait4_nocancel(int pid, user_addr_t status, int options, user_addr_t rusage) NO_SYSCALL_STUB; } - SYS_RECVMSG_NOCANCEL = 401; // { int recvmsg_nocancel(int s, struct msghdr *msg, int flags) NO_SYSCALL_STUB; } - SYS_SENDMSG_NOCANCEL = 402; // { int sendmsg_nocancel(int s, caddr_t msg, int flags) NO_SYSCALL_STUB; } - SYS_RECVFROM_NOCANCEL = 403; // { int recvfrom_nocancel(int s, void *buf, size_t len, int flags, struct sockaddr *from, int *fromlenaddr) NO_SYSCALL_STUB; } - SYS_ACCEPT_NOCANCEL = 404; // { int accept_nocancel(int s, caddr_t name, socklen_t *anamelen) NO_SYSCALL_STUB; } - // SYS_NOSYS = 401; // { int nosys(void); } - // SYS_NOSYS = 402; // { int nosys(void); } - // SYS_NOSYS = 403; // { int nosys(void); } - // SYS_NOSYS = 404; // { int nosys(void); } - SYS_MSYNC_NOCANCEL = 405; // { int msync_nocancel(caddr_t addr, size_t len, int flags) NO_SYSCALL_STUB; } - SYS_FCNTL_NOCANCEL = 406; // { int fcntl_nocancel(int fd, int cmd, long arg) NO_SYSCALL_STUB; } - SYS_SELECT_NOCANCEL = 407; // { int select_nocancel(int nd, u_int32_t *in, u_int32_t *ou, u_int32_t *ex, struct timeval *tv) NO_SYSCALL_STUB; } - SYS_FSYNC_NOCANCEL = 408; // { int fsync_nocancel(int fd) NO_SYSCALL_STUB; } - SYS_CONNECT_NOCANCEL = 409; // { int connect_nocancel(int s, caddr_t name, socklen_t namelen) NO_SYSCALL_STUB; } - // SYS_NOSYS = 409; // { int nosys(void); } - SYS_SIGSUSPEND_NOCANCEL = 410; // { int sigsuspend_nocancel(sigset_t mask) NO_SYSCALL_STUB; } - SYS_READV_NOCANCEL = 411; // { user_ssize_t readv_nocancel(int fd, struct iovec *iovp, u_int iovcnt) NO_SYSCALL_STUB; } - SYS_WRITEV_NOCANCEL = 412; // { user_ssize_t writev_nocancel(int fd, struct iovec *iovp, u_int iovcnt) NO_SYSCALL_STUB; } - SYS_SENDTO_NOCANCEL = 413; // { int sendto_nocancel(int s, caddr_t buf, size_t len, int flags, caddr_t to, socklen_t tolen) NO_SYSCALL_STUB; } - // SYS_NOSYS = 413; // { int nosys(void); } - SYS_PREAD_NOCANCEL = 414; // { user_ssize_t pread_nocancel(int fd, user_addr_t buf, user_size_t nbyte, off_t offset) NO_SYSCALL_STUB; } - SYS_PWRITE_NOCANCEL = 415; // { user_ssize_t pwrite_nocancel(int fd, user_addr_t buf, user_size_t nbyte, off_t offset) NO_SYSCALL_STUB; } - SYS_WAITID_NOCANCEL = 416; // { int waitid_nocancel(idtype_t idtype, id_t id, siginfo_t *infop, int options) NO_SYSCALL_STUB; } - SYS_POLL_NOCANCEL = 417; // { int poll_nocancel(struct pollfd *fds, u_int nfds, int timeout) NO_SYSCALL_STUB; } - SYS_MSGSND_NOCANCEL = 418; // { int msgsnd_nocancel(int msqid, void *msgp, size_t msgsz, int msgflg) NO_SYSCALL_STUB; } - SYS_MSGRCV_NOCANCEL = 419; // { user_ssize_t msgrcv_nocancel(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg) NO_SYSCALL_STUB; } - // SYS_NOSYS = 418; // { int nosys(void); } - // SYS_NOSYS = 419; // { int nosys(void); } - SYS_SEM_WAIT_NOCANCEL = 420; // { int sem_wait_nocancel(sem_t *sem) NO_SYSCALL_STUB; } - SYS_AIO_SUSPEND_NOCANCEL = 421; // { int aio_suspend_nocancel(user_addr_t aiocblist, int nent, user_addr_t timeoutp) NO_SYSCALL_STUB; } - SYS___SIGWAIT_NOCANCEL = 422; // { int __sigwait_nocancel(user_addr_t set, user_addr_t sig) NO_SYSCALL_STUB; } - SYS___SEMWAIT_SIGNAL_NOCANCEL = 423; // { int __semwait_signal_nocancel(int cond_sem, int mutex_sem, int timeout, int relative, time_t tv_sec, int32_t tv_nsec) NO_SYSCALL_STUB; } - SYS___MAC_MOUNT = 424; // { int __mac_mount(char *type, char *path, int flags, caddr_t data, struct mac *mac_p); } - SYS___MAC_GET_MOUNT = 425; // { int __mac_get_mount(char *path, struct mac *mac_p); } - SYS___MAC_GETFSSTAT = 426; // { int __mac_getfsstat(user_addr_t buf, int bufsize, user_addr_t mac, int macsize, int flags); } -) diff --git a/src/lib/syscall/zsysnum_darwin_amd64.go b/src/lib/syscall/zsysnum_darwin_amd64.go deleted file mode 100644 index c4c48c2a2..000000000 --- a/src/lib/syscall/zsysnum_darwin_amd64.go +++ /dev/null @@ -1,485 +0,0 @@ -// mksysnum_darwin /home/rsc/pub/xnu-1228/bsd/kern/syscalls.master -// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT - -package syscall - -const ( - // SYS_NOSYS = 0; // { int nosys(void); } { indirect syscall } - SYS_EXIT = 1; // { void exit(int rval); } - SYS_FORK = 2; // { int fork(void); } - SYS_READ = 3; // { user_ssize_t read(int fd, user_addr_t cbuf, user_size_t nbyte); } - SYS_WRITE = 4; // { user_ssize_t write(int fd, user_addr_t cbuf, user_size_t nbyte); } - SYS_OPEN = 5; // { int open(user_addr_t path, int flags, int mode); } - SYS_CLOSE = 6; // { int close(int fd); } - SYS_WAIT4 = 7; // { int wait4(int pid, user_addr_t status, int options, user_addr_t rusage); } - // SYS_NOSYS = 8; // { int nosys(void); } { old creat } - SYS_LINK = 9; // { int link(user_addr_t path, user_addr_t link); } - SYS_UNLINK = 10; // { int unlink(user_addr_t path); } - // SYS_NOSYS = 11; // { int nosys(void); } { old execv } - SYS_CHDIR = 12; // { int chdir(user_addr_t path); } - SYS_FCHDIR = 13; // { int fchdir(int fd); } - SYS_MKNOD = 14; // { int mknod(user_addr_t path, int mode, int dev); } - SYS_CHMOD = 15; // { int chmod(user_addr_t path, int mode); } - SYS_CHOWN = 16; // { int chown(user_addr_t path, int uid, int gid); } - SYS_OGETFSSTAT = 18; // { int ogetfsstat(user_addr_t buf, int bufsize, int flags); } - SYS_GETFSSTAT = 18; // { int getfsstat(user_addr_t buf, int bufsize, int flags); } - // SYS_NOSYS = 19; // { int nosys(void); } { old lseek } - SYS_GETPID = 20; // { int getpid(void); } - // SYS_NOSYS = 21; // { int nosys(void); } { old mount } - // SYS_NOSYS = 22; // { int nosys(void); } { old umount } - SYS_SETUID = 23; // { int setuid(uid_t uid); } - SYS_GETUID = 24; // { int getuid(void); } - SYS_GETEUID = 25; // { int geteuid(void); } - SYS_PTRACE = 26; // { int ptrace(int req, pid_t pid, caddr_t addr, int data); } - SYS_RECVMSG = 27; // { int recvmsg(int s, struct msghdr *msg, int flags); } - SYS_SENDMSG = 28; // { int sendmsg(int s, caddr_t msg, int flags); } - SYS_RECVFROM = 29; // { int recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, int *fromlenaddr); } - SYS_ACCEPT = 30; // { int accept(int s, caddr_t name, socklen_t *anamelen); } - SYS_GETPEERNAME = 31; // { int getpeername(int fdes, caddr_t asa, socklen_t *alen); } - SYS_GETSOCKNAME = 32; // { int getsockname(int fdes, caddr_t asa, socklen_t *alen); } - // SYS_NOSYS = 27; // { int nosys(void); } - // SYS_NOSYS = 28; // { int nosys(void); } - // SYS_NOSYS = 29; // { int nosys(void); } - // SYS_NOSYS = 30; // { int nosys(void); } - // SYS_NOSYS = 31; // { int nosys(void); } - // SYS_NOSYS = 32; // { int nosys(void); } - SYS_ACCESS = 33; // { int access(user_addr_t 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, int posix); } - // SYS_NOSYS = 38; // { int nosys(void); } { old stat } - SYS_GETPPID = 39; // { int getppid(void); } - // SYS_NOSYS = 40; // { int nosys(void); } { old lstat } - SYS_DUP = 41; // { int dup(u_int fd); } - SYS_PIPE = 42; // { int pipe(void); } - SYS_GETEGID = 43; // { int getegid(void); } - SYS_PROFIL = 44; // { int profil(short *bufbase, size_t bufsize, u_long pcoffset, u_int pcscale); } - // SYS_NOSYS = 45; // { int nosys(void); } { old ktrace } - SYS_SIGACTION = 46; // { int sigaction(int signum, struct __sigaction *nsa, struct sigaction *osa); } - SYS_GETGID = 47; // { int getgid(void); } - SYS_SIGPROCMASK = 48; // { int sigprocmask(int how, user_addr_t mask, user_addr_t omask); } - SYS_GETLOGIN = 49; // { int getlogin(char *namebuf, u_int namelen); } - SYS_SETLOGIN = 50; // { int setlogin(char *namebuf); } - SYS_ACCT = 51; // { int acct(char *path); } - SYS_SIGPENDING = 52; // { int sigpending(struct sigvec *osv); } - SYS_SIGALTSTACK = 53; // { int sigaltstack(struct sigaltstack *nss, struct sigaltstack *oss); } - SYS_IOCTL = 54; // { int ioctl(int fd, u_long com, caddr_t data); } - SYS_REBOOT = 55; // { int reboot(int opt, char *command); } - SYS_REVOKE = 56; // { int revoke(char *path); } - SYS_SYMLINK = 57; // { int symlink(char *path, char *link); } - SYS_READLINK = 58; // { int readlink(char *path, char *buf, int count); } - SYS_EXECVE = 59; // { int execve(char *fname, char **argp, char **envp); } - SYS_UMASK = 60; // { int umask(int newmask); } - SYS_CHROOT = 61; // { int chroot(user_addr_t path); } - // SYS_NOSYS = 62; // { int nosys(void); } { old fstat } - // SYS_NOSYS = 63; // { int nosys(void); } { used internally, reserved } - // SYS_NOSYS = 64; // { int nosys(void); } { old getpagesize } - SYS_MSYNC = 65; // { int msync(caddr_t addr, size_t len, int flags); } - SYS_VFORK = 66; // { int vfork(void); } - // SYS_NOSYS = 67; // { int nosys(void); } { old vread } - // SYS_NOSYS = 68; // { int nosys(void); } { old vwrite } - SYS_SBRK = 69; // { int sbrk(int incr) NO_SYSCALL_STUB; } - SYS_SSTK = 70; // { int sstk(int incr) NO_SYSCALL_STUB; } - // SYS_NOSYS = 71; // { int nosys(void); } { old mmap } - SYS_OVADVISE = 72; // { int ovadvise(void) NO_SYSCALL_STUB; } { old vadvise } - SYS_MUNMAP = 73; // { int munmap(caddr_t addr, size_t len); } - SYS_MPROTECT = 74; // { int mprotect(caddr_t addr, size_t len, int prot); } - SYS_MADVISE = 75; // { int madvise(caddr_t addr, size_t len, int behav); } - // SYS_NOSYS = 76; // { int nosys(void); } { old vhangup } - // SYS_NOSYS = 77; // { int nosys(void); } { old vlimit } - SYS_MINCORE = 78; // { int mincore(user_addr_t addr, user_size_t len, user_addr_t vec); } - SYS_GETGROUPS = 79; // { int getgroups(u_int gidsetsize, gid_t *gidset); } - SYS_SETGROUPS = 80; // { int setgroups(u_int gidsetsize, gid_t *gidset); } - SYS_GETPGRP = 81; // { int getpgrp(void); } - SYS_SETPGID = 82; // { int setpgid(int pid, int pgid); } - SYS_SETITIMER = 83; // { int setitimer(u_int which, struct itimerval *itv, struct itimerval *oitv); } - // SYS_NOSYS = 84; // { int nosys(void); } { old wait } - SYS_SWAPON = 85; // { int swapon(void); } - SYS_GETITIMER = 86; // { int getitimer(u_int which, struct itimerval *itv); } - // SYS_NOSYS = 87; // { int nosys(void); } { old gethostname } - // SYS_NOSYS = 88; // { int nosys(void); } { old sethostname } - SYS_GETDTABLESIZE = 89; // { int getdtablesize(void); } - SYS_DUP2 = 90; // { int dup2(u_int from, u_int to); } - // SYS_NOSYS = 91; // { int nosys(void); } { old getdopt } - SYS_FCNTL = 92; // { int fcntl(int fd, int cmd, long arg); } - SYS_SELECT = 93; // { int select(int nd, u_int32_t *in, u_int32_t *ou, u_int32_t *ex, struct timeval *tv); } - // SYS_NOSYS = 94; // { int nosys(void); } { old setdopt } - SYS_FSYNC = 95; // { int fsync(int fd); } - SYS_SETPRIORITY = 96; // { int setpriority(int which, id_t who, int prio); } - SYS_SOCKET = 97; // { int socket(int domain, int type, int protocol); } - SYS_CONNECT = 98; // { int connect(int s, caddr_t name, socklen_t namelen); } - // SYS_NOSYS = 97; // { int nosys(void); } - // SYS_NOSYS = 98; // { int nosys(void); } - // SYS_NOSYS = 99; // { int nosys(void); } { old accept } - SYS_GETPRIORITY = 100; // { int getpriority(int which, id_t who); } - // SYS_NOSYS = 101; // { int nosys(void); } { old send } - // SYS_NOSYS = 102; // { int nosys(void); } { old recv } - // SYS_NOSYS = 103; // { int nosys(void); } { old sigreturn } - SYS_BIND = 104; // { int bind(int s, caddr_t name, socklen_t namelen); } - SYS_SETSOCKOPT = 105; // { int setsockopt(int s, int level, int name, caddr_t val, socklen_t valsize); } - SYS_LISTEN = 106; // { int listen(int s, int backlog); } - // SYS_NOSYS = 104; // { int nosys(void); } - // SYS_NOSYS = 105; // { int nosys(void); } - // SYS_NOSYS = 106; // { int nosys(void); } - // SYS_NOSYS = 107; // { int nosys(void); } { old vtimes } - // SYS_NOSYS = 108; // { int nosys(void); } { old sigvec } - // SYS_NOSYS = 109; // { int nosys(void); } { old sigblock } - // SYS_NOSYS = 110; // { int nosys(void); } { old sigsetmask } - SYS_SIGSUSPEND = 111; // { int sigsuspend(sigset_t mask); } - // SYS_NOSYS = 112; // { int nosys(void); } { old sigstack } - // SYS_NOSYS = 113; // { int nosys(void); } { old recvmsg } - // SYS_NOSYS = 114; // { int nosys(void); } { old sendmsg } - // SYS_NOSYS = 113; // { int nosys(void); } - // SYS_NOSYS = 114; // { int nosys(void); } - // SYS_NOSYS = 115; // { int nosys(void); } { old vtrace } - SYS_GETTIMEOFDAY = 116; // { int gettimeofday(struct timeval *tp, struct timezone *tzp); } - SYS_GETRUSAGE = 117; // { int getrusage(int who, struct rusage *rusage); } - SYS_GETSOCKOPT = 118; // { int getsockopt(int s, int level, int name, caddr_t val, socklen_t *avalsize); } - // SYS_NOSYS = 118; // { int nosys(void); } - // SYS_NOSYS = 119; // { int nosys(void); } { old resuba } - SYS_READV = 120; // { user_ssize_t readv(int fd, struct iovec *iovp, u_int iovcnt); } - SYS_WRITEV = 121; // { user_ssize_t writev(int fd, struct iovec *iovp, u_int iovcnt); } - SYS_SETTIMEOFDAY = 122; // { int settimeofday(struct timeval *tv, struct timezone *tzp); } - SYS_FCHOWN = 123; // { int fchown(int fd, int uid, int gid); } - SYS_FCHMOD = 124; // { int fchmod(int fd, int mode); } - // SYS_NOSYS = 125; // { int nosys(void); } { old recvfrom } - SYS_SETREUID = 126; // { int setreuid(uid_t ruid, uid_t euid); } - SYS_SETREGID = 127; // { int setregid(gid_t rgid, gid_t egid); } - SYS_RENAME = 128; // { int rename(char *from, char *to); } - // SYS_NOSYS = 129; // { int nosys(void); } { old truncate } - // SYS_NOSYS = 130; // { int nosys(void); } { old ftruncate } - SYS_FLOCK = 131; // { int flock(int fd, int how); } - SYS_MKFIFO = 132; // { int mkfifo(user_addr_t path, int mode); } - SYS_SENDTO = 133; // { int sendto(int s, caddr_t buf, size_t len, int flags, caddr_t to, socklen_t tolen); } - SYS_SHUTDOWN = 134; // { int shutdown(int s, int how); } - SYS_SOCKETPAIR = 135; // { int socketpair(int domain, int type, int protocol, int *rsv); } - // SYS_NOSYS = 133; // { int nosys(void); } - // SYS_NOSYS = 134; // { int nosys(void); } - // SYS_NOSYS = 135; // { int nosys(void); } - SYS_MKDIR = 136; // { int mkdir(user_addr_t path, int mode); } - SYS_RMDIR = 137; // { int rmdir(char *path); } - SYS_UTIMES = 138; // { int utimes(char *path, struct timeval *tptr); } - SYS_FUTIMES = 139; // { int futimes(int fd, struct timeval *tptr); } - SYS_ADJTIME = 140; // { int adjtime(struct timeval *delta, struct timeval *olddelta); } - // SYS_NOSYS = 141; // { int nosys(void); } { old getpeername } - SYS_GETHOSTUUID = 142; // { int gethostuuid(unsigned char *uuid_buf, const struct timespec *timeoutp); } - // SYS_NOSYS = 143; // { int nosys(void); } { old sethostid } - // SYS_NOSYS = 144; // { int nosys(void); } { old getrlimit } - // SYS_NOSYS = 145; // { int nosys(void); } { old setrlimit } - // SYS_NOSYS = 146; // { int nosys(void); } { old killpg } - SYS_SETSID = 147; // { int setsid(void); } - // SYS_NOSYS = 148; // { int nosys(void); } { old setquota } - // SYS_NOSYS = 149; // { int nosys(void); } { old qquota } - // SYS_NOSYS = 150; // { int nosys(void); } { old getsockname } - SYS_GETPGID = 151; // { int getpgid(pid_t pid); } - SYS_SETPRIVEXEC = 152; // { int setprivexec(int flag); } - SYS_PREAD = 153; // { user_ssize_t pread(int fd, user_addr_t buf, user_size_t nbyte, off_t offset); } - SYS_PWRITE = 154; // { user_ssize_t pwrite(int fd, user_addr_t buf, user_size_t nbyte, off_t offset); } - SYS_NFSSVC = 155; // { int nfssvc(int flag, caddr_t argp); } - // SYS_NOSYS = 155; // { int nosys(void); } - // SYS_NOSYS = 156; // { int nosys(void); } { old getdirentries } - SYS_STATFS = 157; // { int statfs(char *path, struct statfs *buf); } - SYS_FSTATFS = 158; // { int fstatfs(int fd, struct statfs *buf); } - SYS_UNMOUNT = 159; // { int unmount(user_addr_t path, int flags); } - // SYS_NOSYS = 160; // { int nosys(void); } { old async_daemon } - SYS_GETFH = 161; // { int getfh(char *fname, fhandle_t *fhp); } - // SYS_NOSYS = 161; // { int nosys(void); } - // SYS_NOSYS = 162; // { int nosys(void); } { old getdomainname } - // SYS_NOSYS = 163; // { int nosys(void); } { old setdomainname } - // SYS_NOSYS = 164; // { int nosys(void); } - SYS_QUOTACTL = 165; // { int quotactl(const char *path, int cmd, int uid, caddr_t arg); } - // SYS_NOSYS = 166; // { int nosys(void); } { old exportfs } - SYS_MOUNT = 167; // { int mount(char *type, char *path, int flags, caddr_t data); } - // SYS_NOSYS = 168; // { int nosys(void); } { old ustat } - SYS_CSOPS = 169; // { int csops(pid_t pid, uint32_t ops, user_addr_t useraddr, user_size_t usersize); } - // SYS_NOSYS = 171; // { int nosys(void); } { old wait3 } - // SYS_NOSYS = 172; // { int nosys(void); } { old rpause } - SYS_WAITID = 173; // { int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options); } - // SYS_NOSYS = 174; // { int nosys(void); } { old getdents } - // SYS_NOSYS = 175; // { int nosys(void); } { old gc_control } - SYS_ADD_PROFIL = 176; // { int add_profil(short *bufbase, size_t bufsize, u_long pcoffset, u_int pcscale); } - // SYS_NOSYS = 177; // { int nosys(void); } - // SYS_NOSYS = 178; // { int nosys(void); } - // SYS_NOSYS = 179; // { int nosys(void); } - SYS_KDEBUG_TRACE = 180; // { int kdebug_trace(int code, int arg1, int arg2, int arg3, int arg4, int arg5) NO_SYSCALL_STUB; } - 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_SIGRETURN = 184; // { int sigreturn(struct ucontext *uctx, int infostyle); } - // SYS_NOSYS = 186; // { int nosys(void); } - // SYS_NOSYS = 187; // { int nosys(void); } - SYS_STAT = 188; // { int stat(user_addr_t path, user_addr_t ub); } - SYS_FSTAT = 189; // { int fstat(int fd, user_addr_t ub); } - SYS_LSTAT = 190; // { int lstat(user_addr_t path, user_addr_t ub); } - SYS_PATHCONF = 191; // { int pathconf(char *path, int name); } - SYS_FPATHCONF = 192; // { int fpathconf(int fd, int name); } - // SYS_NOSYS = 193; // { int nosys(void); } - SYS_GETRLIMIT = 194; // { int getrlimit(u_int which, struct rlimit *rlp); } - SYS_SETRLIMIT = 195; // { int setrlimit(u_int which, struct rlimit *rlp); } - SYS_GETDIRENTRIES = 196; // { int getdirentries(int fd, char *buf, u_int count, long *basep); } - SYS_MMAP = 197; // { user_addr_t mmap(caddr_t addr, size_t len, int prot, int flags, int fd, off_t pos); } - // SYS_NOSYS = 198; // { int nosys(void); } { __syscall } - SYS_LSEEK = 199; // { off_t lseek(int fd, off_t offset, int whence); } - SYS_TRUNCATE = 200; // { int truncate(char *path, off_t length); } - SYS_FTRUNCATE = 201; // { int ftruncate(int fd, off_t length); } - SYS___SYSCTL = 202; // { int __sysctl(int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen); } - SYS_MLOCK = 203; // { int mlock(caddr_t addr, size_t len); } - SYS_MUNLOCK = 204; // { int munlock(caddr_t addr, size_t len); } - SYS_UNDELETE = 205; // { int undelete(user_addr_t path); } - SYS_ATSOCKET = 206; // { int ATsocket(int proto); } - // SYS_NOSYS = 213; // { int nosys(void); } { Reserved for AppleTalk } - // SYS_NOSYS = 206; // { int nosys(void); } - // SYS_NOSYS = 207; // { int nosys(void); } - // SYS_NOSYS = 208; // { int nosys(void); } - // SYS_NOSYS = 209; // { int nosys(void); } - // SYS_NOSYS = 210; // { int nosys(void); } - // SYS_NOSYS = 211; // { int nosys(void); } - // SYS_NOSYS = 212; // { int nosys(void); } - // SYS_NOSYS = 213; // { int nosys(void); } { Reserved for AppleTalk } - SYS_KQUEUE_FROM_PORTSET_NP = 214; // { int kqueue_from_portset_np(int portset); } - SYS_KQUEUE_PORTSET_NP = 215; // { int kqueue_portset_np(int fd); } - SYS_GETATTRLIST = 220; // { int getattrlist(const char *path, struct attrlist *alist, void *attributeBuffer, size_t bufferSize, u_long options); } - SYS_SETATTRLIST = 221; // { int setattrlist(const char *path, struct attrlist *alist, void *attributeBuffer, size_t bufferSize, u_long options); } - SYS_GETDIRENTRIESATTR = 222; // { int getdirentriesattr(int fd, struct attrlist *alist, void *buffer, size_t buffersize, u_long *count, u_long *basep, u_long *newstate, u_long options); } - SYS_EXCHANGEDATA = 223; // { int exchangedata(const char *path1, const char *path2, u_long options); } - // SYS_NOSYS = 224; // { int nosys(void); } { was checkuseraccess } - SYS_SEARCHFS = 225; // { int searchfs(const char *path, struct fssearchblock *searchblock, u_long *nummatches, u_long scriptcode, u_long options, struct searchstate *state); } - SYS_DELETE = 226; // { int delete(user_addr_t path) NO_SYSCALL_STUB; } { private delete (Carbon semantics) } - SYS_COPYFILE = 227; // { int copyfile(char *from, char *to, int mode, int flags) NO_SYSCALL_STUB; } - // SYS_NOSYS = 228; // { int nosys(void); } - // SYS_NOSYS = 229; // { int nosys(void); } - SYS_POLL = 230; // { int poll(struct pollfd *fds, u_int nfds, int timeout); } - SYS_WATCHEVENT = 231; // { int watchevent(struct eventreq *u_req, int u_eventmask); } - SYS_WAITEVENT = 232; // { int waitevent(struct eventreq *u_req, struct timeval *tv); } - SYS_MODWATCH = 233; // { int modwatch(struct eventreq *u_req, int u_eventmask); } - SYS_GETXATTR = 234; // { user_ssize_t getxattr(user_addr_t path, user_addr_t attrname, user_addr_t value, size_t size, uint32_t position, int options); } - SYS_FGETXATTR = 235; // { user_ssize_t fgetxattr(int fd, user_addr_t attrname, user_addr_t value, size_t size, uint32_t position, int options); } - SYS_SETXATTR = 236; // { int setxattr(user_addr_t path, user_addr_t attrname, user_addr_t value, size_t size, uint32_t position, int options); } - SYS_FSETXATTR = 237; // { int fsetxattr(int fd, user_addr_t attrname, user_addr_t value, size_t size, uint32_t position, int options); } - SYS_REMOVEXATTR = 238; // { int removexattr(user_addr_t path, user_addr_t attrname, int options); } - SYS_FREMOVEXATTR = 239; // { int fremovexattr(int fd, user_addr_t attrname, int options); } - SYS_LISTXATTR = 240; // { user_ssize_t listxattr(user_addr_t path, user_addr_t namebuf, size_t bufsize, int options); } - SYS_FLISTXATTR = 241; // { user_ssize_t flistxattr(int fd, user_addr_t namebuf, size_t bufsize, int options); } - SYS_FSCTL = 242; // { int fsctl(const char *path, u_long cmd, caddr_t data, u_long options); } - SYS_INITGROUPS = 243; // { int initgroups(u_int gidsetsize, gid_t *gidset, int gmuid); } - SYS_POSIX_SPAWN = 244; // { int posix_spawn(pid_t *pid, const char *path, const struct _posix_spawn_args_desc *adesc, char **argv, char **envp); } - // SYS_NOSYS = 245; // { int nosys(void); } - // SYS_NOSYS = 246; // { int nosys(void); } - SYS_NFSCLNT = 247; // { int nfsclnt(int flag, caddr_t argp); } - // SYS_NOSYS = 247; // { int nosys(void); } - SYS_FHOPEN = 248; // { int fhopen(const struct fhandle *u_fhp, int flags); } - // SYS_NOSYS = 248; // { int nosys(void); } - // SYS_NOSYS = 249; // { int nosys(void); } - SYS_MINHERIT = 250; // { int minherit(void *addr, size_t len, int inherit); } - SYS_SEMSYS = 251; // { int semsys(u_int which, int a2, int a3, int a4, int a5); } - // SYS_NOSYS = 251; // { int nosys(void); } - SYS_MSGSYS = 252; // { int msgsys(u_int which, int a2, int a3, int a4, int a5); } - // SYS_NOSYS = 252; // { int nosys(void); } - SYS_SHMSYS = 253; // { int shmsys(u_int which, int a2, int a3, int a4); } - // SYS_NOSYS = 253; // { int nosys(void); } - SYS_SEMCTL = 254; // { int semctl(int semid, int semnum, int cmd, semun_t arg); } - SYS_SEMGET = 255; // { int semget(key_t key, int nsems, int semflg); } - SYS_SEMOP = 256; // { int semop(int semid, struct sembuf *sops, int nsops); } - // SYS_NOSYS = 257; // { int nosys(void); } - // SYS_NOSYS = 254; // { int nosys(void); } - // SYS_NOSYS = 255; // { int nosys(void); } - // SYS_NOSYS = 256; // { int nosys(void); } - // SYS_NOSYS = 257; // { int nosys(void); } - SYS_MSGCTL = 258; // { int msgctl(int msqid, int cmd, struct msqid_ds *buf); } - SYS_MSGGET = 259; // { int msgget(key_t key, int msgflg); } - SYS_MSGSND = 260; // { int msgsnd(int msqid, void *msgp, size_t msgsz, int msgflg); } - SYS_MSGRCV = 261; // { user_ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg); } - // SYS_NOSYS = 258; // { int nosys(void); } - // SYS_NOSYS = 259; // { int nosys(void); } - // SYS_NOSYS = 260; // { int nosys(void); } - // SYS_NOSYS = 261; // { int nosys(void); } - SYS_SHMAT = 262; // { user_addr_t shmat(int shmid, void *shmaddr, int shmflg); } - SYS_SHMCTL = 263; // { int shmctl(int shmid, int cmd, struct shmid_ds *buf); } - SYS_SHMDT = 264; // { int shmdt(void *shmaddr); } - SYS_SHMGET = 265; // { int shmget(key_t key, size_t size, int shmflg); } - // SYS_NOSYS = 262; // { int nosys(void); } - // SYS_NOSYS = 263; // { int nosys(void); } - // SYS_NOSYS = 264; // { int nosys(void); } - // SYS_NOSYS = 265; // { int nosys(void); } - SYS_SHM_OPEN = 266; // { int shm_open(const char *name, int oflag, int mode); } - SYS_SHM_UNLINK = 267; // { int shm_unlink(const char *name); } - SYS_SEM_OPEN = 268; // { user_addr_t sem_open(const char *name, int oflag, int mode, int value); } - SYS_SEM_CLOSE = 269; // { int sem_close(sem_t *sem); } - SYS_SEM_UNLINK = 270; // { int sem_unlink(const char *name); } - SYS_SEM_WAIT = 271; // { int sem_wait(sem_t *sem); } - SYS_SEM_TRYWAIT = 272; // { int sem_trywait(sem_t *sem); } - SYS_SEM_POST = 273; // { int sem_post(sem_t *sem); } - SYS_SEM_GETVALUE = 274; // { int sem_getvalue(sem_t *sem, int *sval); } - SYS_SEM_INIT = 275; // { int sem_init(sem_t *sem, int phsared, u_int value); } - SYS_SEM_DESTROY = 276; // { int sem_destroy(sem_t *sem); } - SYS_OPEN_EXTENDED = 277; // { int open_extended(user_addr_t path, int flags, uid_t uid, gid_t gid, int mode, user_addr_t xsecurity) NO_SYSCALL_STUB; } - SYS_UMASK_EXTENDED = 278; // { int umask_extended(int newmask, user_addr_t xsecurity) NO_SYSCALL_STUB; } - SYS_STAT_EXTENDED = 279; // { int stat_extended(user_addr_t path, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size) NO_SYSCALL_STUB; } - SYS_LSTAT_EXTENDED = 280; // { int lstat_extended(user_addr_t path, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size) NO_SYSCALL_STUB; } - SYS_FSTAT_EXTENDED = 281; // { int fstat_extended(int fd, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size) NO_SYSCALL_STUB; } - SYS_CHMOD_EXTENDED = 282; // { int chmod_extended(user_addr_t path, uid_t uid, gid_t gid, int mode, user_addr_t xsecurity) NO_SYSCALL_STUB; } - SYS_FCHMOD_EXTENDED = 283; // { int fchmod_extended(int fd, uid_t uid, gid_t gid, int mode, user_addr_t xsecurity) NO_SYSCALL_STUB; } - SYS_ACCESS_EXTENDED = 284; // { int access_extended(user_addr_t entries, size_t size, user_addr_t results, uid_t uid) NO_SYSCALL_STUB; } - SYS_SETTID = 285; // { int settid(uid_t uid, gid_t gid) NO_SYSCALL_STUB; } - SYS_GETTID = 286; // { int gettid(uid_t *uidp, gid_t *gidp) NO_SYSCALL_STUB; } - SYS_SETSGROUPS = 287; // { int setsgroups(int setlen, user_addr_t guidset) NO_SYSCALL_STUB; } - SYS_GETSGROUPS = 288; // { int getsgroups(user_addr_t setlen, user_addr_t guidset) NO_SYSCALL_STUB; } - SYS_SETWGROUPS = 289; // { int setwgroups(int setlen, user_addr_t guidset) NO_SYSCALL_STUB; } - SYS_GETWGROUPS = 290; // { int getwgroups(user_addr_t setlen, user_addr_t guidset) NO_SYSCALL_STUB; } - SYS_MKFIFO_EXTENDED = 291; // { int mkfifo_extended(user_addr_t path, uid_t uid, gid_t gid, int mode, user_addr_t xsecurity) NO_SYSCALL_STUB; } - SYS_MKDIR_EXTENDED = 292; // { int mkdir_extended(user_addr_t path, uid_t uid, gid_t gid, int mode, user_addr_t xsecurity) NO_SYSCALL_STUB; } - SYS_IDENTITYSVC = 293; // { int identitysvc(int opcode, user_addr_t message) NO_SYSCALL_STUB; } - SYS_SHARED_REGION_CHECK_NP = 294; // { int shared_region_check_np(uint64_t *start_address) NO_SYSCALL_STUB; } - SYS_SHARED_REGION_MAP_NP = 295; // { int shared_region_map_np(int fd, uint32_t count, const struct shared_file_mapping_np *mappings) NO_SYSCALL_STUB; } - // SYS_NOSYS = 296; // { int nosys(void); } { old load_shared_file } - // SYS_NOSYS = 297; // { int nosys(void); } { old reset_shared_file } - // SYS_NOSYS = 298; // { int nosys(void); } { old new_system_shared_regions } - // SYS_ENOSYS = 299; // { int enosys(void); } { old shared_region_map_file_np } - // SYS_ENOSYS = 300; // { int enosys(void); } { old shared_region_make_private_np } - SYS___PTHREAD_MUTEX_DESTROY = 301; // { int __pthread_mutex_destroy(int mutexid); } - SYS___PTHREAD_MUTEX_INIT = 302; // { int __pthread_mutex_init(user_addr_t mutex, user_addr_t attr); } - SYS___PTHREAD_MUTEX_LOCK = 303; // { int __pthread_mutex_lock(int mutexid); } - SYS___PTHREAD_MUTEX_TRYLOCK = 304; // { int __pthread_mutex_trylock(int mutexid); } - SYS___PTHREAD_MUTEX_UNLOCK = 305; // { int __pthread_mutex_unlock(int mutexid); } - SYS___PTHREAD_COND_INIT = 306; // { int __pthread_cond_init(user_addr_t cond, user_addr_t attr); } - SYS___PTHREAD_COND_DESTROY = 307; // { int __pthread_cond_destroy(int condid); } - SYS___PTHREAD_COND_BROADCAST = 308; // { int __pthread_cond_broadcast(int condid); } - SYS___PTHREAD_COND_SIGNAL = 309; // { int __pthread_cond_signal(int condid); } - SYS_GETSID = 310; // { int getsid(pid_t pid); } - SYS_SETTID_WITH_PID = 311; // { int settid_with_pid(pid_t pid, int assume) NO_SYSCALL_STUB; } - SYS___PTHREAD_COND_TIMEDWAIT = 312; // { int __pthread_cond_timedwait(int condid, int mutexid, user_addr_t abstime); } - SYS_AIO_FSYNC = 313; // { int aio_fsync(int op, user_addr_t aiocbp); } - SYS_AIO_RETURN = 314; // { user_ssize_t aio_return(user_addr_t aiocbp); } - SYS_AIO_SUSPEND = 315; // { int aio_suspend(user_addr_t aiocblist, int nent, user_addr_t timeoutp); } - SYS_AIO_CANCEL = 316; // { int aio_cancel(int fd, user_addr_t aiocbp); } - SYS_AIO_ERROR = 317; // { int aio_error(user_addr_t aiocbp); } - SYS_AIO_READ = 318; // { int aio_read(user_addr_t aiocbp); } - SYS_AIO_WRITE = 319; // { int aio_write(user_addr_t aiocbp); } - SYS_LIO_LISTIO = 320; // { int lio_listio(int mode, user_addr_t aiocblist, int nent, user_addr_t sigp); } - SYS___PTHREAD_COND_WAIT = 321; // { int __pthread_cond_wait(int condid, int mutexid); } - SYS_IOPOLICYSYS = 322; // { int iopolicysys(int cmd, void *arg) NO_SYSCALL_STUB; } - // SYS_NOSYS = 323; // { int nosys(void); } - SYS_MLOCKALL = 324; // { int mlockall(int how); } - SYS_MUNLOCKALL = 325; // { int munlockall(int how); } - // SYS_NOSYS = 326; // { int nosys(void); } - SYS_ISSETUGID = 327; // { int issetugid(void); } - SYS___PTHREAD_KILL = 328; // { int __pthread_kill(int thread_port, int sig); } - SYS___PTHREAD_SIGMASK = 329; // { int __pthread_sigmask(int how, user_addr_t set, user_addr_t oset); } - SYS___SIGWAIT = 330; // { int __sigwait(user_addr_t set, user_addr_t sig); } - SYS___DISABLE_THREADSIGNAL = 331; // { int __disable_threadsignal(int value); } - SYS___PTHREAD_MARKCANCEL = 332; // { int __pthread_markcancel(int thread_port); } - SYS___PTHREAD_CANCELED = 333; // { int __pthread_canceled(int action); } - SYS___SEMWAIT_SIGNAL = 334; // { int __semwait_signal(int cond_sem, int mutex_sem, int timeout, int relative, time_t tv_sec, int32_t tv_nsec); } - // SYS_NOSYS = 335; // { int nosys(void); } { old utrace } - SYS_PROC_INFO = 336; // { int proc_info(int32_t callnum,int32_t pid,uint32_t flavor, uint64_t arg,user_addr_t buffer,int32_t buffersize) NO_SYSCALL_STUB; } - SYS_SENDFILE = 337; // { int sendfile(int fd, int s, off_t offset, off_t *nbytes, struct sf_hdtr *hdtr, int flags); } - // SYS_NOSYS = 337; // { int nosys(void); } - SYS_STAT64 = 338; // { int stat64(user_addr_t path, user_addr_t ub); } - SYS_FSTAT64 = 339; // { int fstat64(int fd, user_addr_t ub); } - SYS_LSTAT64 = 340; // { int lstat64(user_addr_t path, user_addr_t ub); } - SYS_STAT64_EXTENDED = 341; // { int stat64_extended(user_addr_t path, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size) NO_SYSCALL_STUB; } - SYS_LSTAT64_EXTENDED = 342; // { int lstat64_extended(user_addr_t path, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size) NO_SYSCALL_STUB; } - SYS_FSTAT64_EXTENDED = 343; // { int fstat64_extended(int fd, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size) NO_SYSCALL_STUB; } - SYS_GETDIRENTRIES64 = 344; // { user_ssize_t getdirentries64(int fd, void *buf, user_size_t bufsize, off_t *position) NO_SYSCALL_STUB; } - SYS_STATFS64 = 345; // { int statfs64(char *path, struct statfs64 *buf); } - SYS_FSTATFS64 = 346; // { int fstatfs64(int fd, struct statfs64 *buf); } - SYS_GETFSSTAT64 = 347; // { int getfsstat64(user_addr_t buf, int bufsize, int flags); } - SYS___PTHREAD_CHDIR = 348; // { int __pthread_chdir(user_addr_t path); } - SYS___PTHREAD_FCHDIR = 349; // { int __pthread_fchdir(int fd); } - SYS_AUDIT = 350; // { int audit(void *record, int length); } - SYS_AUDITON = 351; // { int auditon(int cmd, void *data, int length); } - // SYS_NOSYS = 352; // { int nosys(void); } - SYS_GETAUID = 353; // { int getauid(au_id_t *auid); } - SYS_SETAUID = 354; // { int setauid(au_id_t *auid); } - SYS_GETAUDIT = 355; // { int getaudit(struct auditinfo *auditinfo); } - SYS_SETAUDIT = 356; // { int setaudit(struct auditinfo *auditinfo); } - SYS_GETAUDIT_ADDR = 357; // { int getaudit_addr(struct auditinfo_addr *auditinfo_addr, int length); } - SYS_SETAUDIT_ADDR = 358; // { int setaudit_addr(struct auditinfo_addr *auditinfo_addr, int length); } - SYS_AUDITCTL = 359; // { int auditctl(char *path); } - // SYS_NOSYS = 350; // { int nosys(void); } - // SYS_NOSYS = 351; // { int nosys(void); } - // SYS_NOSYS = 352; // { int nosys(void); } - // SYS_NOSYS = 353; // { int nosys(void); } - // SYS_NOSYS = 354; // { int nosys(void); } - // SYS_NOSYS = 355; // { int nosys(void); } - // SYS_NOSYS = 356; // { int nosys(void); } - // SYS_NOSYS = 357; // { int nosys(void); } - // SYS_NOSYS = 358; // { int nosys(void); } - // SYS_NOSYS = 359; // { int nosys(void); } - SYS_BSDTHREAD_CREATE = 360; // { user_addr_t bsdthread_create(user_addr_t func, user_addr_t func_arg, user_addr_t stack, user_addr_t pthread, uint32_t flags) NO_SYSCALL_STUB; } - SYS_BSDTHREAD_TERMINATE = 361; // { int bsdthread_terminate(user_addr_t stackaddr, size_t freesize, uint32_t port, uint32_t sem) NO_SYSCALL_STUB; } - SYS_KQUEUE = 362; // { int kqueue(void); } - SYS_KEVENT = 363; // { int kevent(int fd, const struct kevent *changelist, int nchanges, struct kevent *eventlist, int nevents, const struct timespec *timeout); } - SYS_LCHOWN = 364; // { int lchown(user_addr_t path, uid_t owner, gid_t group); } - SYS_STACK_SNAPSHOT = 365; // { int stack_snapshot(pid_t pid, user_addr_t tracebuf, uint32_t tracebuf_size, uint32_t options) NO_SYSCALL_STUB; } - SYS_BSDTHREAD_REGISTER = 366; // { int bsdthread_register(user_addr_t threadstart, user_addr_t wqthread, int pthsize) NO_SYSCALL_STUB; } - SYS_WORKQ_OPEN = 367; // { int workq_open(void) NO_SYSCALL_STUB; } - SYS_WORKQ_OPS = 368; // { int workq_ops(int options, user_addr_t item, int prio) NO_SYSCALL_STUB; } - // SYS_NOSYS = 369; // { int nosys(void); } - // SYS_NOSYS = 370; // { int nosys(void); } - // SYS_NOSYS = 371; // { int nosys(void); } - // SYS_NOSYS = 372; // { int nosys(void); } - // SYS_NOSYS = 373; // { int nosys(void); } - // SYS_NOSYS = 374; // { int nosys(void); } - // SYS_NOSYS = 375; // { int nosys(void); } - // SYS_NOSYS = 376; // { int nosys(void); } - // SYS_NOSYS = 377; // { int nosys(void); } - // SYS_NOSYS = 378; // { int nosys(void); } - // SYS_NOSYS = 379; // { int nosys(void); } - SYS___MAC_EXECVE = 380; // { int __mac_execve(char *fname, char **argp, char **envp, struct mac *mac_p); } - SYS___MAC_SYSCALL = 381; // { int __mac_syscall(char *policy, int call, user_addr_t arg); } - SYS___MAC_GET_FILE = 382; // { int __mac_get_file(char *path_p, struct mac *mac_p); } - SYS___MAC_SET_FILE = 383; // { int __mac_set_file(char *path_p, struct mac *mac_p); } - SYS___MAC_GET_LINK = 384; // { int __mac_get_link(char *path_p, struct mac *mac_p); } - SYS___MAC_SET_LINK = 385; // { int __mac_set_link(char *path_p, struct mac *mac_p); } - SYS___MAC_GET_PROC = 386; // { int __mac_get_proc(struct mac *mac_p); } - SYS___MAC_SET_PROC = 387; // { int __mac_set_proc(struct mac *mac_p); } - SYS___MAC_GET_FD = 388; // { int __mac_get_fd(int fd, struct mac *mac_p); } - SYS___MAC_SET_FD = 389; // { int __mac_set_fd(int fd, struct mac *mac_p); } - SYS___MAC_GET_PID = 390; // { int __mac_get_pid(pid_t pid, struct mac *mac_p); } - SYS___MAC_GET_LCID = 391; // { int __mac_get_lcid(pid_t lcid, struct mac *mac_p); } - SYS___MAC_GET_LCTX = 392; // { int __mac_get_lctx(struct mac *mac_p); } - SYS___MAC_SET_LCTX = 393; // { int __mac_set_lctx(struct mac *mac_p); } - SYS_SETLCID = 394; // { int setlcid(pid_t pid, pid_t lcid) NO_SYSCALL_STUB; } - SYS_GETLCID = 395; // { int getlcid(pid_t pid) NO_SYSCALL_STUB; } - SYS_READ_NOCANCEL = 396; // { user_ssize_t read_nocancel(int fd, user_addr_t cbuf, user_size_t nbyte) NO_SYSCALL_STUB; } - SYS_WRITE_NOCANCEL = 397; // { user_ssize_t write_nocancel(int fd, user_addr_t cbuf, user_size_t nbyte) NO_SYSCALL_STUB; } - SYS_OPEN_NOCANCEL = 398; // { int open_nocancel(user_addr_t path, int flags, int mode) NO_SYSCALL_STUB; } - SYS_CLOSE_NOCANCEL = 399; // { int close_nocancel(int fd) NO_SYSCALL_STUB; } - SYS_WAIT4_NOCANCEL = 400; // { int wait4_nocancel(int pid, user_addr_t status, int options, user_addr_t rusage) NO_SYSCALL_STUB; } - SYS_RECVMSG_NOCANCEL = 401; // { int recvmsg_nocancel(int s, struct msghdr *msg, int flags) NO_SYSCALL_STUB; } - SYS_SENDMSG_NOCANCEL = 402; // { int sendmsg_nocancel(int s, caddr_t msg, int flags) NO_SYSCALL_STUB; } - SYS_RECVFROM_NOCANCEL = 403; // { int recvfrom_nocancel(int s, void *buf, size_t len, int flags, struct sockaddr *from, int *fromlenaddr) NO_SYSCALL_STUB; } - SYS_ACCEPT_NOCANCEL = 404; // { int accept_nocancel(int s, caddr_t name, socklen_t *anamelen) NO_SYSCALL_STUB; } - // SYS_NOSYS = 401; // { int nosys(void); } - // SYS_NOSYS = 402; // { int nosys(void); } - // SYS_NOSYS = 403; // { int nosys(void); } - // SYS_NOSYS = 404; // { int nosys(void); } - SYS_MSYNC_NOCANCEL = 405; // { int msync_nocancel(caddr_t addr, size_t len, int flags) NO_SYSCALL_STUB; } - SYS_FCNTL_NOCANCEL = 406; // { int fcntl_nocancel(int fd, int cmd, long arg) NO_SYSCALL_STUB; } - SYS_SELECT_NOCANCEL = 407; // { int select_nocancel(int nd, u_int32_t *in, u_int32_t *ou, u_int32_t *ex, struct timeval *tv) NO_SYSCALL_STUB; } - SYS_FSYNC_NOCANCEL = 408; // { int fsync_nocancel(int fd) NO_SYSCALL_STUB; } - SYS_CONNECT_NOCANCEL = 409; // { int connect_nocancel(int s, caddr_t name, socklen_t namelen) NO_SYSCALL_STUB; } - // SYS_NOSYS = 409; // { int nosys(void); } - SYS_SIGSUSPEND_NOCANCEL = 410; // { int sigsuspend_nocancel(sigset_t mask) NO_SYSCALL_STUB; } - SYS_READV_NOCANCEL = 411; // { user_ssize_t readv_nocancel(int fd, struct iovec *iovp, u_int iovcnt) NO_SYSCALL_STUB; } - SYS_WRITEV_NOCANCEL = 412; // { user_ssize_t writev_nocancel(int fd, struct iovec *iovp, u_int iovcnt) NO_SYSCALL_STUB; } - SYS_SENDTO_NOCANCEL = 413; // { int sendto_nocancel(int s, caddr_t buf, size_t len, int flags, caddr_t to, socklen_t tolen) NO_SYSCALL_STUB; } - // SYS_NOSYS = 413; // { int nosys(void); } - SYS_PREAD_NOCANCEL = 414; // { user_ssize_t pread_nocancel(int fd, user_addr_t buf, user_size_t nbyte, off_t offset) NO_SYSCALL_STUB; } - SYS_PWRITE_NOCANCEL = 415; // { user_ssize_t pwrite_nocancel(int fd, user_addr_t buf, user_size_t nbyte, off_t offset) NO_SYSCALL_STUB; } - SYS_WAITID_NOCANCEL = 416; // { int waitid_nocancel(idtype_t idtype, id_t id, siginfo_t *infop, int options) NO_SYSCALL_STUB; } - SYS_POLL_NOCANCEL = 417; // { int poll_nocancel(struct pollfd *fds, u_int nfds, int timeout) NO_SYSCALL_STUB; } - SYS_MSGSND_NOCANCEL = 418; // { int msgsnd_nocancel(int msqid, void *msgp, size_t msgsz, int msgflg) NO_SYSCALL_STUB; } - SYS_MSGRCV_NOCANCEL = 419; // { user_ssize_t msgrcv_nocancel(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg) NO_SYSCALL_STUB; } - // SYS_NOSYS = 418; // { int nosys(void); } - // SYS_NOSYS = 419; // { int nosys(void); } - SYS_SEM_WAIT_NOCANCEL = 420; // { int sem_wait_nocancel(sem_t *sem) NO_SYSCALL_STUB; } - SYS_AIO_SUSPEND_NOCANCEL = 421; // { int aio_suspend_nocancel(user_addr_t aiocblist, int nent, user_addr_t timeoutp) NO_SYSCALL_STUB; } - SYS___SIGWAIT_NOCANCEL = 422; // { int __sigwait_nocancel(user_addr_t set, user_addr_t sig) NO_SYSCALL_STUB; } - SYS___SEMWAIT_SIGNAL_NOCANCEL = 423; // { int __semwait_signal_nocancel(int cond_sem, int mutex_sem, int timeout, int relative, time_t tv_sec, int32_t tv_nsec) NO_SYSCALL_STUB; } - SYS___MAC_MOUNT = 424; // { int __mac_mount(char *type, char *path, int flags, caddr_t data, struct mac *mac_p); } - SYS___MAC_GET_MOUNT = 425; // { int __mac_get_mount(char *path, struct mac *mac_p); } - SYS___MAC_GETFSSTAT = 426; // { int __mac_getfsstat(user_addr_t buf, int bufsize, user_addr_t mac, int macsize, int flags); } -) diff --git a/src/lib/syscall/zsysnum_linux_386.go b/src/lib/syscall/zsysnum_linux_386.go deleted file mode 100644 index 46c1112f8..000000000 --- a/src/lib/syscall/zsysnum_linux_386.go +++ /dev/null @@ -1,319 +0,0 @@ -// Generated by mklinux; DO NOT EDIT. -// mklinux /usr/include/asm/unistd_32.h - -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_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_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 = 322; - SYS_EVENTFD = 323; - SYS_FALLOCATE = 324; -) - -func _darwin_system_call_conflict() { -} diff --git a/src/lib/syscall/zsysnum_linux_amd64.go b/src/lib/syscall/zsysnum_linux_amd64.go deleted file mode 100644 index 94424f3f3..000000000 --- a/src/lib/syscall/zsysnum_linux_amd64.go +++ /dev/null @@ -1,296 +0,0 @@ -// Generated by mklinux; DO NOT EDIT. -// mklinux /usr/include/asm/unistd_64.h - -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 = 283; - SYS_EVENTFD = 284; - SYS_FALLOCATE = 285; -) - -func _darwin_system_call_conflict() { -} diff --git a/src/lib/syscall/ztypes_darwin_386.go b/src/lib/syscall/ztypes_darwin_386.go deleted file mode 100644 index 29d0d9676..000000000 --- a/src/lib/syscall/ztypes_darwin_386.go +++ /dev/null @@ -1,246 +0,0 @@ -// godefs -gsyscall -f-m32 types_darwin.c types_darwin_386.c - -// MACHINE GENERATED - DO NOT EDIT. - -package syscall - -// Constants -const ( - sizeofPtr = 0x4; - sizeofShort = 0x2; - sizeofInt = 0x4; - sizeofLong = 0x4; - sizeofLongLong = 0x8; - O_RDONLY = 0; - O_WRONLY = 0x1; - O_RDWR = 0x2; - O_APPEND = 0x8; - O_ASYNC = 0x40; - O_CREAT = 0x200; - O_NOCTTY = 0x20000; - O_NONBLOCK = 0x4; - O_SYNC = 0x80; - O_TRUNC = 0x400; - O_CLOEXEC = 0; - F_GETFD = 0x1; - F_SETFD = 0x2; - F_GETFL = 0x3; - F_SETFL = 0x4; - FD_CLOEXEC = 0x1; - NAME_MAX = 0xff; - 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_IFWHT = 0xe000; - S_ISUID = 0x800; - S_ISGID = 0x400; - S_ISVTX = 0x200; - S_IRUSR = 0x100; - S_IWUSR = 0x80; - S_IXUSR = 0x40; - WNOHANG = 0x1; - WUNTRACED = 0x2; - WEXITED = 0x4; - WSTOPPED = 0x7f; - WCONTINUED = 0x10; - WNOWAIT = 0x20; - AF_UNIX = 0x1; - AF_INET = 0x2; - AF_DATAKIT = 0x9; - AF_INET6 = 0x1e; - SOCK_STREAM = 0x1; - SOCK_DGRAM = 0x2; - SOCK_RAW = 0x3; - SOCK_SEQPACKET = 0x5; - SOL_SOCKET = 0xffff; - SO_REUSEADDR = 0x4; - SO_KEEPALIVE = 0x8; - SO_DONTROUTE = 0x10; - SO_BROADCAST = 0x20; - SO_USELOOPBACK = 0x40; - SO_LINGER = 0x80; - SO_REUSEPORT = 0x200; - SO_SNDBUF = 0x1001; - SO_RCVBUF = 0x1002; - SO_SNDTIMEO = 0x1005; - SO_RCVTIMEO = 0x1006; - SO_NOSIGPIPE = 0x1022; - IPPROTO_TCP = 0x6; - IPPROTO_UDP = 0x11; - TCP_NODELAY = 0x1; - SOMAXCONN = 0x80; - SizeofSockaddrInet4 = 0x10; - SizeofSockaddrInet6 = 0x1c; - SizeofSockaddrAny = 0x1c; - SizeofSockaddrUnix = 0x6a; - EVFILT_READ = -0x1; - EVFILT_WRITE = -0x2; - EVFILT_AIO = -0x3; - EVFILT_VNODE = -0x4; - EVFILT_PROC = -0x5; - EVFILT_SIGNAL = -0x6; - EVFILT_TIMER = -0x7; - EVFILT_MACHPORT = -0x8; - EVFILT_FS = -0x9; - EVFILT_SYSCOUNT = 0x9; - EV_ADD = 0x1; - EV_DELETE = 0x2; - EV_DISABLE = 0x8; - EV_RECEIPT = 0x40; - EV_ONESHOT = 0x10; - EV_CLEAR = 0x20; - EV_SYSFLAGS = 0xf000; - EV_FLAG0 = 0x1000; - EV_FLAG1 = 0x2000; - EV_EOF = 0x8000; - EV_ERROR = 0x4000; -) - -// Types - -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 _C_int int32 - -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 Dirent struct { - Ino uint64; - Seekoff uint64; - Reclen uint16; - Namlen uint16; - Type uint8; - Name [1024]int8; - Pad0 [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 RawSockaddr struct { - Len uint8; - Family uint8; - Data [14]int8; -} - -type RawSockaddrAny struct { - Addr RawSockaddr; - Pad [12]int8; -} - -type _Socklen uint32 - -type Linger struct { - Onoff int32; - Linger int32; -} - -type Kevent_t struct { - Ident uint32; - Filter int16; - Flags uint16; - Fflags uint32; - Data int32; - Udata *byte; -} - -type FdSet struct { - Bits [32]int32; -} diff --git a/src/lib/syscall/ztypes_darwin_amd64.go b/src/lib/syscall/ztypes_darwin_amd64.go deleted file mode 100644 index 0523c50a4..000000000 --- a/src/lib/syscall/ztypes_darwin_amd64.go +++ /dev/null @@ -1,248 +0,0 @@ -// godefs -gsyscall -f-m64 types_darwin.c types_darwin_amd64.c - -// MACHINE GENERATED - DO NOT EDIT. - -package syscall - -// Constants -const ( - sizeofPtr = 0x8; - sizeofShort = 0x2; - sizeofInt = 0x4; - sizeofLong = 0x8; - sizeofLongLong = 0x8; - O_RDONLY = 0; - O_WRONLY = 0x1; - O_RDWR = 0x2; - O_APPEND = 0x8; - O_ASYNC = 0x40; - O_CREAT = 0x200; - O_NOCTTY = 0x20000; - O_NONBLOCK = 0x4; - O_SYNC = 0x80; - O_TRUNC = 0x400; - O_CLOEXEC = 0; - F_GETFD = 0x1; - F_SETFD = 0x2; - F_GETFL = 0x3; - F_SETFL = 0x4; - FD_CLOEXEC = 0x1; - NAME_MAX = 0xff; - 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_IFWHT = 0xe000; - S_ISUID = 0x800; - S_ISGID = 0x400; - S_ISVTX = 0x200; - S_IRUSR = 0x100; - S_IWUSR = 0x80; - S_IXUSR = 0x40; - WNOHANG = 0x1; - WUNTRACED = 0x2; - WEXITED = 0x4; - WSTOPPED = 0x7f; - WCONTINUED = 0x10; - WNOWAIT = 0x20; - AF_UNIX = 0x1; - AF_INET = 0x2; - AF_DATAKIT = 0x9; - AF_INET6 = 0x1e; - SOCK_STREAM = 0x1; - SOCK_DGRAM = 0x2; - SOCK_RAW = 0x3; - SOCK_SEQPACKET = 0x5; - SOL_SOCKET = 0xffff; - SO_REUSEADDR = 0x4; - SO_KEEPALIVE = 0x8; - SO_DONTROUTE = 0x10; - SO_BROADCAST = 0x20; - SO_USELOOPBACK = 0x40; - SO_LINGER = 0x80; - SO_REUSEPORT = 0x200; - SO_SNDBUF = 0x1001; - SO_RCVBUF = 0x1002; - SO_SNDTIMEO = 0x1005; - SO_RCVTIMEO = 0x1006; - SO_NOSIGPIPE = 0x1022; - IPPROTO_TCP = 0x6; - IPPROTO_UDP = 0x11; - TCP_NODELAY = 0x1; - SOMAXCONN = 0x80; - SizeofSockaddrInet4 = 0x10; - SizeofSockaddrInet6 = 0x1c; - SizeofSockaddrAny = 0x1c; - SizeofSockaddrUnix = 0x6a; - EVFILT_READ = -0x1; - EVFILT_WRITE = -0x2; - EVFILT_AIO = -0x3; - EVFILT_VNODE = -0x4; - EVFILT_PROC = -0x5; - EVFILT_SIGNAL = -0x6; - EVFILT_TIMER = -0x7; - EVFILT_MACHPORT = -0x8; - EVFILT_FS = -0x9; - EVFILT_SYSCOUNT = 0x9; - EV_ADD = 0x1; - EV_DELETE = 0x2; - EV_DISABLE = 0x8; - EV_RECEIPT = 0x40; - EV_ONESHOT = 0x10; - EV_CLEAR = 0x20; - EV_SYSFLAGS = 0xf000; - EV_FLAG0 = 0x1000; - EV_FLAG1 = 0x2000; - EV_EOF = 0x8000; - EV_ERROR = 0x4000; -) - -// Types - -type Timespec struct { - Sec int64; - Nsec int64; -} - -type Timeval struct { - Sec int64; - Usec int32; - Pad0 [4]byte; -} - -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 _C_int int32 - -type _Gid_t uint32 - -type Stat_t struct { - Dev int32; - Mode uint16; - Nlink uint16; - Ino uint64; - Uid uint32; - Gid uint32; - Rdev int32; - Pad0 [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 Dirent struct { - Ino uint64; - Seekoff uint64; - Reclen uint16; - Namlen uint16; - Type uint8; - Name [1024]int8; - Pad0 [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 RawSockaddr struct { - Len uint8; - Family uint8; - Data [14]int8; -} - -type RawSockaddrAny struct { - Addr RawSockaddr; - Pad [12]int8; -} - -type _Socklen uint32 - -type Linger struct { - Onoff int32; - Linger int32; -} - -type Kevent_t struct { - Ident uint64; - Filter int16; - Flags uint16; - Fflags uint32; - Data int64; - Udata *byte; -} - -type FdSet struct { - Bits [32]int32; -} diff --git a/src/lib/syscall/ztypes_linux_386.go b/src/lib/syscall/ztypes_linux_386.go deleted file mode 100644 index c3a083762..000000000 --- a/src/lib/syscall/ztypes_linux_386.go +++ /dev/null @@ -1,297 +0,0 @@ -// godefs -gsyscall -f-m32 types_linux.c types_linux_386.c - -// MACHINE GENERATED - DO NOT EDIT. - -package syscall - -// Constants -const ( - sizeofPtr = 0x4; - sizeofShort = 0x2; - sizeofInt = 0x4; - sizeofLong = 0x4; - sizeofLongLong = 0x8; - PathMax = 0x1000; - O_RDONLY = 0; - O_WRONLY = 0x1; - O_RDWR = 0x2; - O_APPEND = 0x400; - O_ASYNC = 0x2000; - O_CREAT = 0x40; - O_NOCTTY = 0x100; - O_NONBLOCK = 0x800; - O_SYNC = 0x1000; - O_TRUNC = 0x200; - O_CLOEXEC = 0; - F_GETFD = 0x1; - F_SETFD = 0x2; - F_GETFL = 0x3; - F_SETFL = 0x4; - FD_CLOEXEC = 0x1; - NAME_MAX = 0xff; - 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; - WNOHANG = 0x1; - WUNTRACED = 0x2; - WEXITED = 0x4; - WSTOPPED = 0x2; - WCONTINUED = 0x8; - WNOWAIT = 0x1000000; - AF_UNIX = 0x1; - AF_INET = 0x2; - AF_INET6 = 0xa; - SOCK_STREAM = 0x1; - SOCK_DGRAM = 0x2; - SOCK_RAW = 0x3; - SOCK_SEQPACKET = 0x5; - SOL_SOCKET = 0x1; - SO_REUSEADDR = 0x2; - SO_KEEPALIVE = 0x9; - SO_DONTROUTE = 0x5; - SO_BROADCAST = 0x6; - SO_LINGER = 0xd; - SO_SNDBUF = 0x7; - SO_RCVBUF = 0x8; - SO_SNDTIMEO = 0x15; - SO_RCVTIMEO = 0x14; - IPPROTO_TCP = 0x6; - IPPROTO_UDP = 0x11; - TCP_NODELAY = 0x1; - SOMAXCONN = 0x80; - SizeofSockaddrInet4 = 0x10; - SizeofSockaddrInet6 = 0x1c; - SizeofSockaddrAny = 0x1c; - SizeofSockaddrUnix = 0x6e; - EPOLLIN = 0x1; - EPOLLRDHUP = 0x2000; - EPOLLOUT = 0x4; - EPOLLONESHOT = 0x40000000; - EPOLL_CTL_MOD = 0x3; - EPOLL_CTL_ADD = 0x1; - EPOLL_CTL_DEL = 0x2; -) - -// Types - -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; - int32; - int32; - int32; - int32; - int32; - int32; - int32; - int32; - int32; - int32; - int32; - 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 uint32; - Max uint32; -} - -type _C_int int32 - -type _Gid_t uint32 - -type Stat_t struct { - Dev uint64; - __pad1 uint16; - Pad0 [2]byte; - Ino uint32; - Mode uint32; - Nlink uint32; - Uid uint32; - Gid uint32; - Rdev uint64; - __pad2 uint16; - Pad1 [2]byte; - Size int32; - Blksize int32; - Blocks int32; - Atim Timespec; - Mtim Timespec; - Ctim Timespec; - __unused4 uint32; - __unused5 uint32; -} - -type Statfs_t struct { - Type int32; - Bsize int32; - Blocks uint32; - Bfree uint32; - Bavail uint32; - Files uint32; - Ffree uint32; - Fsid [8]byte /* __fsid_t */; - Namelen int32; - Frsize int32; - Spare [5]int32; -} - -type Dirent struct { - Ino uint32; - Off int32; - Reclen uint16; - Type uint8; - Name [256]int8; - Pad0 [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 RawSockaddr struct { - Family uint16; - Data [14]int8; -} - -type RawSockaddrAny struct { - Addr RawSockaddr; - Pad [12]int8; -} - -type _Socklen uint32 - -type Linger struct { - Onoff int32; - Linger int32; -} - -type FdSet struct { - __fds_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; - _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/lib/syscall/ztypes_linux_amd64.go b/src/lib/syscall/ztypes_linux_amd64.go deleted file mode 100644 index f17ebe139..000000000 --- a/src/lib/syscall/ztypes_linux_amd64.go +++ /dev/null @@ -1,300 +0,0 @@ -// godefs -gsyscall -f-m64 types_linux.c types_linux_amd64.c - -// MACHINE GENERATED - DO NOT EDIT. - -package syscall - -// Constants -const ( - sizeofPtr = 0x8; - sizeofShort = 0x2; - sizeofInt = 0x4; - sizeofLong = 0x8; - sizeofLongLong = 0x8; - PathMax = 0x1000; - O_RDONLY = 0; - O_WRONLY = 0x1; - O_RDWR = 0x2; - O_APPEND = 0x400; - O_ASYNC = 0x2000; - O_CREAT = 0x40; - O_NOCTTY = 0x100; - O_NONBLOCK = 0x800; - O_SYNC = 0x1000; - O_TRUNC = 0x200; - O_CLOEXEC = 0; - F_GETFD = 0x1; - F_SETFD = 0x2; - F_GETFL = 0x3; - F_SETFL = 0x4; - FD_CLOEXEC = 0x1; - NAME_MAX = 0xff; - 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; - WNOHANG = 0x1; - WUNTRACED = 0x2; - WEXITED = 0x4; - WSTOPPED = 0x2; - WCONTINUED = 0x8; - WNOWAIT = 0x1000000; - AF_UNIX = 0x1; - AF_INET = 0x2; - AF_INET6 = 0xa; - SOCK_STREAM = 0x1; - SOCK_DGRAM = 0x2; - SOCK_RAW = 0x3; - SOCK_SEQPACKET = 0x5; - SOL_SOCKET = 0x1; - SO_REUSEADDR = 0x2; - SO_KEEPALIVE = 0x9; - SO_DONTROUTE = 0x5; - SO_BROADCAST = 0x6; - SO_LINGER = 0xd; - SO_SNDBUF = 0x7; - SO_RCVBUF = 0x8; - SO_SNDTIMEO = 0x15; - SO_RCVTIMEO = 0x14; - IPPROTO_TCP = 0x6; - IPPROTO_UDP = 0x11; - TCP_NODELAY = 0x1; - SOMAXCONN = 0x80; - SizeofSockaddrInet4 = 0x10; - SizeofSockaddrInet6 = 0x1c; - SizeofSockaddrAny = 0x1c; - SizeofSockaddrUnix = 0x6e; - EPOLLIN = 0x1; - EPOLLRDHUP = 0x2000; - EPOLLOUT = 0x4; - EPOLLONESHOT = 0x40000000; - EPOLL_CTL_MOD = 0x3; - EPOLL_CTL_ADD = 0x1; - EPOLL_CTL_DEL = 0x2; -) - -// Types - -type Timespec struct { - Sec int64; - Nsec int64; -} - -type Timeval struct { - Sec int64; - Usec int64; -} - -type Timex struct { - Modes uint32; - Pad0 [4]byte; - Offset int64; - Freq int64; - Maxerror int64; - Esterror int64; - Status int32; - Pad1 [4]byte; - Constant int64; - Precision int64; - Tolerance int64; - Time Timeval; - Tick int64; - Ppsfreq int64; - Jitter int64; - Shift int32; - Pad2 [4]byte; - Stabil int64; - Jitcnt int64; - Calcnt int64; - Errcnt int64; - Stbcnt int64; - int32; - int32; - int32; - int32; - int32; - int32; - int32; - int32; - int32; - int32; - int32; - 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 _C_int int32 - -type _Gid_t uint32 - -type Stat_t struct { - Dev uint64; - Ino uint64; - Nlink uint64; - Mode uint32; - Uid uint32; - Gid uint32; - Pad0 int32; - Rdev uint64; - Size int64; - Blksize int64; - Blocks int64; - Atim Timespec; - Mtim Timespec; - Ctim Timespec; - __unused [3]int64; -} - -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; - Pad0 [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 RawSockaddr struct { - Family uint16; - Data [14]int8; -} - -type RawSockaddrAny struct { - Addr RawSockaddr; - Pad [12]int8; -} - -type _Socklen uint32 - -type Linger struct { - Onoff int32; - Linger int32; -} - -type FdSet struct { - __fds_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; - Pad0 [4]byte; - Totalhigh uint64; - Freehigh uint64; - Unit uint32; - _f [2]int8; - Pad1 [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; - Pad0 [4]byte; - Tinode uint64; - Fname [6]int8; - Fpack [6]int8; - Pad1 [4]byte; -} - -type EpollEvent struct { - Events uint32; - Fd int32; - Pad int32; -} diff --git a/src/lib/tabwriter/Makefile b/src/lib/tabwriter/Makefile deleted file mode 100644 index 1c4518066..000000000 --- a/src/lib/tabwriter/Makefile +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m >Makefile - -D= - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - tabwriter.$O\ - - -phases: a1 -_obj$D/tabwriter.a: phases - -a1: $(O1) - $(AR) grc _obj$D/tabwriter.a tabwriter.$O - rm -f $(O1) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/tabwriter.a - -$(O1): newpkg -$(O2): a1 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/tabwriter.a - -packages: _obj$D/tabwriter.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/tabwriter.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/tabwriter.a diff --git a/src/lib/tabwriter/tabwriter.go b/src/lib/tabwriter/tabwriter.go deleted file mode 100644 index 6799f72d1..000000000 --- a/src/lib/tabwriter/tabwriter.go +++ /dev/null @@ -1,437 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// The tabwriter package implements a write filter (tabwriter.Writer) -// that translates tabbed columns in input into properly aligned text, -// using the Elastic Tabstops algorithm described at -// http://nickgravgaard.com/elastictabstops/index.html. -// -package tabwriter - -import ( - "container/vector"; - "io"; - "os"; - "utf8"; -) - - -// ---------------------------------------------------------------------------- -// Filter implementation - -// 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 tab-terminated cells. 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. Note that cells are tab-terminated, -// not tab-separated: trailing non-tab text at the end of a line -// is not part of any cell. -// -// The Writer assumes that all characters have the same width; -// this may not be true in some fonts, especially with certain -// UTF-8 characters. -// -// If a Writer is configured to filter HTML, HTML tags and entities -// are simply passed through and their widths are assumed to be zero -// for formatting purposes. -// -// The form feed 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, form feed 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; - cellwidth int; - padding int; - padbytes [8]byte; - flags uint; - - // current state - html_char byte; // terminating char of html tag/entity, or 0 ('>', ';', or 0) - buf io.ByteBuffer; // collected text w/o tabs, newlines, or form feed chars - size int; // size of incomplete cell in bytes - width int; // width of incomplete cell in runes up to buf[pos] w/o ignored sections - pos int; // buffer position up to which width of incomplete cell has been computed - lines_size vector.Vector; // list of lines; each line is a list of cell sizes in bytes - lines_width vector.Vector; // list of lines; each line is a list of cell widths in runes - widths vector.IntVector; // list of column widths in runes - re-used during formatting -} - - -// Internal representation (current state): -// -// - all text written is appended to buf; form feed chars, tabs and newlines are stripped away -// - at any given time there is a (possibly empty) incomplete cell at the end -// (the cell starts after a tab or newline) -// - size is the number of bytes belonging to the cell so far -// - 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_size and -// lines_width arrays, which contain an array of sizes or widths for each line -// - the widths array is a temporary array with current widths used during -// formatting; it is kept in Writer because it's re-used -// -// |<---------- size ---------->| -// | | -// |<- width ->|<- ignored ->| | -// | | | | -// [---processed---tab------------......] -// ^ ^ ^ -// | | | -// buf start of incomplete cell pos - - -func (b *Writer) addLine() { - b.lines_size.Push(vector.NewIntVector(0)); - b.lines_width.Push(vector.NewIntVector(0)); -} - - -// 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 = 1 << iota; - - // Force right-alignment of cell content. - // Default is left-alignment. - AlignRight; -) - - -// A Writer must be initialized with a call to Init. The first parameter (output) -// specifies the filter output. The remaining parameters control the formatting: -// -// cellwidth minimal cell width -// padding additional cell padding -// padchar ASCII char used for padding -// if padchar == '\t', the Writer will assume that the -// width of a '\t' in the formatted output is cellwidth, -// and cells are left-aligned independent of align_left -// (for correct-looking results, cellwidth must correspond -// to the tab width in the viewer displaying the result) -// flags formatting control -// -func (b *Writer) Init(output io.Writer, cellwidth, padding int, padchar byte, flags uint) *Writer { - if cellwidth < 0 { - panic("negative cellwidth"); - } - if padding < 0 { - panic("negative padding"); - } - b.output = output; - b.cellwidth = cellwidth; - b.padding = padding; - for i := len(b.padbytes) - 1; i >= 0; i-- { - b.padbytes[i] = padchar; - } - if padchar == '\t' { - // tab enforces left-alignment - flags &^= AlignRight; - } - b.flags = flags; - - b.lines_size.Init(0); - b.lines_width.Init(0); - b.widths.Init(0); - b.addLine(); // the very first line - - return b; -} - - -func (b *Writer) line(i int) (*vector.IntVector, *vector.IntVector) { - return - b.lines_size.At(i).(*vector.IntVector), - b.lines_width.At(i).(*vector.IntVector); -} - - -// debugging support (keep code around) -/* -func (b *Writer) dump() { - pos := 0; - for i := 0; i < b.lines_size.Len(); i++ { - line_size, line_width := b.line(i); - print("(", i, ") "); - for j := 0; j < line_size.Len(); j++ { - s := line_size.At(j); - print("[", string(b.buf.slice(pos, pos + s)), "]"); - pos += s; - } - print("\n"); - } - print("\n"); -} -*/ - - -func (b *Writer) write0(buf []byte) os.Error { - n, err := b.output.Write(buf); - if n != len(buf) && err == nil { - err = os.EIO; - } - return err; -} - - -var newline = []byte{'\n'} - -func (b *Writer) writePadding(textw, cellw int) os.Error { - if b.padbytes[0] == '\t' { - // make cell width a multiple of cellwidth - cellw = ((cellw + b.cellwidth - 1) / b.cellwidth) * b.cellwidth; - } - - n := cellw - textw; - if n < 0 { - panic("internal error"); - } - - if b.padbytes[0] == '\t' { - n = (n + b.cellwidth - 1) / b.cellwidth; - } - - for n > len(b.padbytes) { - if err := b.write0(&b.padbytes); err != nil { - return err; - } - n -= len(b.padbytes); - } - - return b.write0(b.padbytes[0 : n]); -} - - -func (b *Writer) writeLines(pos0 int, line0, line1 int) (int, os.Error) { - pos := pos0; - for i := line0; i < line1; i++ { - line_size, line_width := b.line(i); - for j := 0; j < line_size.Len(); j++ { - s, w := line_size.At(j), line_width.At(j); - - switch { - default: // align left - - if err := b.write0(b.buf.Data()[pos : pos + s]); err != nil { - return pos, err; - } - pos += s; - if j < b.widths.Len() { - if err := b.writePadding(w, b.widths.At(j)); err != nil { - return pos, err; - } - } - - case b.flags & AlignRight != 0: // align right - - if j < b.widths.Len() { - if err := b.writePadding(w, b.widths.At(j)); err != nil { - return pos, err; - } - } - if err := b.write0(b.buf.Data()[pos : pos + s]); err != nil { - return pos, err; - } - pos += s; - } - } - - if i+1 == b.lines_size.Len() { - // last buffered line - we don't have a newline, so just write - // any outstanding buffered data - if err := b.write0(b.buf.Data()[pos : pos + b.size]); err != nil { - return pos, err; - } - pos += b.size; - } else { - // not the last line - write newline - if err := b.write0(newline); err != nil { - return pos, err; - } - } - } - return pos, nil; -} - - -func (b *Writer) format(pos0 int, line0, line1 int) (pos int, err os.Error) { - pos = pos0; - column := b.widths.Len(); - last := line0; - for this := line0; this < line1; this++ { - line_size, line_width := b.line(this); - - if column < line_size.Len() - 1 { - // cell exists in this column - // (note that the last cell per line is ignored) - - // print unprinted lines until beginning of block - pos, err = b.writeLines(pos, last, this); - if err != nil { - return pos, err; - } - last = this; - - // column block begin - width := b.cellwidth; // minimal width - for ; this < line1; this++ { - line_size, line_width = b.line(this); - if column < line_size.Len() - 1 { - // cell exists in this column => update width - w := line_width.At(column) + b.padding; - if w > width { - width = w; - } - } else { - break - } - } - // column block end - - // format and print all columns to the right of this column - // (we know the widths of this column and all columns to the left) - b.widths.Push(width); - pos, err = b.format(pos, last, this); - b.widths.Pop(); - last = this; - } - } - - // print unprinted lines until end - return b.writeLines(pos, last, line1); -} - - -// Flush should be called after the last call to Write to ensure -// that any data buffered in the Writer is written to output. -// -func (b *Writer) Flush() os.Error { - _, err := b.format(0, 0, b.lines_size.Len()); - // reset (even in the presence of errors) - b.buf.Reset(); - b.size, b.width = 0, 0; - b.pos = 0; - b.lines_size.Init(0); - b.lines_width.Init(0); - b.addLine(); - return err; -} - - -func unicodeLen(buf []byte) int { - l := 0; - for i := 0; i < len(buf); { - if buf[i] < utf8.RuneSelf { - i++; - } else { - rune, size := utf8.DecodeRune(buf[i : len(buf)]); - i += size; - } - l++; - } - return l; -} - - -func (b *Writer) append(buf []byte) { - b.buf.Write(buf); - b.size += len(buf); -} - - -// 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) (written int, err os.Error) { - i0, n := 0, len(buf); - - // split text into cells - for i := 0; i < n; i++ { - ch := buf[i]; - - if b.html_char == 0 { - // outside html tag/entity - switch ch { - case '\t', '\n', '\f': - b.append(buf[i0 : i]); - i0 = i + 1; // exclude ch from (next) cell - b.width += unicodeLen(b.buf.Data()[b.pos : b.buf.Len()]); - b.pos = b.buf.Len(); - - // terminate cell - last_size, last_width := b.line(b.lines_size.Len() - 1); - last_size.Push(b.size); - last_width.Push(b.width); - b.size, b.width = 0, 0; - - if ch != '\t' { - // terminate line - b.addLine(); - if ch == '\f' || last_size.Len() == 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 i0, err; - } - } - } - - case '<', '&': - if b.flags & FilterHTML != 0 { - b.append(buf[i0 : i]); - i0 = i; - b.width += unicodeLen(b.buf.Data()[b.pos : b.buf.Len()]); - b.pos = -1; // preventative - should not be used (will cause index out of bounds) - if ch == '<' { - b.html_char = '>'; - } else { - b.html_char = ';'; - } - } - } - - } else { - // inside html tag/entity - if ch == b.html_char { - // reached the end of tag/entity - b.append(buf[i0 : i + 1]); - i0 = i + 1; - if b.html_char == ';' { - b.width++; // count as one char - } - b.pos = b.buf.Len(); - b.html_char = 0; - } - } - } - - // append leftover text - b.append(buf[i0 : n]); - return n, nil; -} - - -// NewWriter allocates and initializes a new tabwriter.Writer. -// The parameters are the same as for the the Init function. -// -func NewWriter(output io.Writer, cellwidth, padding int, padchar byte, flags uint) *Writer { - return new(Writer).Init(output, cellwidth, padding, padchar, flags) -} diff --git a/src/lib/tabwriter/tabwriter_test.go b/src/lib/tabwriter/tabwriter_test.go deleted file mode 100644 index 7026446e6..000000000 --- a/src/lib/tabwriter/tabwriter_test.go +++ /dev/null @@ -1,380 +0,0 @@ -// Copyright 2009 The Go Authors. 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"; - "tabwriter"; - "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 { - panicln("buffer too small", n, m, cap(b.a)); - } - return len(buf), nil; -} - - -func (b *buffer) String() string { - return string(b.a); -} - - -func write(t *testing.T, w *tabwriter.Writer, src string) { - written, err := io.WriteString(w, src); - if err != nil { - t.Errorf("--- src:\n%s\n--- write error: %v\n", src, err); - } - if written != len(src) { - t.Errorf("--- src:\n%s\n--- written = %d, len(src) = %d\n", src, written, len(src)); - } -} - - -func verify(t *testing.T, w *tabwriter.Writer, b *buffer, src, expected string) { - err := w.Flush(); - if err != nil { - t.Errorf("--- src:\n%s\n--- flush error: %v\n", src, err); - } - - res := b.String(); - if res != expected { - t.Errorf("--- src:\n%s\n--- found:\n%s\n--- expected:\n%s\n", src, res, expected) - } -} - - -func check(t *testing.T, tabwidth, padding int, padchar byte, flags uint, src, expected string) { - var b buffer; - b.init(1000); - - var w tabwriter.Writer; - w.Init(&b, tabwidth, padding, padchar, flags); - - // write all at once - b.clear(); - write(t, &w, src); - verify(t, &w, &b, src, expected); - - // write byte-by-byte - b.clear(); - for i := 0; i < len(src); i++ { - write(t, &w, src[i : i+1]); - } - verify(t, &w, &b, src, expected); - - // write using Fibonacci slice sizes - b.clear(); - for i, d := 0, 0; i < len(src); { - write(t, &w, src[i : i+d]); - i, d = i+d, d+1; - if i+d > len(src) { - d = len(src) - i; - } - } - verify(t, &w, &b, src, expected); -} - - -type entry struct { - tabwidth, padding int; - padchar byte; - flags uint; - src, expected string; -} - - -var tests = []entry { - entry{ - 8, 1, '.', 0, - "", - "" - }, - - entry{ - 8, 1, '.', 0, - "\n\n\n", - "\n\n\n" - }, - - entry{ - 8, 1, '.', 0, - "a\nb\nc", - "a\nb\nc" - }, - - entry{ - 8, 1, '.', 0, - "\t", // '\t' terminates an empty cell on last line - nothing to print - "" - }, - - entry{ - 8, 1, '.', tabwriter.AlignRight, - "\t", // '\t' terminates an empty cell on last line - nothing to print - "" - }, - - entry{ - 8, 1, '.', 0, - "*\t*", - "**" - }, - - entry{ - 8, 1, '.', 0, - "*\t*\n", - "*.......*\n" - }, - - entry{ - 8, 1, '.', 0, - "*\t*\t", - "*.......*" - }, - - entry{ - 8, 1, '.', tabwriter.AlignRight, - "*\t*\t", - ".......**" - }, - - entry{ - 8, 1, '.', 0, - "\t\n", - "........\n" - }, - - entry{ - 8, 1, '.', 0, - "a) foo", - "a) foo" - }, - - entry{ - 8, 1, ' ', 0, - "b) foo\tbar", // "bar" is not in any cell - not formatted, just flushed - "b) foobar" - }, - - entry{ - 8, 1, '.', 0, - "c) foo\tbar\t", - "c) foo..bar" - }, - - entry{ - 8, 1, '.', 0, - "d) foo\tbar\n", - "d) foo..bar\n" - }, - - entry{ - 8, 1, '.', 0, - "e) foo\tbar\t\n", - "e) foo..bar.....\n" - }, - - entry{ - 8, 1, '.', tabwriter.FilterHTML, - "f) f<o\tbar\t\n", - "f) f<o..bar.....\n" - }, - - entry{ - 8, 1, '*', 0, - "Hello, world!\n", - "Hello, world!\n" - }, - - entry{ - 0, 0, '.', 0, - "1\t2\t3\t4\n" - "11\t222\t3333\t44444\n", - - "1.2..3...4\n" - "11222333344444\n" - }, - - entry{ - 0, 0, '.', tabwriter.FilterHTML, - "1\t2\t3\t4\n" // \f inside HTML is ignored - "11\t222\t3333\t44444\n", - - "1.2..3...4\n" - "11222333344444\n" - }, - - entry{ - 0, 0, '.', 0, - "1\t2\t3\t4\f" // \f causes a newline and flush - "11\t222\t3333\t44444\n", - - "1234\n" - "11222333344444\n" - }, - - entry{ - 5, 0, '.', 0, - "1\t2\t3\t4\n", - "1....2....3....4\n" - }, - - entry{ - 5, 0, '.', 0, - "1\t2\t3\t4\t\n", - "1....2....3....4....\n" - }, - - entry{ - 8, 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" - }, - - entry{ - 8, 1, ' ', tabwriter.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" - }, - - entry{ - 2, 0, ' ', 0, - "a\tb\tc\n" - "aa\tbbb\tcccc\n" - "aaa\tbbbb\n", - - "a b c\n" - "aa bbbcccc\n" - "aaabbbb\n" - }, - - entry{ - 8, 1, '_', 0, - "a\tb\tc\n" - "aa\tbbb\tcccc\n" - "aaa\tbbbb\n", - - "a_______b_______c\n" - "aa______bbb_____cccc\n" - "aaa_____bbbb\n" - }, - - entry{ - 4, 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" - }, - - entry{ - 4, 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" - }, - - entry{ - 8, 1, '\t', tabwriter.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\t999999999\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\t999999999\t0000000000\n" - }, - - entry{ - 0, 2, ' ', tabwriter.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" - }, -} - - -func Test(t *testing.T) { - for _, e := range tests { - check(t, e.tabwidth, e.padding, e.padchar, e.flags, e.src, e.expected); - } -} diff --git a/src/lib/template/Makefile b/src/lib/template/Makefile deleted file mode 100644 index e91c08818..000000000 --- a/src/lib/template/Makefile +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m >Makefile - -D= - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - format.$O\ - -O2=\ - template.$O\ - - -phases: a1 a2 -_obj$D/template.a: phases - -a1: $(O1) - $(AR) grc _obj$D/template.a format.$O - rm -f $(O1) - -a2: $(O2) - $(AR) grc _obj$D/template.a template.$O - rm -f $(O2) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/template.a - -$(O1): newpkg -$(O2): a1 -$(O3): a2 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/template.a - -packages: _obj$D/template.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/template.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/template.a diff --git a/src/lib/template/format.go b/src/lib/template/format.go deleted file mode 100644 index 4fb5393b9..000000000 --- a/src/lib/template/format.go +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Template library: default formatters - -package template - -import ( - "fmt"; - "io"; - "reflect"; -) - -// 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, value interface{}, format string) { - fmt.Fprint(w, value); -} - - -var esc_amp = io.StringBytes("&") -var esc_lt = io.StringBytes("<") -var esc_gt = io.StringBytes(">") - -// HtmlEscape writes to w the properly escaped HTML equivalent -// of the plain text data s. -func HtmlEscape(w io.Writer, s []byte) { - last := 0; - for i, c := range s { - if c == '&' || c == '<' || c == '>' { - w.Write(s[last:i]); - switch c { - case '&': - w.Write(esc_amp); - case '<': - w.Write(esc_lt); - case '>': - w.Write(esc_gt); - } - last = i+1; - } - } - w.Write(s[last:len(s)]); -} - -// HtmlFormatter formats arbitrary values for HTML -func HtmlFormatter(w io.Writer, value interface{}, format string) { - var b io.ByteBuffer; - fmt.Fprint(&b, value); - HtmlEscape(w, b.Data()); -} diff --git a/src/lib/template/template.go b/src/lib/template/template.go deleted file mode 100644 index a5e9b0c7d..000000000 --- a/src/lib/template/template.go +++ /dev/null @@ -1,808 +0,0 @@ -// Copyright 2009 The Go 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. See - http://code.google.com/p/json-template/wiki/Reference - for full documentation of the template language. A summary: - - 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) 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. - - Major constructs ({} are metacharacters; [] marks optional elements): - - {# comment } - - A one-line comment. - - {.section field} XXX [ {.or} YYY ] {.end} - - Set @ to the value of the field. It may be an explicit @ - to stay at the same point in the data. If the field is nil - or empty, execute YYY; otherwise execute XXX. - - {.repeated section field} XXX [ {.alternates with} ZZZ ] [ {.or} YYY ] {.end} - - Like .section, but field must be an array or slice. XXX - is executed for each element. If the array is nil or empty, - YYY is executed instead. If the {.alternates with} marker - is present, ZZZ is executed between iterations of XXX. - - {field} - {field|formatter} - - Insert the value of the field into the output. Field is - first looked for in the cursor, as in .section and .repeated. - If it is not found, the search continues in outer sections - until the top level is reached. - - If a formatter is specified, it must be named in the formatter - map passed to the template set up routines or in the default - set ("html","str","") and is used to process the data for - output. The formatter function has signature - func(wr io.Write, data interface{}, formatter string) - where wr is the destination for output, data is the field - value, and formatter is its name at the invocation site. -*/ -package template - -import ( - "container/vector"; - "fmt"; - "io"; - "os"; - "reflect"; - "runtime"; - "strings"; - "template"; -) - -// 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, interface{}, string) - -// 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 to be evaluated -type variableElement struct { - linenum int; - name string; - formatter string; // TODO(r): implement pipelines -} - -// A .section block, possibly with a .or -type sectionElement struct { - linenum int; // of .section itself - field string; // cursor field for this block - start int; // first element - or int; // first element of .or block - end int; // one beyond last element -} - -// A .repeated block, possibly with a .or and a .alternates -type repeatedElement struct { - sectionElement; // It has the same structure... - altstart int; // ... except for alternates - altend int; -} - -// Template is the type that represents a template definition. -// It is unchanged after parsing. -type Template struct { - fmap FormatterMap; // formatters for variables - // Used during parsing: - ldelim, rdelim []byte; // delimiters; default {} - buf []byte; // input text to process - p int; // position in buf - linenum int; // position in input - errors chan os.Error; // for error reporting during parsing (only) - // 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 - errors chan os.Error; // for reporting errors during execute -} - -func (parent *state) clone(data reflect.Value) *state { - return &state{parent, data, parent.wr, parent.errors} -} - -// 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.errors = make(chan os.Error); - t.elems = vector.New(0); - return t; -} - -// Generic error handler, called only from execError or parseError. -func error(errors chan os.Error, line int, err string, args ...) { - errors <- &Error{line, fmt.Sprintf(err, args)}; - runtime.Goexit(); -} - -// Report error and stop executing. The line number must be provided explicitly. -func (t *Template) execError(st *state, line int, err string, args ...) { - error(st.errors, line, err, args); -} - -// Report error and stop parsing. The line number comes from the template state. -func (t *Template) parseError(err string, args ...) { - error(t.errors, t.linenum, err, args) -} - -// -- 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:len(s)]; - 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 the white space on -// either side, up to and including the newline. -func (t *Template) nextItem() []byte { - sawLeft := false; // are we waiting for an opening delimiter? - special := false; // is this a {.foo} directive, which means trim white space? - // Delete surrounding white space if this {.foo} is the only thing on the line. - trim_white := t.p == 0 || t.buf[t.p-1] == '\n'; - only_white := true; // we have seen only white space so far - var i int; - start := t.p; -Loop: - for i = t.p; i < len(t.buf); i++ { - switch { - case t.buf[i] == '\n': - t.linenum++; - i++; - break Loop; - case white(t.buf[i]): - // white space, do nothing - case !sawLeft && equal(t.buf, i, t.ldelim): // sawLeft checked because delims may be equal - // anything interesting already on the line? - if !only_white { - break Loop; - } - // is it a directive or comment? - j := i + len(t.ldelim); // position after delimiter - if j+1 < len(t.buf) && (t.buf[j] == '.' || t.buf[j] == '#') { - special = true; - if trim_white && only_white { - start = i; - } - } else if i > t.p { // have some text accumulated so stop before delimiter - break Loop; - } - sawLeft = true; - i = j - 1; - case equal(t.buf, i, t.rdelim): - if !sawLeft { - t.parseError("unmatched closing delimiter") - } - sawLeft = false; - i += len(t.rdelim); - break Loop; - default: - only_white = false; - } - } - if sawLeft { - t.parseError("unmatched opening delimiter") - } - item := t.buf[start:i]; - if special && trim_white { - // consume trailing white space - for ; i < len(t.buf) && white(t.buf[i]); i++ { - if t.buf[i] == '\n' { - i++; - break // stop after newline - } - } - } - 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 - } - if i == cap(s) { - ns := make([]string, 2*cap(s)); - for j := range s { - ns[j] = s[j] - } - s = ns; - } - s = s[0:i+1]; - s[i] = string(buf[start:p]) - } - 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 - } - if len(item) <= len(t.ldelim)+len(t.rdelim) { // no contents - t.parseError("empty directive") - } - // 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") - } - if len(w) == 1 && 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) - } - tok = tokSection; - return; - case ".repeated": - if len(w) != 3 || w[1] != "section" { - t.parseError("incorrect fields for .repeated: %s", item) - } - tok = tokRepeated; - return; - case ".alternates": - if len(w) != 2 || w[1] != "with" { - t.parseError("incorrect fields for .alternates: %s", item) - } - tok = tokAlternates; - return; - } - t.parseError("bad directive: %s", item); - return -} - -// -- Parsing - -// Allocate a new variable-evaluation element. -func (t *Template) newVariable(name_formatter string) (v *variableElement) { - name := name_formatter; - formatter := ""; - bar := strings.Index(name_formatter, "|"); - if bar >= 0 { - name = name_formatter[0:bar]; - formatter = name_formatter[bar+1:len(name_formatter)]; - } - // Probably ok, so let's build it. - v = &variableElement{t.linenum, name, formatter}; - - // We could remember the function address here and avoid the lookup later, - // but it's more dynamic to let the user change the map contents underfoot. - // We do require the name to be present, though. - - // Is it in user-supplied map? - if t.fmap != nil { - if fn, ok := t.fmap[formatter]; ok { - return - } - } - // Is it in builtin map? - if fn, ok := builtins[formatter]; ok { - return - } - t.parseError("unknown formatter: %s", formatter); - return -} - -// Grab the next item. If it's simple, just append it to the template. -// Otherwise return its details. -func (t *Template) parseSimple(item []byte) (done bool, tok int, w []string) { - tok, w = t.analyze(item); - done = true; // assume for simplicity - switch tok { - case tokComment: - return; - case tokText: - t.elems.Push(&textElement{item}); - return; - case tokLiteral: - switch w[0] { - case ".meta-left": - t.elems.Push(&literalElement{t.ldelim}); - case ".meta-right": - t.elems.Push(&literalElement{t.rdelim}); - case ".space": - t.elems.Push(&literalElement{space}); - case ".tab": - t.elems.Push(&literalElement{tab}); - default: - t.parseError("internal error: unknown literal: %s", w[0]); - } - return; - case tokVariable: - t.elems.Push(t.newVariable(w[0])); - return; - } - return false, tok, w -} - -// parseSection and parseRepeated are mutually recursive -func (t *Template) parseSection(words []string) *sectionElement - -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") - } - 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"); - } - 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"); - } - if r.or >= 0 { - t.parseError(".alternates inside .or block in .repeated section"); - } - r.altstart = t.elems.Len(); - default: - t.parseError("internal error: unknown repeated section item: %s", item); - } - } - 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") - } - 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"); - } - 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 - -// If the data for this template is a struct, find the named variable. -// The special name "@" (the "cursor") denotes the current data. -func (st *state) findVar(s string) reflect.Value { - if s == "@" { - return st.data - } - data := reflect.Indirect(st.data); - typ, ok := data.Type().(reflect.StructType); - if ok { - for i := 0; i < typ.Len(); i++ { - name, ftyp, tag, offset := typ.Field(i); - if name == s { - return data.(reflect.StructValue).Field(i) - } - } - } - return nil -} - -// Is there no data to look at? -func empty(v reflect.Value, indirect_ok bool) bool { - v = reflect.Indirect(v); - if v == nil { - return true - } - switch v.Type().Kind() { - case reflect.StringKind: - return v.(reflect.StringValue).Get() == ""; - case reflect.StructKind: - return false; - case reflect.ArrayKind: - return v.(reflect.ArrayValue).Len() == 0; - } - return true; -} - -// Look up a variable, up through the parent if necessary. -func (t *Template) varValue(v *variableElement, st *state) reflect.Value { - field := st.findVar(v.name); - if field == nil { - if st.parent == nil { - t.execError(st, t.linenum, "name not found: %s", v.name) - } - return t.varValue(v, st.parent); - } - return field; -} - -// Evaluate a variable, looking up through the parent if necessary. -// If it has a formatter attached ({var|formatter}) run that too. -func (t *Template) writeVariable(v *variableElement, st *state) { - formatter := v.formatter; - val := t.varValue(v, st).Interface(); - // is it in user-supplied map? - if t.fmap != nil { - if fn, ok := t.fmap[v.formatter]; ok { - fn(st.wr, val, v.formatter); - return; - } - } - // is it in builtin map? - if fn, ok := builtins[v.formatter]; ok { - fn(st.wr, val, v.formatter); - return; - } - t.execError(st, v.linenum, "missing formatter %s for variable %s", v.formatter, v.name) -} - -// execute{|Element|Section|Repeated} are mutually recursive -func (t *Template) executeSection(s *sectionElement, st *state) -func (t *Template) executeRepeated(r *repeatedElement, st *state) - -// 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 := st.findVar(s.field); - if field == nil { - t.execError(st, s.linenum, ".section: cannot find field %s in %s", s.field, reflect.Indirect(st.data).Type()); - } - st = st.clone(field); - start, end := s.start, s.or; - if !empty(field, true) { - // 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) - } -} - -// 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 := st.findVar(r.field); - if field == nil { - t.execError(st, r.linenum, ".repeated: cannot find field %s in %s", r.field, reflect.Indirect(st.data).Type()); - } - field = reflect.Indirect(field); - - // Must be an array/slice - if field != nil && field.Kind() != reflect.ArrayKind { - t.execError(st, r.linenum, ".repeated: %s has bad type %s", r.field, field.Type()); - } - if empty(field, true) { - // 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 - } - // Execute the normal block. - start, end := r.start, r.or; - if end < 0 { - end = r.end - } - if r.altstart >= 0 { - end = r.altstart - } - if field != nil { - array := field.(reflect.ArrayValue); - for j := 0; j < array.Len(); j++ { - newst := st.clone(array.Elem(j)); - for i := start; i < end; { - i = t.executeElement(i, newst) - } - // If appropriate, do .alternates between elements - if j < array.Len() - 1 && r.altstart >= 0 { - for i := r.altstart; i < r.altend; i++ { - i = t.executeElement(i, newst) - } - } - } - } -} - -// A valid delimiter must contain no white space and be non-empty. -func validDelim(d []byte) bool { - if len(d) == 0 { - return false - } - for i, c := range d { - if white(c) { - return false - } - } - return true; -} - -// -- 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) os.Error { - if !validDelim(t.ldelim) || !validDelim(t.rdelim) { - return &Error{1, fmt.Sprintf("bad delimiter strings %q %q", t.ldelim, t.rdelim)} - } - t.buf = io.StringBytes(s); - t.p = 0; - t.linenum = 0; - go func() { - t.parse(); - t.errors <- nil; // clean return; - }(); - return <-t.errors; -} - -// Execute applies a parsed template to the specified data object, -// generating output to wr. -func (t *Template) Execute(data interface{}, wr io.Writer) os.Error { - // Extract the driver data. - val := reflect.NewValue(data); - errors := make(chan os.Error); - go func() { - t.p = 0; - t.execute(0, t.elems.Len(), &state{nil, val, wr, errors}); - errors <- nil; // clean return; - }(); - return <-errors; -} - -// 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 = io.StringBytes(left); - t.rdelim = io.StringBytes(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); - return -} diff --git a/src/lib/template/template_test.go b/src/lib/template/template_test.go deleted file mode 100644 index 9a81d274c..000000000 --- a/src/lib/template/template_test.go +++ /dev/null @@ -1,331 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package template - -import ( - "fmt"; - "io"; - "os"; - "reflect"; - "template"; - "testing"; -) - -type Test struct { - in, out string -} - -type T struct { - item string; - value string; -} - -type S struct { - header string; - integer int; - raw string; - data []T; - pdata []*T; - empty []*T; - emptystring string; - null []*T; -} - -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, interface{}, string)) { - return func(w io.Writer, v interface{}, format string) { - io.WriteString(w, f(v)); - } -} - - -var formatters = FormatterMap { - "uppercase" : writer(uppercase), - "+1" : writer(plus1), -} - -var tests = []*Test { - // Simple - &Test{ "", "" }, - &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", "" }, - - // Variables at top level - &Test{ - "{header}={integer}\n", - - "Header=77\n" - }, - - // Section - &Test{ - "{.section data }\n" - "some text for the section\n" - "{.end}\n", - - "some text for the section\n" - }, - &Test{ - "{.section data }\n" - "{header}={integer}\n" - "{.end}\n", - - "Header=77\n" - }, - &Test{ - "{.section pdata }\n" - "{header}={integer}\n" - "{.end}\n", - - "Header=77\n" - }, - &Test{ - "{.section pdata }\n" - "data present\n" - "{.or}\n" - "data not present\n" - "{.end}\n", - - "data present\n" - }, - &Test{ - "{.section empty }\n" - "data present\n" - "{.or}\n" - "data not present\n" - "{.end}\n", - - "data not present\n" - }, - &Test{ - "{.section null }\n" - "data present\n" - "{.or}\n" - "data not present\n" - "{.end}\n", - - "data not present\n" - }, - &Test{ - "{.section pdata }\n" - "{header}={integer}\n" - "{.section @ }\n" - "{header}={integer}\n" - "{.end}\n" - "{.end}\n", - - "Header=77\n" - "Header=77\n" - }, - &Test{ - "{.section data}{.end} {header}\n", - - " Header\n" - }, - - // Repeated - &Test{ - "{.section pdata }\n" - "{.repeated section @ }\n" - "{item}={value}\n" - "{.end}\n" - "{.end}\n", - - "ItemNumber1=ValueNumber1\n" - "ItemNumber2=ValueNumber2\n" - }, - &Test{ - "{.section pdata }\n" - "{.repeated section @ }\n" - "{item}={value}\n" - "{.or}\n" - "this should not appear\n" - "{.end}\n" - "{.end}\n", - - "ItemNumber1=ValueNumber1\n" - "ItemNumber2=ValueNumber2\n" - }, - &Test{ - "{.section @ }\n" - "{.repeated section empty }\n" - "{item}={value}\n" - "{.or}\n" - "this should appear: empty field\n" - "{.end}\n" - "{.end}\n", - - "this should appear: empty field\n" - }, - &Test{ - "{.section pdata }\n" - "{.repeated section @ }\n" - "{item}={value}\n" - "{.alternates with}DIVIDER\n" - "{.or}\n" - "this should not appear\n" - "{.end}\n" - "{.end}\n", - - "ItemNumber1=ValueNumber1\n" - "DIVIDER\n" - "ItemNumber2=ValueNumber2\n" - }, - - // Formatters - &Test{ - "{.section pdata }\n" - "{header|uppercase}={integer|+1}\n" - "{header|html}={integer|str}\n" - "{.end}\n", - - "HEADER=78\n" - "Header=77\n" - }, - - &Test{ - "{raw}\n" - "{raw|html}\n", - - "&<>!@ #$%^\n" - "&<>!@ #$%^\n" - }, - - &Test{ - "{.section emptystring}emptystring{.end}\n" - "{.section header}header{.end}\n", - - "\nheader\n" - }, -} - -func TestAll(t *testing.T) { - s := new(S); - // initialized by hand for clarity. - s.header = "Header"; - s.integer = 77; - s.raw = "&<>!@ #$%^"; - s.data = []T{ t1, t2 }; - s.pdata = []*T{ &t1, &t2 }; - s.empty = []*T{ }; - s.null = nil; - - var buf io.ByteBuffer; - for i, test := range tests { - buf.Reset(); - tmpl, err := Parse(test.in, formatters); - if err != nil { - t.Error("unexpected parse error:", err); - continue; - } - err = tmpl.Execute(s, &buf); - if err != nil { - t.Error("unexpected execute error:", err) - } - if string(buf.Data()) != test.out { - t.Errorf("for %q: expected %q got %q", test.in, test.out, string(buf.Data())); - } - } -} - -func TestStringDriverType(t *testing.T) { - tmpl, err := Parse("template: {@}", nil); - if err != nil { - t.Error("unexpected parse error:", err) - } - var b io.ByteBuffer; - err = tmpl.Execute("hello", &b); - if err != nil { - t.Error("unexpected execute error:", err) - } - s := string(b.Data()); - if s != "template: hello" { - t.Errorf("failed passing string as data: expected %q got %q", "template: hello", s) - } -} - -func TestTwice(t *testing.T) { - tmpl, err := Parse("template: {@}", nil); - if err != nil { - t.Error("unexpected parse error:", err) - } - var b io.ByteBuffer; - err = tmpl.Execute("hello", &b); - if err != nil { - t.Error("unexpected parse error:", err) - } - s := string(b.Data()); - text := "template: hello"; - if s != text { - t.Errorf("failed passing string as data: expected %q got %q", text, s); - } - err = tmpl.Execute("hello", &b); - if err != nil { - t.Error("unexpected parse error:", err) - } - s = string(b.Data()); - text += text; - if s != text { - t.Errorf("failed passing string as data: expected %q got %q", text, s); - } -} - -func TestCustomDelims(t *testing.T) { - // try various lengths. zero should catch error. - for i := 0; i < 7; i++ { - for j := 0; j < 7; j++ { - tmpl := New(nil); - // first two chars deliberately the same to test equal left and right delims - ldelim := "$!#$%^&"[0:i]; - rdelim := "$*&^%$!"[0:j]; - tmpl.SetDelims(ldelim, rdelim); - // if braces, this would be template: {@}{.meta-left}{.meta-right} - text := "template: " + - ldelim + "@" + rdelim + - ldelim + ".meta-left" + rdelim + - ldelim + ".meta-right" + rdelim; - err := tmpl.Parse(text); - if err != nil { - if i == 0 || j == 0 { // expected - continue - } - t.Error("unexpected parse error:", err) - } else if i == 0 || j == 0 { - t.Errorf("expected parse error for empty delimiter: %d %d %q %q", i, j, ldelim, rdelim); - continue; - } - var b io.ByteBuffer; - err = tmpl.Execute("hello", &b); - s := string(b.Data()); - if s != "template: hello" + ldelim + rdelim { - t.Errorf("failed delim check(%q %q) %q got %q", ldelim, rdelim, text, s) - } - } - } -} diff --git a/src/lib/testing/Makefile b/src/lib/testing/Makefile deleted file mode 100644 index 493eba6f2..000000000 --- a/src/lib/testing/Makefile +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m >Makefile - -D= - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - testing.$O\ - - -phases: a1 -_obj$D/testing.a: phases - -a1: $(O1) - $(AR) grc _obj$D/testing.a testing.$O - rm -f $(O1) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/testing.a - -$(O1): newpkg -$(O2): a1 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/testing.a - -packages: _obj$D/testing.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/testing.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/testing.a diff --git a/src/lib/testing/iotest/Makefile b/src/lib/testing/iotest/Makefile deleted file mode 100644 index 1d01041f5..000000000 --- a/src/lib/testing/iotest/Makefile +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m >Makefile - -D=/testing/ - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - logger.$O\ - reader.$O\ - - -phases: a1 -_obj$D/iotest.a: phases - -a1: $(O1) - $(AR) grc _obj$D/iotest.a logger.$O reader.$O - rm -f $(O1) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/iotest.a - -$(O1): newpkg -$(O2): a1 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/iotest.a - -packages: _obj$D/iotest.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/iotest.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/iotest.a diff --git a/src/lib/testing/iotest/logger.go b/src/lib/testing/iotest/logger.go deleted file mode 100644 index 8ee574080..000000000 --- a/src/lib/testing/iotest/logger.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2009 The Go Authors. 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.Stdoutf("%s %x: %v", l.prefix, p[0:n], err); - } else { - log.Stdoutf("%s %x", l.prefix, p[0:n]); - } - return; -} - -// NewWriteLogger returns a writer that behaves like w except -// that it logs (using log.Stdout) each write to standard output, -// 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.Stdoutf("%s %x: %v", l.prefix, p[0:n], err); - } else { - log.Stdoutf("%s %x", l.prefix, p[0:n]); - } - return; -} - -// NewReadLogger returns a writer that behaves like w except -// that it logs (using log.Stdout) each write to standard output, -// 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/lib/testing/iotest/reader.go b/src/lib/testing/iotest/reader.go deleted file mode 100644 index 0bb863338..000000000 --- a/src/lib/testing/iotest/reader.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// The iotest package implements Readers and Writers -// useful only for testing. -package iotest - -import ( - "io"; - "os"; -) - -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]); -} - -// 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 halfReader struct { - r io.Reader; -} - -func (r *halfReader) Read(p []byte) (int, os.Error) { - return r.r.Read(p[0:(len(p)+1)/2]); -} - -// 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}; -} - diff --git a/src/lib/testing/testing.go b/src/lib/testing/testing.go deleted file mode 100644 index 330fadd3a..000000000 --- a/src/lib/testing/testing.go +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// The testing package provides support for automated testing of Go packages. -// It is intended to be used in concert with the ``gotest'' utility, which automates -// execution of any function of the form -// func TestXxx(*testing.T) -// where Xxx can by 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. -package testing - -import ( - "flag"; - "fmt"; - "os"; - "regexp"; - "runtime"; -) - -// Report as tests are run; default is silent for success. -var chatty = flag.Bool("v", false, "verbose: print additional output") -var match = flag.String("match", "", "regular expression to select tests to run") - - -// Insert final newline if needed and tabs after internal newlines. -func tabify(s string) string { - n := len(s); - if n > 0 && s[n-1] != '\n' { - s += "\n"; - n++; - } - for i := 0; i < n - 1; i++ { // -1 to avoid final newline - if s[i] == '\n' { - return s[0:i+1] + "\t" + tabify(s[i+1:n]); - } - } - return s -} - -// T is a type passed to Test functions to manage test state and support formatted test logs. -// Logs are accumulated during execution and dumped to standard error when done. -type T struct { - errors string; - failed bool; - ch chan *T; -} - -// Fail marks the Test function as having failed but continues execution. -func (t *T) Fail() { - t.failed = true -} - -// Failed returns whether the Test function has failed. -func (t *T) Failed() bool { - return t.failed -} - -// FailNow marks the Test function as having failed and stops its execution. -// Execution will continue at the next Test. -func (t *T) FailNow() { - t.Fail(); - t.ch <- t; - runtime.Goexit(); -} - -// Log formats its arguments using default formatting, analogous to Print(), -// and records the text in the error log. -func (t *T) Log(args ...) { - t.errors += "\t" + tabify(fmt.Sprintln(args)); -} - -// Log formats its arguments according to the format, analogous to Printf(), -// and records the text in the error log. -func (t *T) Logf(format string, args ...) { - t.errors += "\t" + tabify(fmt.Sprintf(format, args)); -} - -// Error is equivalent to Log() followed by Fail(). -func (t *T) Error(args ...) { - t.Log(args); - t.Fail(); -} - -// Errorf is equivalent to Logf() followed by Fail(). -func (t *T) Errorf(format string, args ...) { - t.Logf(format, args); - t.Fail(); -} - -// Fatal is equivalent to Log() followed by FailNow(). -func (t *T) Fatal(args ...) { - t.Log(args); - t.FailNow(); -} - -// Fatalf is equivalent to Logf() followed by FailNow(). -func (t *T) Fatalf(format string, args ...) { - t.Logf(format, args); - t.FailNow(); -} - -// An internal type but exported because it is cross-package; part of the implementation -// of gotest. -type Test struct { - Name string; - F func(*T); -} - -func tRunner(t *T, test *Test) { - test.F(t); - t.ch <- t; -} - -// An internal function but exported because it is cross-package; part of the implementation -// of gotest. -func Main(tests []Test) { - flag.Parse(); - args := flag.Args(); - ok := true; - if len(tests) == 0 { - println("testing: warning: no tests to run"); - } - re, err := regexp.Compile(*match); - if err != nil { - println("invalid regexp for -match:", err.String()); - os.Exit(1); - } - for i := 0; i < len(tests); i++ { - if !re.Match(tests[i].Name) { - continue; - } - if *chatty { - println("=== RUN ", tests[i].Name); - } - t := new(T); - t.ch = make(chan *T); - go tRunner(t, &tests[i]); - <-t.ch; - if t.failed { - println("--- FAIL:", tests[i].Name); - print(t.errors); - ok = false; - } else if *chatty { - println("--- PASS:", tests[i].Name); - print(t.errors); - } - } - if !ok { - println("FAIL"); - os.Exit(1); - } - println("PASS"); -} diff --git a/src/lib/time/Makefile b/src/lib/time/Makefile deleted file mode 100644 index 8d3c3b65f..000000000 --- a/src/lib/time/Makefile +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m >Makefile - -D= - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - sleep.$O\ - zoneinfo.$O\ - -O2=\ - time.$O\ - -O3=\ - tick.$O\ - - -phases: a1 a2 a3 -_obj$D/time.a: phases - -a1: $(O1) - $(AR) grc _obj$D/time.a sleep.$O zoneinfo.$O - rm -f $(O1) - -a2: $(O2) - $(AR) grc _obj$D/time.a time.$O - rm -f $(O2) - -a3: $(O3) - $(AR) grc _obj$D/time.a tick.$O - rm -f $(O3) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/time.a - -$(O1): newpkg -$(O2): a1 -$(O3): a2 -$(O4): a3 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/time.a - -packages: _obj$D/time.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/time.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/time.a diff --git a/src/lib/time/sleep.go b/src/lib/time/sleep.go deleted file mode 100644 index 3bb76cf47..000000000 --- a/src/lib/time/sleep.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package time - -import ( - "os"; - "syscall"; - "unsafe"; -) - -// Sleep pauses the current goroutine for ns nanoseconds. -// It returns os.EINTR if interrupted. -func Sleep(ns int64) os.Error { - return os.ErrnoToError(syscall.Sleep(ns)); -} diff --git a/src/lib/time/tick.go b/src/lib/time/tick.go deleted file mode 100644 index 53e2234f8..000000000 --- a/src/lib/time/tick.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2009 The Go Authors. 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"; - "time"; - "unsafe"; -) - -// TODO(rsc): This implementation of time.Tick is a -// simple placeholder. Eventually, there will need to be -// a single central time server no matter how many tickers -// are active. There also needs to be a way to cancel a ticker. -// -// Also, if timeouts become part of the select statement, -// perhaps the Ticker is just: -// -// func Ticker(ns int64, c chan int64) { -// for { -// select { timeout ns: } -// nsec, err := time.Nanoseconds(); -// c <- nsec; -// } - -func ticker(ns int64, c chan int64) { - var tv syscall.Timeval; - now := time.Nanoseconds(); - when := now; - for { - when += ns; // next alarm - - // if c <- now took too long, skip ahead - if when < now { - // one big step - when += (now-when)/ns * ns; - } - for when <= now { - // little steps until when > now - when += ns - } - - time.Sleep(when - now); - now = time.Nanoseconds(); - c <- now; - } -} - -// Tick creates a synchronous 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. -func Tick(ns int64) chan int64 { - if ns <= 0 { - return nil - } - c := make(chan int64); - go ticker(ns, c); - return c; -} - diff --git a/src/lib/time/tick_test.go b/src/lib/time/tick_test.go deleted file mode 100644 index 0667be679..000000000 --- a/src/lib/time/tick_test.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2009 The Go Authors. 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 ( - "testing"; - "time"; -) - -func TestTick(t *testing.T) { - const ( - Delta = 100*1e6; - Count = 10; - ); - c := Tick(Delta); - t0 := Nanoseconds(); - for i := 0; i < Count; i++ { - <-c; - } - 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)); - } -} diff --git a/src/lib/time/time.go b/src/lib/time/time.go deleted file mode 100644 index ea9b66cbc..000000000 --- a/src/lib/time/time.go +++ /dev/null @@ -1,372 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// The time package provides functionality for measuring and -// displaying time. -package time - -import ( - "os"; - "time" -) - -// Seconds reports the number of seconds since the Unix epoch, -// January 1, 1970 00:00:00 UTC. -func Seconds() int64 { - sec, nsec, err := os.Time(); - if err != nil { - panic("time: os.Time: ", err.String()); - } - 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("time: os.Time: ", err.String()); - } - return sec*1e9 + nsec -} - -// Days of the week. -const ( - Sunday = iota; - Monday; - Tuesday; - Wednesday; - Thursday; - Friday; - Saturday; -) - -// Time is the struct representing a parsed time value. -type Time struct { - Year int64; // 2008 is 2008 - Month, Day int; // Sep-17 is 9, 17 - Hour, Minute, Second int; // 10:43:12 is 10, 43, 12 - Weekday int; // Sunday, Monday, ... - ZoneOffset int; // seconds west of UTC - Zone string; -} - -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; - } else { - // Cut off 400 year cycles. - n := day/daysPer400Years; - year += 400*n; - day -= daysPer400Years*n; - } - - // Cut off 100-year cycles - n := day/daysPer100Years; - year += 100*n; - day -= daysPer100Years*n; - - // Cut off 4-year cycles - n = day/daysPer4Years; - year += 4*n; - day -= daysPer4Years*n; - - // Cut off non-leap years. - n = day/365; - year += n; - day -= 365*n; - - t.Year = year; - - // If someone ever needs yearday, - // tyearday = day (+1?) - - months := months(year); - var m int; - yday := int(day); - for m = 0; m < 12 && yday >= months[m]; m++ { - yday -= months[m] - } - t.Month = m+1; - t.Day = yday+1; - t.Zone = "UTC"; - - return t; -} - -// UTC returns the current time as a parsed Time value in the UTC time zone. -func UTC() *Time { - return SecondsToUTC(Seconds()) -} - -// SecondsToLocalTime converts sec, in number of seconds since the Unix epoch, -// into a parsed Time value in the local time zone. -func SecondsToLocalTime(sec int64) *Time { - z, offset, err := time.lookupTimezone(sec); - if err != nil { - return SecondsToUTC(sec) - } - t := SecondsToUTC(sec+int64(offset)); - t.Zone = z; - t.ZoneOffset = offset; - return t -} - -// LocalTime returns the current time as a parsed Time value in the local time zone. -func LocalTime() *Time { - return SecondsToLocalTime(Seconds()) -} - -// Seconds returns the number of seconds since January 1, 1970 represented by the -// parsed Time value. -func (t *Time) Seconds() int64 { - // First, accumulate days since January 1, 2001. - // Using 2001 instead of 1970 makes the leap-year - // handling easier (see SecondsToUTC), because - // it is at the beginning of the 4-, 100-, and 400-year cycles. - day := int64(0); - - // Rewrite year to be >= 2001. - year := t.Year; - if year < 2001 { - n := (2001 - year)/400 + 1; - year += 400*n; - day -= daysPer400Years*n; - } - - // Add in days from 400-year cycles. - n := (year - 2001) / 400; - year -= 400*n; - day += daysPer400Years*n; - - // Add in 100-year cycles. - n = (year - 2001) / 100; - year -= 100*n; - day += daysPer100Years*n; - - // Add in 4-year cycles. - n = (year - 2001) / 4; - year -= 4*n; - day += daysPer4Years*n; - - // Add in non-leap years. - n = year - 2001; - day += 365*n; - - // Add in days this year. - months := months(t.Year); - for m := 0; m < t.Month-1; m++ { - day += int64(months[m]) - } - day += int64(t.Day - 1); - - // Convert days to seconds since January 1, 2001. - sec := day * secondsPerDay; - - // Add in time elapsed today. - sec += int64(t.Hour) * 3600; - sec += int64(t.Minute) * 60; - sec += int64(t.Second); - - // Convert from seconds since 2001 to seconds since 1970. - sec += days1970To2001 * secondsPerDay; - - // Account for local time zone. - sec -= int64(t.ZoneOffset); - return sec -} - -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" -} - -func copy(dst []byte, s string) { - for i := 0; i < len(s); i++ { - dst[i] = s[i] - } -} - -func decimal(dst []byte, n int) { - if n < 0 { - n = 0 - } - for i := len(dst)-1; i >= 0; i-- { - dst[i] = byte(n%10 + '0'); - n /= 10 - } -} - -func addString(buf []byte, bp int, s string) int { - n := len(s); - copy(buf[bp:bp+n], s); - return bp+n -} - -// Just enough of strftime to implement the date formats below. -// Not exported. -func format(t *Time, fmt string) string { - buf := make([]byte, 128); - bp := 0; - - for i := 0; i < len(fmt); i++ { - if fmt[i] == '%' { - i++; - switch fmt[i] { - case 'A': // %A full weekday name - bp = addString(buf, bp, longDayNames[t.Weekday]); - case 'a': // %a abbreviated weekday name - bp = addString(buf, bp, shortDayNames[t.Weekday]); - case 'b': // %b abbreviated month name - bp = addString(buf, bp, shortMonthNames[t.Month-1]); - case 'd': // %d day of month (01-31) - decimal(buf[bp:bp+2], t.Day); - bp += 2; - case 'e': // %e day of month ( 1-31) - if t.Day >= 10 { - decimal(buf[bp:bp+2], t.Day) - } else { - buf[bp] = ' '; - buf[bp+1] = byte(t.Day + '0') - } - bp += 2; - case 'H': // %H hour 00-23 - decimal(buf[bp:bp+2], t.Hour); - bp += 2; - case 'M': // %M minute 00-59 - decimal(buf[bp:bp+2], t.Minute); - bp += 2; - case 'S': // %S second 00-59 - decimal(buf[bp:bp+2], t.Second); - bp += 2; - case 'Y': // %Y year 2008 - decimal(buf[bp:bp+4], int(t.Year)); - bp += 4; - case 'y': // %y year 08 - decimal(buf[bp:bp+2], int(t.Year%100)); - bp += 2; - case 'Z': - bp = addString(buf, bp, t.Zone); - default: - buf[bp] = '%'; - buf[bp+1] = fmt[i]; - bp += 2 - } - } else { - buf[bp] = fmt[i]; - bp++; - } - } - return string(buf[0:bp]) -} - -// Asctime formats the parsed time value in the style of -// ANSI C asctime: Sun Nov 6 08:49:37 1994 -func (t *Time) Asctime() string { - return format(t, "%a %b %e %H:%M:%S %Y") -} - -// RFC850 formats the parsed time value in the style of -// RFC 850: Sunday, 06-Nov-94 08:49:37 UTC -func (t *Time) RFC850() string { - return format(t, "%A, %d-%b-%y %H:%M:%S %Z") -} - -// RFC1123 formats the parsed time value in the style of -// RFC 1123: Sun, 06 Nov 1994 08:49:37 UTC -func (t *Time) RFC1123() string { - return format(t, "%a, %d %b %Y %H:%M:%S %Z") -} - -// String formats the parsed time value in the style of -// date(1) - Sun Nov 6 08:49:37 UTC 1994 -func (t *Time) String() string { - return format(t, "%a %b %e %H:%M:%S %Z %Y") -} diff --git a/src/lib/time/time_test.go b/src/lib/time/time_test.go deleted file mode 100644 index 41e6736e8..000000000 --- a/src/lib/time/time_test.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package time - -import ( - "os"; - "testing"; - "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", "US/Pacific"); -} - -type TimeTest struct { - seconds int64; - golden Time; -} - -var utctests = []TimeTest { - TimeTest{0, Time{1970, 1, 1, 0, 0, 0, Thursday, 0, "UTC"}}, - TimeTest{1221681866, Time{2008, 9, 17, 20, 4, 26, Wednesday, 0, "UTC"}}, - TimeTest{-1221681866, Time{1931, 4, 16, 3, 55, 34, Thursday, 0, "UTC"}}, - TimeTest{1e18, Time{31688740476, 10, 23, 1, 46, 40, Friday, 0, "UTC"}}, - TimeTest{-1e18, Time{-31688736537, 3, 10, 22, 13, 20, Tuesday, 0, "UTC"}}, - TimeTest{0x7fffffffffffffff, Time{292277026596, 12, 4, 15, 30, 7, Sunday, 0, "UTC"}}, - TimeTest{-0x8000000000000000, Time{-292277022657, 1, 27, 8, 29, 52, Sunday, 0, "UTC"}} -} - -var localtests = []TimeTest { - TimeTest{0, Time{1969, 12, 31, 16, 0, 0, Wednesday, -8*60*60, "PST"}}, - TimeTest{1221681866, Time{2008, 9, 17, 13, 4, 26, Wednesday, -7*60*60, "PDT"}} -} - -func same(t, u *Time) bool { - return t.Year == u.Year - && t.Month == u.Month - && t.Day == u.Day - && t.Hour == u.Hour - && t.Minute == u.Minute - && t.Second == u.Second - && t.Weekday == u.Weekday - && t.ZoneOffset == u.ZoneOffset - && t.Zone == u.Zone -} - -func TestSecondsToUTC(t *testing.T) { - for i := 0; i < len(utctests); i++ { - sec := utctests[i].seconds; - golden := &utctests[i].golden; - tm := SecondsToUTC(sec); - newsec := tm.Seconds(); - if newsec != sec { - t.Errorf("SecondsToUTC(%d).Seconds() = %d", sec, newsec); - } - if !same(tm, golden) { - t.Errorf("SecondsToUTC(%d):", sec); - t.Errorf(" want=%v", *golden); - t.Errorf(" have=%v", *tm); - } - } -} - -func TestSecondsToLocalTime(t *testing.T) { - for i := 0; i < len(localtests); i++ { - sec := localtests[i].seconds; - golden := &localtests[i].golden; - tm := SecondsToLocalTime(sec); - newsec := tm.Seconds(); - if newsec != sec { - t.Errorf("SecondsToLocalTime(%d).Seconds() = %d", sec, newsec); - } - if !same(tm, golden) { - t.Errorf("SecondsToLocalTime(%d):", sec); - t.Errorf(" want=%v", *golden); - t.Errorf(" have=%v", *tm); - } - } -} - diff --git a/src/lib/time/zoneinfo.go b/src/lib/time/zoneinfo.go deleted file mode 100644 index 751afc931..000000000 --- a/src/lib/time/zoneinfo.go +++ /dev/null @@ -1,285 +0,0 @@ -// Copyright 2009 The Go 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"; - "once"; - "os" -) - -const ( - maxFileSize = 8192; // actual files are closer to 1K - headerSize = 4+16+4*7; - - zoneDir = "/usr/share/zoneinfo/"; -) - -// Errors that can be generated recovering time zone information. -type TimeZoneError struct { - os.ErrorString -} - -var errShort = TimeZoneError{ "time: short zone file" } -var errInvalid = TimeZoneError{ "time: invalid zone file" } -var errLong = TimeZoneError{ "time: zone file too long" } - -// 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:len(d.p)]; - return p -} - -func (d *data) big4() (n uint32, ok bool) { - p := d.read(4); - if len(p) < 4 { - d.error = true; - return 0, false - } - return uint32(p[0]) << 24 | uint32(p[1]) << 16 | uint32(p[2]) << 8 | uint32(p[3]), true -} - -func (d *data) byte() (n byte, ok bool) { - p := d.read(1); - if len(p) < 1 { - d.error = true; - return 0, false - } - return p[0], true -} - - -// Make a string by stopping at the first NUL -func byteString(p []byte) string { - for i := 0; i < len(p); i++ { - if p[i] == 0 { - return string(p[0:i]) - } - } - return string(p) -} - -// Parsed representation -type zone struct { - utcoff int; - isdst bool; - name string; -} - -type zonetime struct { - time int32; // transition time, in seconds since 1970 GMT - zone *zone; // the zone that goes into effect at that time - isstd, isutc bool; // ignored - no idea what these mean -} - -func parseinfo(bytes []byte) (zt []zonetime, err os.Error) { - d := data{bytes, false}; - - // 4-byte magic "TZif" - if magic := d.read(4); string(magic) != "TZif" { - return nil, TimeZoneError{ "time: bad zone magic" } - } - - // 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, TimeZoneError { "time: bad zone file version" } - } - vers := p[0]; - - // 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, errShort - } - 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 - leapdata := data{d.read(n[NLeap]*8), false}; - - // 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, errShort - } - - // 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, errShort - } - z[i].utcoff = int(n); - var b byte; - if b, ok = zonedata.byte(); !ok { - return nil, errShort - } - z[i].isdst = b != 0; - if b, ok = zonedata.byte(); !ok || int(b) >= len(abbrev) { - return nil, errInvalid - } - z[i].name = byteString(abbrev[b:len(abbrev)]) - } - - // 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, errShort - } - zt[i].time = int32(n); - if int(txzones[i]) >= len(z) { - return nil, errInvalid - } - 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, nil -} - -func readfile(name string, max int) (p []byte, err os.Error) { - f, e := os.Open(name, os.O_RDONLY, 0); - if e != nil { - return nil, e; - } - p = make([]byte, max); - n, err1 := io.FullRead(f, p); - f.Close(); - if err1 == nil { // too long - return nil, errLong; - } - if err1 != io.ErrEOF { - return nil, err1; - } - return p[0:n], nil; -} - -func readinfofile(name string) ([]zonetime, os.Error) { - buf, err := readfile(name, maxFileSize); - if err != nil { - goto Error; - } - tx, err := parseinfo(buf); - if err != nil { - goto Error; - } - return tx, nil; - -Error: - if tzerr, ok := err.(TimeZoneError); ok { - tzerr.ErrorString = os.ErrorString(tzerr.String() + ": " + name) - } - return nil, err -} - -var zones []zonetime -var zoneerr os.Error - -func setupZone() { - // consult $TZ to find the time zone to use. - // no $TZ means use the system default /etc/localtime. - // $TZ="" means use UTC. - // $TZ="foo" means use /usr/share/zoneinfo/foo. - - tz, err := os.Getenv("TZ"); - var file string; - switch { - case err == os.ENOENV: - zones, zoneerr = readinfofile("/etc/localtime"); - case err != nil: - zoneerr = err; - case len(tz) > 0: - zones, zoneerr = readinfofile(zoneDir + tz); - case len(tz) == 0: - // do nothing: use UTC - } -} - -func lookupTimezone(sec int64) (zone string, offset int, err os.Error) { - once.Do(setupZone); - if zoneerr != nil || len(zones) == 0 { - return "UTC", 0, zoneerr - } - - // 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:len(tz)] - } - } - z := tz[0].zone; - return z.name, z.utcoff, nil -} diff --git a/src/lib/unicode/Makefile b/src/lib/unicode/Makefile deleted file mode 100644 index de1677b8d..000000000 --- a/src/lib/unicode/Makefile +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m >Makefile - -D= - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - letter.$O\ - -O2=\ - decimaldigit.$O\ - - -phases: a1 a2 -_obj$D/unicode.a: phases - -a1: $(O1) - $(AR) grc _obj$D/unicode.a letter.$O - rm -f $(O1) - -a2: $(O2) - $(AR) grc _obj$D/unicode.a decimaldigit.$O - rm -f $(O2) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/unicode.a - -$(O1): newpkg -$(O2): a1 -$(O3): a2 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/unicode.a - -packages: _obj$D/unicode.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/unicode.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/unicode.a diff --git a/src/lib/unicode/decimaldigit.go b/src/lib/unicode/decimaldigit.go deleted file mode 100644 index 1165e3ae1..000000000 --- a/src/lib/unicode/decimaldigit.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package unicode - -// TODO: Generated by hand starting with -// http://www.unicode.org/Public/UNIDATA/UnicodeData.txt -// These ranges are the characters with the third field "Nd". -// Should generate automatically etc. - -import "unicode" - -// Decimal digit is the set of Unicode characters with the "decimal digit" property. -var DecimalDigit = []Range{ - Range{0x0030, 0x0039, 1}, - Range{0x0660, 0x0669, 1}, - Range{0x06F0, 0x06F9, 1}, - Range{0x07C0, 0x07C9, 1}, - Range{0x0966, 0x096F, 1}, - Range{0x09E6, 0x09EF, 1}, - Range{0x0A66, 0x0A6F, 1}, - Range{0x0AE6, 0x0AEF, 1}, - Range{0x0B66, 0x0B6F, 1}, - Range{0x0BE6, 0x0BEF, 1}, - Range{0x0C66, 0x0C6F, 1}, - Range{0x0CE6, 0x0CEF, 1}, - Range{0x0D66, 0x0D6F, 1}, - Range{0x0E50, 0x0E59, 1}, - Range{0x0ED0, 0x0ED9, 1}, - Range{0x0F20, 0x0F29, 1}, - Range{0x1040, 0x1049, 1}, - Range{0x1090, 0x1099, 1}, - Range{0x17E0, 0x17E9, 1}, - Range{0x1810, 0x1819, 1}, - Range{0x1946, 0x194F, 1}, - Range{0x19D0, 0x19D9, 1}, - Range{0x1B50, 0x1B59, 1}, - Range{0x1BB0, 0x1BB9, 1}, - Range{0x1C40, 0x1C49, 1}, - Range{0x1C50, 0x1C59, 1}, - Range{0xA620, 0xA629, 1}, - Range{0xA8D0, 0xA8D9, 1}, - Range{0xA900, 0xA909, 1}, - Range{0xAA50, 0xAA59, 1}, - Range{0xFF10, 0xFF19, 1}, -} - -// IsDecimalDigit reports whether the rune is a decimal digit. -func IsDecimalDigit(rune int) bool { - return Is(DecimalDigit, rune); -} diff --git a/src/lib/unicode/decimaldigit_test.go b/src/lib/unicode/decimaldigit_test.go deleted file mode 100644 index f7b470c67..000000000 --- a/src/lib/unicode/decimaldigit_test.go +++ /dev/null @@ -1,375 +0,0 @@ -// Copyright 2009 The Go Authors. 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 - -import ( - "testing"; - "unicode"; -) - -// To get data: -// grep '^....;[^;]*;Nd;' UnicodeData.txt -// To generate this table: -// ,s/([^;]+).+/ 0x\1, \/\/ &/g -var testDecimal = []int{ - 0x0030, // 0030;DIGIT ZERO;Nd;0;EN;;0;0;0;N;;;;; - 0x0031, // 0031;DIGIT ONE;Nd;0;EN;;1;1;1;N;;;;; - 0x0032, // 0032;DIGIT TWO;Nd;0;EN;;2;2;2;N;;;;; - 0x0033, // 0033;DIGIT THREE;Nd;0;EN;;3;3;3;N;;;;; - 0x0034, // 0034;DIGIT FOUR;Nd;0;EN;;4;4;4;N;;;;; - 0x0035, // 0035;DIGIT FIVE;Nd;0;EN;;5;5;5;N;;;;; - 0x0036, // 0036;DIGIT SIX;Nd;0;EN;;6;6;6;N;;;;; - 0x0037, // 0037;DIGIT SEVEN;Nd;0;EN;;7;7;7;N;;;;; - 0x0038, // 0038;DIGIT EIGHT;Nd;0;EN;;8;8;8;N;;;;; - 0x0039, // 0039;DIGIT NINE;Nd;0;EN;;9;9;9;N;;;;; - 0x0660, // 0660;ARABIC-INDIC DIGIT ZERO;Nd;0;AN;;0;0;0;N;;;;; - 0x0661, // 0661;ARABIC-INDIC DIGIT ONE;Nd;0;AN;;1;1;1;N;;;;; - 0x0662, // 0662;ARABIC-INDIC DIGIT TWO;Nd;0;AN;;2;2;2;N;;;;; - 0x0663, // 0663;ARABIC-INDIC DIGIT THREE;Nd;0;AN;;3;3;3;N;;;;; - 0x0664, // 0664;ARABIC-INDIC DIGIT FOUR;Nd;0;AN;;4;4;4;N;;;;; - 0x0665, // 0665;ARABIC-INDIC DIGIT FIVE;Nd;0;AN;;5;5;5;N;;;;; - 0x0666, // 0666;ARABIC-INDIC DIGIT SIX;Nd;0;AN;;6;6;6;N;;;;; - 0x0667, // 0667;ARABIC-INDIC DIGIT SEVEN;Nd;0;AN;;7;7;7;N;;;;; - 0x0668, // 0668;ARABIC-INDIC DIGIT EIGHT;Nd;0;AN;;8;8;8;N;;;;; - 0x0669, // 0669;ARABIC-INDIC DIGIT NINE;Nd;0;AN;;9;9;9;N;;;;; - 0x06F0, // 06F0;EXTENDED ARABIC-INDIC DIGIT ZERO;Nd;0;EN;;0;0;0;N;EASTERN ARABIC-INDIC DIGIT ZERO;;;; - 0x06F1, // 06F1;EXTENDED ARABIC-INDIC DIGIT ONE;Nd;0;EN;;1;1;1;N;EASTERN ARABIC-INDIC DIGIT ONE;;;; - 0x06F2, // 06F2;EXTENDED ARABIC-INDIC DIGIT TWO;Nd;0;EN;;2;2;2;N;EASTERN ARABIC-INDIC DIGIT TWO;;;; - 0x06F3, // 06F3;EXTENDED ARABIC-INDIC DIGIT THREE;Nd;0;EN;;3;3;3;N;EASTERN ARABIC-INDIC DIGIT THREE;;;; - 0x06F4, // 06F4;EXTENDED ARABIC-INDIC DIGIT FOUR;Nd;0;EN;;4;4;4;N;EASTERN ARABIC-INDIC DIGIT FOUR;;;; - 0x06F5, // 06F5;EXTENDED ARABIC-INDIC DIGIT FIVE;Nd;0;EN;;5;5;5;N;EASTERN ARABIC-INDIC DIGIT FIVE;;;; - 0x06F6, // 06F6;EXTENDED ARABIC-INDIC DIGIT SIX;Nd;0;EN;;6;6;6;N;EASTERN ARABIC-INDIC DIGIT SIX;;;; - 0x06F7, // 06F7;EXTENDED ARABIC-INDIC DIGIT SEVEN;Nd;0;EN;;7;7;7;N;EASTERN ARABIC-INDIC DIGIT SEVEN;;;; - 0x06F8, // 06F8;EXTENDED ARABIC-INDIC DIGIT EIGHT;Nd;0;EN;;8;8;8;N;EASTERN ARABIC-INDIC DIGIT EIGHT;;;; - 0x06F9, // 06F9;EXTENDED ARABIC-INDIC DIGIT NINE;Nd;0;EN;;9;9;9;N;EASTERN ARABIC-INDIC DIGIT NINE;;;; - 0x07C0, // 07C0;NKO DIGIT ZERO;Nd;0;R;;0;0;0;N;;;;; - 0x07C1, // 07C1;NKO DIGIT ONE;Nd;0;R;;1;1;1;N;;;;; - 0x07C2, // 07C2;NKO DIGIT TWO;Nd;0;R;;2;2;2;N;;;;; - 0x07C3, // 07C3;NKO DIGIT THREE;Nd;0;R;;3;3;3;N;;;;; - 0x07C4, // 07C4;NKO DIGIT FOUR;Nd;0;R;;4;4;4;N;;;;; - 0x07C5, // 07C5;NKO DIGIT FIVE;Nd;0;R;;5;5;5;N;;;;; - 0x07C6, // 07C6;NKO DIGIT SIX;Nd;0;R;;6;6;6;N;;;;; - 0x07C7, // 07C7;NKO DIGIT SEVEN;Nd;0;R;;7;7;7;N;;;;; - 0x07C8, // 07C8;NKO DIGIT EIGHT;Nd;0;R;;8;8;8;N;;;;; - 0x07C9, // 07C9;NKO DIGIT NINE;Nd;0;R;;9;9;9;N;;;;; - 0x0966, // 0966;DEVANAGARI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; - 0x0967, // 0967;DEVANAGARI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; - 0x0968, // 0968;DEVANAGARI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; - 0x0969, // 0969;DEVANAGARI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; - 0x096A, // 096A;DEVANAGARI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; - 0x096B, // 096B;DEVANAGARI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; - 0x096C, // 096C;DEVANAGARI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; - 0x096D, // 096D;DEVANAGARI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; - 0x096E, // 096E;DEVANAGARI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; - 0x096F, // 096F;DEVANAGARI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; - 0x09E6, // 09E6;BENGALI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; - 0x09E7, // 09E7;BENGALI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; - 0x09E8, // 09E8;BENGALI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; - 0x09E9, // 09E9;BENGALI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; - 0x09EA, // 09EA;BENGALI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; - 0x09EB, // 09EB;BENGALI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; - 0x09EC, // 09EC;BENGALI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; - 0x09ED, // 09ED;BENGALI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; - 0x09EE, // 09EE;BENGALI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; - 0x09EF, // 09EF;BENGALI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; - 0x0A66, // 0A66;GURMUKHI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; - 0x0A67, // 0A67;GURMUKHI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; - 0x0A68, // 0A68;GURMUKHI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; - 0x0A69, // 0A69;GURMUKHI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; - 0x0A6A, // 0A6A;GURMUKHI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; - 0x0A6B, // 0A6B;GURMUKHI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; - 0x0A6C, // 0A6C;GURMUKHI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; - 0x0A6D, // 0A6D;GURMUKHI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; - 0x0A6E, // 0A6E;GURMUKHI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; - 0x0A6F, // 0A6F;GURMUKHI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; - 0x0AE6, // 0AE6;GUJARATI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; - 0x0AE7, // 0AE7;GUJARATI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; - 0x0AE8, // 0AE8;GUJARATI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; - 0x0AE9, // 0AE9;GUJARATI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; - 0x0AEA, // 0AEA;GUJARATI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; - 0x0AEB, // 0AEB;GUJARATI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; - 0x0AEC, // 0AEC;GUJARATI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; - 0x0AED, // 0AED;GUJARATI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; - 0x0AEE, // 0AEE;GUJARATI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; - 0x0AEF, // 0AEF;GUJARATI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; - 0x0B66, // 0B66;ORIYA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; - 0x0B67, // 0B67;ORIYA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; - 0x0B68, // 0B68;ORIYA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; - 0x0B69, // 0B69;ORIYA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; - 0x0B6A, // 0B6A;ORIYA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; - 0x0B6B, // 0B6B;ORIYA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; - 0x0B6C, // 0B6C;ORIYA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; - 0x0B6D, // 0B6D;ORIYA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; - 0x0B6E, // 0B6E;ORIYA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; - 0x0B6F, // 0B6F;ORIYA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; - 0x0BE6, // 0BE6;TAMIL DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; - 0x0BE7, // 0BE7;TAMIL DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; - 0x0BE8, // 0BE8;TAMIL DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; - 0x0BE9, // 0BE9;TAMIL DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; - 0x0BEA, // 0BEA;TAMIL DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; - 0x0BEB, // 0BEB;TAMIL DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; - 0x0BEC, // 0BEC;TAMIL DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; - 0x0BED, // 0BED;TAMIL DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; - 0x0BEE, // 0BEE;TAMIL DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; - 0x0BEF, // 0BEF;TAMIL DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; - 0x0C66, // 0C66;TELUGU DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; - 0x0C67, // 0C67;TELUGU DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; - 0x0C68, // 0C68;TELUGU DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; - 0x0C69, // 0C69;TELUGU DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; - 0x0C6A, // 0C6A;TELUGU DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; - 0x0C6B, // 0C6B;TELUGU DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; - 0x0C6C, // 0C6C;TELUGU DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; - 0x0C6D, // 0C6D;TELUGU DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; - 0x0C6E, // 0C6E;TELUGU DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; - 0x0C6F, // 0C6F;TELUGU DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; - 0x0CE6, // 0CE6;KANNADA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; - 0x0CE7, // 0CE7;KANNADA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; - 0x0CE8, // 0CE8;KANNADA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; - 0x0CE9, // 0CE9;KANNADA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; - 0x0CEA, // 0CEA;KANNADA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; - 0x0CEB, // 0CEB;KANNADA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; - 0x0CEC, // 0CEC;KANNADA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; - 0x0CED, // 0CED;KANNADA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; - 0x0CEE, // 0CEE;KANNADA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; - 0x0CEF, // 0CEF;KANNADA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; - 0x0D66, // 0D66;MALAYALAM DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; - 0x0D67, // 0D67;MALAYALAM DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; - 0x0D68, // 0D68;MALAYALAM DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; - 0x0D69, // 0D69;MALAYALAM DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; - 0x0D6A, // 0D6A;MALAYALAM DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; - 0x0D6B, // 0D6B;MALAYALAM DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; - 0x0D6C, // 0D6C;MALAYALAM DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; - 0x0D6D, // 0D6D;MALAYALAM DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; - 0x0D6E, // 0D6E;MALAYALAM DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; - 0x0D6F, // 0D6F;MALAYALAM DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; - 0x0E50, // 0E50;THAI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; - 0x0E51, // 0E51;THAI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; - 0x0E52, // 0E52;THAI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; - 0x0E53, // 0E53;THAI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; - 0x0E54, // 0E54;THAI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; - 0x0E55, // 0E55;THAI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; - 0x0E56, // 0E56;THAI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; - 0x0E57, // 0E57;THAI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; - 0x0E58, // 0E58;THAI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; - 0x0E59, // 0E59;THAI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; - 0x0ED0, // 0ED0;LAO DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; - 0x0ED1, // 0ED1;LAO DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; - 0x0ED2, // 0ED2;LAO DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; - 0x0ED3, // 0ED3;LAO DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; - 0x0ED4, // 0ED4;LAO DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; - 0x0ED5, // 0ED5;LAO DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; - 0x0ED6, // 0ED6;LAO DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; - 0x0ED7, // 0ED7;LAO DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; - 0x0ED8, // 0ED8;LAO DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; - 0x0ED9, // 0ED9;LAO DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; - 0x0F20, // 0F20;TIBETAN DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; - 0x0F21, // 0F21;TIBETAN DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; - 0x0F22, // 0F22;TIBETAN DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; - 0x0F23, // 0F23;TIBETAN DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; - 0x0F24, // 0F24;TIBETAN DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; - 0x0F25, // 0F25;TIBETAN DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; - 0x0F26, // 0F26;TIBETAN DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; - 0x0F27, // 0F27;TIBETAN DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; - 0x0F28, // 0F28;TIBETAN DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; - 0x0F29, // 0F29;TIBETAN DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; - 0x1040, // 1040;MYANMAR DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; - 0x1041, // 1041;MYANMAR DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; - 0x1042, // 1042;MYANMAR DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; - 0x1043, // 1043;MYANMAR DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; - 0x1044, // 1044;MYANMAR DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; - 0x1045, // 1045;MYANMAR DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; - 0x1046, // 1046;MYANMAR DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; - 0x1047, // 1047;MYANMAR DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; - 0x1048, // 1048;MYANMAR DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; - 0x1049, // 1049;MYANMAR DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; - 0x1090, // 1090;MYANMAR SHAN DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; - 0x1091, // 1091;MYANMAR SHAN DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; - 0x1092, // 1092;MYANMAR SHAN DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; - 0x1093, // 1093;MYANMAR SHAN DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; - 0x1094, // 1094;MYANMAR SHAN DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; - 0x1095, // 1095;MYANMAR SHAN DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; - 0x1096, // 1096;MYANMAR SHAN DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; - 0x1097, // 1097;MYANMAR SHAN DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; - 0x1098, // 1098;MYANMAR SHAN DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; - 0x1099, // 1099;MYANMAR SHAN DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; - 0x17E0, // 17E0;KHMER DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; - 0x17E1, // 17E1;KHMER DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; - 0x17E2, // 17E2;KHMER DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; - 0x17E3, // 17E3;KHMER DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; - 0x17E4, // 17E4;KHMER DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; - 0x17E5, // 17E5;KHMER DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; - 0x17E6, // 17E6;KHMER DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; - 0x17E7, // 17E7;KHMER DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; - 0x17E8, // 17E8;KHMER DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; - 0x17E9, // 17E9;KHMER DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; - 0x1810, // 1810;MONGOLIAN DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; - 0x1811, // 1811;MONGOLIAN DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; - 0x1812, // 1812;MONGOLIAN DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; - 0x1813, // 1813;MONGOLIAN DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; - 0x1814, // 1814;MONGOLIAN DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; - 0x1815, // 1815;MONGOLIAN DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; - 0x1816, // 1816;MONGOLIAN DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; - 0x1817, // 1817;MONGOLIAN DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; - 0x1818, // 1818;MONGOLIAN DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; - 0x1819, // 1819;MONGOLIAN DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; - 0x1946, // 1946;LIMBU DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; - 0x1947, // 1947;LIMBU DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; - 0x1948, // 1948;LIMBU DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; - 0x1949, // 1949;LIMBU DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; - 0x194A, // 194A;LIMBU DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; - 0x194B, // 194B;LIMBU DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; - 0x194C, // 194C;LIMBU DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; - 0x194D, // 194D;LIMBU DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; - 0x194E, // 194E;LIMBU DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; - 0x194F, // 194F;LIMBU DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; - 0x19D0, // 19D0;NEW TAI LUE DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; - 0x19D1, // 19D1;NEW TAI LUE DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; - 0x19D2, // 19D2;NEW TAI LUE DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; - 0x19D3, // 19D3;NEW TAI LUE DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; - 0x19D4, // 19D4;NEW TAI LUE DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; - 0x19D5, // 19D5;NEW TAI LUE DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; - 0x19D6, // 19D6;NEW TAI LUE DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; - 0x19D7, // 19D7;NEW TAI LUE DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; - 0x19D8, // 19D8;NEW TAI LUE DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; - 0x19D9, // 19D9;NEW TAI LUE DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; - 0x1B50, // 1B50;BALINESE DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; - 0x1B51, // 1B51;BALINESE DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; - 0x1B52, // 1B52;BALINESE DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; - 0x1B53, // 1B53;BALINESE DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; - 0x1B54, // 1B54;BALINESE DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; - 0x1B55, // 1B55;BALINESE DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; - 0x1B56, // 1B56;BALINESE DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; - 0x1B57, // 1B57;BALINESE DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; - 0x1B58, // 1B58;BALINESE DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; - 0x1B59, // 1B59;BALINESE DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; - 0x1BB0, // 1BB0;SUNDANESE DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; - 0x1BB1, // 1BB1;SUNDANESE DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; - 0x1BB2, // 1BB2;SUNDANESE DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; - 0x1BB3, // 1BB3;SUNDANESE DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; - 0x1BB4, // 1BB4;SUNDANESE DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; - 0x1BB5, // 1BB5;SUNDANESE DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; - 0x1BB6, // 1BB6;SUNDANESE DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; - 0x1BB7, // 1BB7;SUNDANESE DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; - 0x1BB8, // 1BB8;SUNDANESE DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; - 0x1BB9, // 1BB9;SUNDANESE DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; - 0x1C40, // 1C40;LEPCHA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; - 0x1C41, // 1C41;LEPCHA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; - 0x1C42, // 1C42;LEPCHA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; - 0x1C43, // 1C43;LEPCHA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; - 0x1C44, // 1C44;LEPCHA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; - 0x1C45, // 1C45;LEPCHA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; - 0x1C46, // 1C46;LEPCHA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; - 0x1C47, // 1C47;LEPCHA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; - 0x1C48, // 1C48;LEPCHA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; - 0x1C49, // 1C49;LEPCHA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; - 0x1C50, // 1C50;OL CHIKI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; - 0x1C51, // 1C51;OL CHIKI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; - 0x1C52, // 1C52;OL CHIKI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; - 0x1C53, // 1C53;OL CHIKI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; - 0x1C54, // 1C54;OL CHIKI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; - 0x1C55, // 1C55;OL CHIKI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; - 0x1C56, // 1C56;OL CHIKI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; - 0x1C57, // 1C57;OL CHIKI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; - 0x1C58, // 1C58;OL CHIKI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; - 0x1C59, // 1C59;OL CHIKI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; - 0xA620, // A620;VAI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; - 0xA621, // A621;VAI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; - 0xA622, // A622;VAI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; - 0xA623, // A623;VAI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; - 0xA624, // A624;VAI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; - 0xA625, // A625;VAI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; - 0xA626, // A626;VAI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; - 0xA627, // A627;VAI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; - 0xA628, // A628;VAI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; - 0xA629, // A629;VAI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; - 0xA8D0, // A8D0;SAURASHTRA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; - 0xA8D1, // A8D1;SAURASHTRA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; - 0xA8D2, // A8D2;SAURASHTRA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; - 0xA8D3, // A8D3;SAURASHTRA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; - 0xA8D4, // A8D4;SAURASHTRA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; - 0xA8D5, // A8D5;SAURASHTRA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; - 0xA8D6, // A8D6;SAURASHTRA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; - 0xA8D7, // A8D7;SAURASHTRA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; - 0xA8D8, // A8D8;SAURASHTRA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; - 0xA8D9, // A8D9;SAURASHTRA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; - 0xA900, // A900;KAYAH LI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; - 0xA901, // A901;KAYAH LI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; - 0xA902, // A902;KAYAH LI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; - 0xA903, // A903;KAYAH LI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; - 0xA904, // A904;KAYAH LI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; - 0xA905, // A905;KAYAH LI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; - 0xA906, // A906;KAYAH LI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; - 0xA907, // A907;KAYAH LI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; - 0xA908, // A908;KAYAH LI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; - 0xA909, // A909;KAYAH LI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; - 0xAA50, // AA50;CHAM DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; - 0xAA51, // AA51;CHAM DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; - 0xAA52, // AA52;CHAM DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; - 0xAA53, // AA53;CHAM DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; - 0xAA54, // AA54;CHAM DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; - 0xAA55, // AA55;CHAM DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; - 0xAA56, // AA56;CHAM DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; - 0xAA57, // AA57;CHAM DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; - 0xAA58, // AA58;CHAM DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; - 0xAA59, // AA59;CHAM DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; - 0xFF10, // FF10;FULLWIDTH DIGIT ZERO;Nd;0;EN; 0030;0;0;0;N;;;;; - 0xFF11, // FF11;FULLWIDTH DIGIT ONE;Nd;0;EN; 0031;1;1;1;N;;;;; - 0xFF12, // FF12;FULLWIDTH DIGIT TWO;Nd;0;EN; 0032;2;2;2;N;;;;; - 0xFF13, // FF13;FULLWIDTH DIGIT THREE;Nd;0;EN; 0033;3;3;3;N;;;;; - 0xFF14, // FF14;FULLWIDTH DIGIT FOUR;Nd;0;EN; 0034;4;4;4;N;;;;; - 0xFF15, // FF15;FULLWIDTH DIGIT FIVE;Nd;0;EN; 0035;5;5;5;N;;;;; - 0xFF16, // FF16;FULLWIDTH DIGIT SIX;Nd;0;EN; 0036;6;6;6;N;;;;; - 0xFF17, // FF17;FULLWIDTH DIGIT SEVEN;Nd;0;EN; 0037;7;7;7;N;;;;; - 0xFF18, // FF18;FULLWIDTH DIGIT EIGHT;Nd;0;EN; 0038;8;8;8;N;;;;; - 0xFF19, // FF19;FULLWIDTH DIGIT NINE;Nd;0;EN; 0039;9;9;9;N;;;;; -} - -var testLetter = []int{ - 0x41, - 0x61, - 0xaa, - 0xba, - 0xc8, - 0xdb, - 0xf9, - 0x2ec, - 0x535, - 0x6e6, - 0x93d, - 0xa15, - 0xb99, - 0xdc0, - 0xedd, - 0x1000, - 0x1200, - 0x1312, - 0x1401, - 0x1885, - 0x2c00, - 0xa800, - 0xf900, - 0xfa30, - 0xffda, - 0xffdc, - 0x10000, - 0x10300, - 0x10400, - 0x20000, - 0x2f800, - 0x2fa1d, -} - -func TestIsDecimalDigit(t *testing.T) { - for i, r := range(testDecimal) { - if !IsDecimalDigit(r) { - t.Errorf("IsDecimalDigit(%#x) = false, want true\n", r); - } - } - for i, r := range(testLetter) { - if IsDecimalDigit(r) { - t.Errorf("IsDecimalDigit(%#x) = true, want false\n", r); - } - } -} diff --git a/src/lib/unicode/letter.go b/src/lib/unicode/letter.go deleted file mode 100644 index d7aa678c9..000000000 --- a/src/lib/unicode/letter.go +++ /dev/null @@ -1,578 +0,0 @@ -// Copyright 2009 The Go 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 access. A quick start for now. - -// TODO: Generated by hand. -// Should generate automatically from Unicode -// tables, expand to other properties, split into files, -// link in only the tables that are used by the program, -// etc. - -// This package provides data and functions to test some properties of Unicode code points. -// It is rudimentary but will improve. -package unicode - -// The representation of a range of Unicode code points. The range runs from Lo to Hi -// inclusive and has the specified stride. -type Range struct { - Lo int; - Hi int; - Stride int; -} - -// Upper is the set of Unicode upper case letters. -var Upper = []Range{ - Range{0x0041, 0x005a, 1}, - Range{0x00c0, 0x00d6, 1}, - Range{0x00d8, 0x00de, 1}, - Range{0x0100, 0x0136, 2}, - Range{0x0139, 0x0147, 2}, - Range{0x014a, 0x0176, 2}, - Range{0x0178, 0x0179, 1}, - Range{0x017b, 0x017d, 2}, - Range{0x0181, 0x0182, 1}, - Range{0x0184, 0x0184, 1}, - Range{0x0186, 0x0187, 1}, - Range{0x0189, 0x018b, 1}, - Range{0x018e, 0x0191, 1}, - Range{0x0193, 0x0194, 1}, - Range{0x0196, 0x0198, 1}, - Range{0x019c, 0x019d, 1}, - Range{0x019f, 0x01a0, 1}, - Range{0x01a2, 0x01a4, 2}, - Range{0x01a6, 0x01a7, 1}, - Range{0x01a9, 0x01ac, 3}, - Range{0x01ae, 0x01af, 1}, - Range{0x01b1, 0x01b3, 1}, - Range{0x01b5, 0x01b5, 1}, - Range{0x01b7, 0x01b8, 1}, - Range{0x01bc, 0x01c4, 8}, - Range{0x01c7, 0x01cd, 3}, - Range{0x01cf, 0x01db, 2}, - Range{0x01de, 0x01ee, 2}, - Range{0x01f1, 0x01f4, 3}, - Range{0x01f6, 0x01f8, 1}, - Range{0x01fa, 0x0232, 2}, - Range{0x023a, 0x023b, 1}, - Range{0x023d, 0x023e, 1}, - Range{0x0241, 0x0241, 1}, - Range{0x0243, 0x0246, 1}, - Range{0x0248, 0x024e, 2}, - Range{0x0370, 0x0372, 2}, - Range{0x0376, 0x0386, 16}, - Range{0x0388, 0x038a, 1}, - Range{0x038c, 0x038c, 1}, - Range{0x038e, 0x038f, 1}, - Range{0x0391, 0x03a1, 1}, - Range{0x03a3, 0x03ab, 1}, - Range{0x03cf, 0x03cf, 1}, - Range{0x03d2, 0x03d4, 1}, - Range{0x03d8, 0x03ee, 2}, - Range{0x03f4, 0x03f7, 3}, - Range{0x03f9, 0x03fa, 1}, - Range{0x03fd, 0x042f, 1}, - Range{0x0460, 0x0480, 2}, - Range{0x048a, 0x04be, 2}, - Range{0x04c0, 0x04c1, 1}, - Range{0x04c3, 0x04cd, 2}, - Range{0x04d0, 0x0522, 2}, - Range{0x0531, 0x0556, 1}, - Range{0x10a0, 0x10c5, 1}, - Range{0x1e00, 0x1e94, 2}, - Range{0x1e9e, 0x1efe, 2}, - Range{0x1f08, 0x1f0f, 1}, - Range{0x1f18, 0x1f1d, 1}, - Range{0x1f28, 0x1f2f, 1}, - Range{0x1f38, 0x1f3f, 1}, - Range{0x1f48, 0x1f4d, 1}, - Range{0x1f59, 0x1f5f, 2}, - Range{0x1f68, 0x1f6f, 1}, - Range{0x1fb8, 0x1fbb, 1}, - Range{0x1fc8, 0x1fcb, 1}, - Range{0x1fd8, 0x1fdb, 1}, - Range{0x1fe8, 0x1fec, 1}, - Range{0x1ff8, 0x1ffb, 1}, - Range{0x2102, 0x2107, 5}, - Range{0x210b, 0x210d, 1}, - Range{0x2110, 0x2112, 1}, - Range{0x2115, 0x2115, 1}, - Range{0x2119, 0x211d, 1}, - Range{0x2124, 0x2128, 2}, - Range{0x212a, 0x212d, 1}, - Range{0x2130, 0x2133, 1}, - Range{0x213e, 0x213f, 1}, - Range{0x2145, 0x2183, 62}, - Range{0x2c00, 0x2c2e, 1}, - Range{0x2c60, 0x2c60, 1}, - Range{0x2c62, 0x2c64, 1}, - Range{0x2c67, 0x2c6b, 2}, - Range{0x2c6d, 0x2c6f, 1}, - Range{0x2c72, 0x2c75, 3}, - Range{0x2c80, 0x2ce2, 2}, - Range{0xa640, 0xa65e, 2}, - Range{0xa662, 0xa66c, 2}, - Range{0xa680, 0xa696, 2}, - Range{0xa722, 0xa72e, 2}, - Range{0xa732, 0xa76e, 2}, - Range{0xa779, 0xa77b, 2}, - Range{0xa77d, 0xa77e, 1}, - Range{0xa780, 0xa786, 2}, - Range{0xa78b, 0xa78b, 1}, - Range{0xff21, 0xff3a, 1}, - Range{0x10400, 0x10427, 1}, - Range{0x1d400, 0x1d419, 1}, - Range{0x1d434, 0x1d44d, 1}, - Range{0x1d468, 0x1d481, 1}, - Range{0x1d49c, 0x1d49c, 1}, - Range{0x1d49e, 0x1d49f, 1}, - Range{0x1d4a2, 0x1d4a2, 1}, - Range{0x1d4a5, 0x1d4a6, 1}, - Range{0x1d4a9, 0x1d4ac, 1}, - Range{0x1d4ae, 0x1d4b5, 1}, - Range{0x1d4d0, 0x1d4e9, 1}, - Range{0x1d504, 0x1d505, 1}, - Range{0x1d507, 0x1d50a, 1}, - Range{0x1d50d, 0x1d514, 1}, - Range{0x1d516, 0x1d51c, 1}, - Range{0x1d538, 0x1d539, 1}, - Range{0x1d53b, 0x1d53e, 1}, - Range{0x1d540, 0x1d544, 1}, - Range{0x1d546, 0x1d546, 1}, - Range{0x1d54a, 0x1d550, 1}, - Range{0x1d56c, 0x1d585, 1}, - Range{0x1d5a0, 0x1d5b9, 1}, - Range{0x1d5d4, 0x1d5ed, 1}, - Range{0x1d608, 0x1d621, 1}, - Range{0x1d63c, 0x1d655, 1}, - Range{0x1d670, 0x1d689, 1}, - Range{0x1d6a8, 0x1d6c0, 1}, - Range{0x1d6e2, 0x1d6fa, 1}, - Range{0x1d71c, 0x1d734, 1}, - Range{0x1d756, 0x1d76e, 1}, - Range{0x1d790, 0x1d7a8, 1}, - Range{0x1d7ca, 0x1d7ca, 1}, -} - -// Letter is the set of Unicode letters. -var Letter = []Range { - Range{0x0041, 0x005a, 1}, - Range{0x0061, 0x007a, 1}, - Range{0x00aa, 0x00b5, 11}, - Range{0x00ba, 0x00ba, 1}, - Range{0x00c0, 0x00d6, 1}, - Range{0x00d8, 0x00f6, 1}, - Range{0x00f8, 0x02c1, 1}, - Range{0x02c6, 0x02d1, 1}, - Range{0x02e0, 0x02e4, 1}, - Range{0x02ec, 0x02ee, 2}, - Range{0x0370, 0x0374, 1}, - Range{0x0376, 0x0377, 1}, - Range{0x037a, 0x037d, 1}, - Range{0x0386, 0x0386, 1}, - Range{0x0388, 0x038a, 1}, - Range{0x038c, 0x038c, 1}, - Range{0x038e, 0x03a1, 1}, - Range{0x03a3, 0x03f5, 1}, - Range{0x03f7, 0x0481, 1}, - Range{0x048a, 0x0523, 1}, - Range{0x0531, 0x0556, 1}, - Range{0x0559, 0x0559, 1}, - Range{0x0561, 0x0587, 1}, - Range{0x05d0, 0x05ea, 1}, - Range{0x05f0, 0x05f2, 1}, - Range{0x0621, 0x064a, 1}, - Range{0x066e, 0x066f, 1}, - Range{0x0671, 0x06d3, 1}, - Range{0x06d5, 0x06d5, 1}, - Range{0x06e5, 0x06e6, 1}, - Range{0x06ee, 0x06ef, 1}, - Range{0x06fa, 0x06fc, 1}, - Range{0x06ff, 0x0710, 17}, - Range{0x0712, 0x072f, 1}, - Range{0x074d, 0x07a5, 1}, - Range{0x07b1, 0x07b1, 1}, - Range{0x07ca, 0x07ea, 1}, - Range{0x07f4, 0x07f5, 1}, - Range{0x07fa, 0x07fa, 1}, - Range{0x0904, 0x0939, 1}, - Range{0x093d, 0x0950, 19}, - Range{0x0958, 0x0961, 1}, - Range{0x0971, 0x0972, 1}, - Range{0x097b, 0x097f, 1}, - Range{0x0985, 0x098c, 1}, - Range{0x098f, 0x0990, 1}, - Range{0x0993, 0x09a8, 1}, - Range{0x09aa, 0x09b0, 1}, - Range{0x09b2, 0x09b2, 1}, - Range{0x09b6, 0x09b9, 1}, - Range{0x09bd, 0x09ce, 17}, - Range{0x09dc, 0x09dd, 1}, - Range{0x09df, 0x09e1, 1}, - Range{0x09f0, 0x09f1, 1}, - Range{0x0a05, 0x0a0a, 1}, - Range{0x0a0f, 0x0a10, 1}, - Range{0x0a13, 0x0a28, 1}, - Range{0x0a2a, 0x0a30, 1}, - Range{0x0a32, 0x0a33, 1}, - Range{0x0a35, 0x0a36, 1}, - Range{0x0a38, 0x0a39, 1}, - Range{0x0a59, 0x0a5c, 1}, - Range{0x0a5e, 0x0a5e, 1}, - Range{0x0a72, 0x0a74, 1}, - Range{0x0a85, 0x0a8d, 1}, - Range{0x0a8f, 0x0a91, 1}, - Range{0x0a93, 0x0aa8, 1}, - Range{0x0aaa, 0x0ab0, 1}, - Range{0x0ab2, 0x0ab3, 1}, - Range{0x0ab5, 0x0ab9, 1}, - Range{0x0abd, 0x0ad0, 19}, - Range{0x0ae0, 0x0ae1, 1}, - Range{0x0b05, 0x0b0c, 1}, - Range{0x0b0f, 0x0b10, 1}, - Range{0x0b13, 0x0b28, 1}, - Range{0x0b2a, 0x0b30, 1}, - Range{0x0b32, 0x0b33, 1}, - Range{0x0b35, 0x0b39, 1}, - Range{0x0b3d, 0x0b3d, 1}, - Range{0x0b5c, 0x0b5d, 1}, - Range{0x0b5f, 0x0b61, 1}, - Range{0x0b71, 0x0b83, 18}, - Range{0x0b85, 0x0b8a, 1}, - Range{0x0b8e, 0x0b90, 1}, - Range{0x0b92, 0x0b95, 1}, - Range{0x0b99, 0x0b9a, 1}, - Range{0x0b9c, 0x0b9c, 1}, - Range{0x0b9e, 0x0b9f, 1}, - Range{0x0ba3, 0x0ba4, 1}, - Range{0x0ba8, 0x0baa, 1}, - Range{0x0bae, 0x0bb9, 1}, - Range{0x0bd0, 0x0bd0, 1}, - Range{0x0c05, 0x0c0c, 1}, - Range{0x0c0e, 0x0c10, 1}, - Range{0x0c12, 0x0c28, 1}, - Range{0x0c2a, 0x0c33, 1}, - Range{0x0c35, 0x0c39, 1}, - Range{0x0c3d, 0x0c3d, 1}, - Range{0x0c58, 0x0c59, 1}, - Range{0x0c60, 0x0c61, 1}, - Range{0x0c85, 0x0c8c, 1}, - Range{0x0c8e, 0x0c90, 1}, - Range{0x0c92, 0x0ca8, 1}, - Range{0x0caa, 0x0cb3, 1}, - Range{0x0cb5, 0x0cb9, 1}, - Range{0x0cbd, 0x0cde, 33}, - Range{0x0ce0, 0x0ce1, 1}, - Range{0x0d05, 0x0d0c, 1}, - Range{0x0d0e, 0x0d10, 1}, - Range{0x0d12, 0x0d28, 1}, - Range{0x0d2a, 0x0d39, 1}, - Range{0x0d3d, 0x0d3d, 1}, - Range{0x0d60, 0x0d61, 1}, - Range{0x0d7a, 0x0d7f, 1}, - Range{0x0d85, 0x0d96, 1}, - Range{0x0d9a, 0x0db1, 1}, - Range{0x0db3, 0x0dbb, 1}, - Range{0x0dbd, 0x0dbd, 1}, - Range{0x0dc0, 0x0dc6, 1}, - Range{0x0e01, 0x0e30, 1}, - Range{0x0e32, 0x0e33, 1}, - Range{0x0e40, 0x0e46, 1}, - Range{0x0e81, 0x0e82, 1}, - Range{0x0e84, 0x0e84, 1}, - Range{0x0e87, 0x0e88, 1}, - Range{0x0e8a, 0x0e8d, 3}, - Range{0x0e94, 0x0e97, 1}, - Range{0x0e99, 0x0e9f, 1}, - Range{0x0ea1, 0x0ea3, 1}, - Range{0x0ea5, 0x0ea7, 2}, - Range{0x0eaa, 0x0eab, 1}, - Range{0x0ead, 0x0eb0, 1}, - Range{0x0eb2, 0x0eb3, 1}, - Range{0x0ebd, 0x0ebd, 1}, - Range{0x0ec0, 0x0ec4, 1}, - Range{0x0ec6, 0x0ec6, 1}, - Range{0x0edc, 0x0edd, 1}, - Range{0x0f00, 0x0f00, 1}, - Range{0x0f40, 0x0f47, 1}, - Range{0x0f49, 0x0f6c, 1}, - Range{0x0f88, 0x0f8b, 1}, - Range{0x1000, 0x102a, 1}, - Range{0x103f, 0x103f, 1}, - Range{0x1050, 0x1055, 1}, - Range{0x105a, 0x105d, 1}, - Range{0x1061, 0x1061, 1}, - Range{0x1065, 0x1066, 1}, - Range{0x106e, 0x1070, 1}, - Range{0x1075, 0x1081, 1}, - Range{0x108e, 0x108e, 1}, - Range{0x10a0, 0x10c5, 1}, - Range{0x10d0, 0x10fa, 1}, - Range{0x10fc, 0x10fc, 1}, - Range{0x1100, 0x1159, 1}, - Range{0x115f, 0x11a2, 1}, - Range{0x11a8, 0x11f9, 1}, - Range{0x1200, 0x1248, 1}, - Range{0x124a, 0x124d, 1}, - Range{0x1250, 0x1256, 1}, - Range{0x1258, 0x1258, 1}, - Range{0x125a, 0x125d, 1}, - Range{0x1260, 0x1288, 1}, - Range{0x128a, 0x128d, 1}, - Range{0x1290, 0x12b0, 1}, - Range{0x12b2, 0x12b5, 1}, - Range{0x12b8, 0x12be, 1}, - Range{0x12c0, 0x12c0, 1}, - Range{0x12c2, 0x12c5, 1}, - Range{0x12c8, 0x12d6, 1}, - Range{0x12d8, 0x1310, 1}, - Range{0x1312, 0x1315, 1}, - Range{0x1318, 0x135a, 1}, - Range{0x1380, 0x138f, 1}, - Range{0x13a0, 0x13f4, 1}, - Range{0x1401, 0x166c, 1}, - Range{0x166f, 0x1676, 1}, - Range{0x1681, 0x169a, 1}, - Range{0x16a0, 0x16ea, 1}, - Range{0x1700, 0x170c, 1}, - Range{0x170e, 0x1711, 1}, - Range{0x1720, 0x1731, 1}, - Range{0x1740, 0x1751, 1}, - Range{0x1760, 0x176c, 1}, - Range{0x176e, 0x1770, 1}, - Range{0x1780, 0x17b3, 1}, - Range{0x17d7, 0x17dc, 5}, - Range{0x1820, 0x1877, 1}, - Range{0x1880, 0x18a8, 1}, - Range{0x18aa, 0x18aa, 1}, - Range{0x1900, 0x191c, 1}, - Range{0x1950, 0x196d, 1}, - Range{0x1970, 0x1974, 1}, - Range{0x1980, 0x19a9, 1}, - Range{0x19c1, 0x19c7, 1}, - Range{0x1a00, 0x1a16, 1}, - Range{0x1b05, 0x1b33, 1}, - Range{0x1b45, 0x1b4b, 1}, - Range{0x1b83, 0x1ba0, 1}, - Range{0x1bae, 0x1baf, 1}, - Range{0x1c00, 0x1c23, 1}, - Range{0x1c4d, 0x1c4f, 1}, - Range{0x1c5a, 0x1c7d, 1}, - Range{0x1d00, 0x1dbf, 1}, - Range{0x1e00, 0x1f15, 1}, - Range{0x1f18, 0x1f1d, 1}, - Range{0x1f20, 0x1f45, 1}, - Range{0x1f48, 0x1f4d, 1}, - Range{0x1f50, 0x1f57, 1}, - Range{0x1f59, 0x1f5d, 2}, - Range{0x1f5f, 0x1f7d, 1}, - Range{0x1f80, 0x1fb4, 1}, - Range{0x1fb6, 0x1fbc, 1}, - Range{0x1fbe, 0x1fbe, 1}, - Range{0x1fc2, 0x1fc4, 1}, - Range{0x1fc6, 0x1fcc, 1}, - Range{0x1fd0, 0x1fd3, 1}, - Range{0x1fd6, 0x1fdb, 1}, - Range{0x1fe0, 0x1fec, 1}, - Range{0x1ff2, 0x1ff4, 1}, - Range{0x1ff6, 0x1ffc, 1}, - Range{0x2071, 0x207f, 14}, - Range{0x2090, 0x2094, 1}, - Range{0x2102, 0x2107, 5}, - Range{0x210a, 0x2113, 1}, - Range{0x2115, 0x2115, 1}, - Range{0x2119, 0x211d, 1}, - Range{0x2124, 0x2128, 2}, - Range{0x212a, 0x212d, 1}, - Range{0x212f, 0x2139, 1}, - Range{0x213c, 0x213f, 1}, - Range{0x2145, 0x2149, 1}, - Range{0x214e, 0x214e, 1}, - Range{0x2183, 0x2184, 1}, - Range{0x2c00, 0x2c2e, 1}, - Range{0x2c30, 0x2c5e, 1}, - Range{0x2c60, 0x2c6f, 1}, - Range{0x2c71, 0x2c7d, 1}, - Range{0x2c80, 0x2ce4, 1}, - Range{0x2d00, 0x2d25, 1}, - Range{0x2d30, 0x2d65, 1}, - Range{0x2d6f, 0x2d6f, 1}, - Range{0x2d80, 0x2d96, 1}, - Range{0x2da0, 0x2da6, 1}, - Range{0x2da8, 0x2dae, 1}, - Range{0x2db0, 0x2db6, 1}, - Range{0x2db8, 0x2dbe, 1}, - Range{0x2dc0, 0x2dc6, 1}, - Range{0x2dc8, 0x2dce, 1}, - Range{0x2dd0, 0x2dd6, 1}, - Range{0x2dd8, 0x2dde, 1}, - Range{0x2e2f, 0x2e2f, 1}, - Range{0x3005, 0x3006, 1}, - Range{0x3031, 0x3035, 1}, - Range{0x303b, 0x303c, 1}, - Range{0x3041, 0x3096, 1}, - Range{0x309d, 0x309f, 1}, - Range{0x30a1, 0x30fa, 1}, - Range{0x30fc, 0x30ff, 1}, - Range{0x3105, 0x312d, 1}, - Range{0x3131, 0x318e, 1}, - Range{0x31a0, 0x31b7, 1}, - Range{0x31f0, 0x31ff, 1}, - Range{0x3400, 0x4db5, 1}, - Range{0x4e00, 0x9fc3, 1}, - Range{0xa000, 0xa48c, 1}, - Range{0xa500, 0xa60c, 1}, - Range{0xa610, 0xa61f, 1}, - Range{0xa62a, 0xa62b, 1}, - Range{0xa640, 0xa65f, 1}, - Range{0xa662, 0xa66e, 1}, - Range{0xa67f, 0xa697, 1}, - Range{0xa717, 0xa71f, 1}, - Range{0xa722, 0xa788, 1}, - Range{0xa78b, 0xa78c, 1}, - Range{0xa7fb, 0xa801, 1}, - Range{0xa803, 0xa805, 1}, - Range{0xa807, 0xa80a, 1}, - Range{0xa80c, 0xa822, 1}, - Range{0xa840, 0xa873, 1}, - Range{0xa882, 0xa8b3, 1}, - Range{0xa90a, 0xa925, 1}, - Range{0xa930, 0xa946, 1}, - Range{0xaa00, 0xaa28, 1}, - Range{0xaa40, 0xaa42, 1}, - Range{0xaa44, 0xaa4b, 1}, - Range{0xac00, 0xd7a3, 1}, - Range{0xf900, 0xfa2d, 1}, - Range{0xfa30, 0xfa6a, 1}, - Range{0xfa70, 0xfad9, 1}, - Range{0xfb00, 0xfb06, 1}, - Range{0xfb13, 0xfb17, 1}, - Range{0xfb1d, 0xfb1d, 1}, - Range{0xfb1f, 0xfb28, 1}, - Range{0xfb2a, 0xfb36, 1}, - Range{0xfb38, 0xfb3c, 1}, - Range{0xfb3e, 0xfb3e, 1}, - Range{0xfb40, 0xfb41, 1}, - Range{0xfb43, 0xfb44, 1}, - Range{0xfb46, 0xfbb1, 1}, - Range{0xfbd3, 0xfd3d, 1}, - Range{0xfd50, 0xfd8f, 1}, - Range{0xfd92, 0xfdc7, 1}, - Range{0xfdf0, 0xfdfb, 1}, - Range{0xfe70, 0xfe74, 1}, - Range{0xfe76, 0xfefc, 1}, - Range{0xff21, 0xff3a, 1}, - Range{0xff41, 0xff5a, 1}, - Range{0xff66, 0xffbe, 1}, - Range{0xffc2, 0xffc7, 1}, - Range{0xffca, 0xffcf, 1}, - Range{0xffd2, 0xffd7, 1}, - Range{0xffda, 0xffdc, 1}, - Range{0x10000, 0x1000b, 1}, - Range{0x1000d, 0x10026, 1}, - Range{0x10028, 0x1003a, 1}, - Range{0x1003c, 0x1003d, 1}, - Range{0x1003f, 0x1004d, 1}, - Range{0x10050, 0x1005d, 1}, - Range{0x10080, 0x100fa, 1}, - Range{0x10280, 0x1029c, 1}, - Range{0x102a0, 0x102d0, 1}, - Range{0x10300, 0x1031e, 1}, - Range{0x10330, 0x10340, 1}, - Range{0x10342, 0x10349, 1}, - Range{0x10380, 0x1039d, 1}, - Range{0x103a0, 0x103c3, 1}, - Range{0x103c8, 0x103cf, 1}, - Range{0x10400, 0x1049d, 1}, - Range{0x10800, 0x10805, 1}, - Range{0x10808, 0x10808, 1}, - Range{0x1080a, 0x10835, 1}, - Range{0x10837, 0x10838, 1}, - Range{0x1083c, 0x1083f, 3}, - Range{0x10900, 0x10915, 1}, - Range{0x10920, 0x10939, 1}, - Range{0x10a00, 0x10a00, 1}, - Range{0x10a10, 0x10a13, 1}, - Range{0x10a15, 0x10a17, 1}, - Range{0x10a19, 0x10a33, 1}, - Range{0x12000, 0x1236e, 1}, - Range{0x1d400, 0x1d454, 1}, - Range{0x1d456, 0x1d49c, 1}, - Range{0x1d49e, 0x1d49f, 1}, - Range{0x1d4a2, 0x1d4a2, 1}, - Range{0x1d4a5, 0x1d4a6, 1}, - Range{0x1d4a9, 0x1d4ac, 1}, - Range{0x1d4ae, 0x1d4b9, 1}, - Range{0x1d4bb, 0x1d4bb, 1}, - Range{0x1d4bd, 0x1d4c3, 1}, - Range{0x1d4c5, 0x1d505, 1}, - Range{0x1d507, 0x1d50a, 1}, - Range{0x1d50d, 0x1d514, 1}, - Range{0x1d516, 0x1d51c, 1}, - Range{0x1d51e, 0x1d539, 1}, - Range{0x1d53b, 0x1d53e, 1}, - Range{0x1d540, 0x1d544, 1}, - Range{0x1d546, 0x1d546, 1}, - Range{0x1d54a, 0x1d550, 1}, - Range{0x1d552, 0x1d6a5, 1}, - Range{0x1d6a8, 0x1d6c0, 1}, - Range{0x1d6c2, 0x1d6da, 1}, - Range{0x1d6dc, 0x1d6fa, 1}, - Range{0x1d6fc, 0x1d714, 1}, - Range{0x1d716, 0x1d734, 1}, - Range{0x1d736, 0x1d74e, 1}, - Range{0x1d750, 0x1d76e, 1}, - Range{0x1d770, 0x1d788, 1}, - Range{0x1d78a, 0x1d7a8, 1}, - Range{0x1d7aa, 0x1d7c2, 1}, - Range{0x1d7c4, 0x1d7cb, 1}, - Range{0x20000, 0x2a6d6, 1}, - Range{0x2f800, 0x2fa1d, 1}, -} - -// Is tests whether rune is in the specified table of ranges. -func Is(ranges []Range, rune int) bool { - // common case: rune is ASCII or Latin-1 - if rune < 0x100 { - for i := 0; i < len(ranges); i++ { - r := ranges[i]; - if rune > r.Hi { - continue; - } - if rune < r.Lo { - return false; - } - return (rune - r.Lo) % r.Stride == 0; - } - return false; - } - - // binary search over ranges - lo := 0; - hi := len(ranges); - for lo < hi { - m := lo + (hi - lo)/2; - r := ranges[m]; - if r.Lo <= rune && rune <= r.Hi { - return (rune - r.Lo) % r.Stride == 0; - } - if rune < r.Lo { - hi = m; - } else { - lo = m+1; - } - } - return false; -} - -// IsLetter reports whether the rune is an upper case letter. -func IsUpper(rune int) bool { - return Is(Upper, rune); -} - -// IsLetter reports whether the rune is a letter. -func IsLetter(rune int) bool { - return Is(Letter, rune); -} - diff --git a/src/lib/unicode/letter_test.go b/src/lib/unicode/letter_test.go deleted file mode 100644 index d39d74e6b..000000000 --- a/src/lib/unicode/letter_test.go +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright 2009 The Go Authors. 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 - -import ( - "testing"; - "unicode"; -) - -var upper = []int{ - 0x41, - 0xc0, - 0xd8, - 0x100, - 0x139, - 0x14a, - 0x178, - 0x181, - 0x376, - 0x3cf, - 0x1f2a, - 0x2102, - 0x2c00, - 0x2c10, - 0x2c20, - 0xa650, - 0xa722, - 0xff3a, - 0x10400, - 0x1d400, - 0x1d7ca, -} - -var notupper = []int{ - 0x40, - 0x5b, - 0x61, - 0x185, - 0x1b0, - 0x377, - 0x387, - 0x2150, - 0xffff, - 0x10000, -} - -var letter = []int{ - 0x41, - 0x61, - 0xaa, - 0xba, - 0xc8, - 0xdb, - 0xf9, - 0x2ec, - 0x535, - 0x6e6, - 0x93d, - 0xa15, - 0xb99, - 0xdc0, - 0xedd, - 0x1000, - 0x1200, - 0x1312, - 0x1401, - 0x1885, - 0x2c00, - 0xa800, - 0xf900, - 0xfa30, - 0xffda, - 0xffdc, - 0x10000, - 0x10300, - 0x10400, - 0x20000, - 0x2f800, - 0x2fa1d, -} - -var notletter = []int{ - 0x20, - 0x35, - 0x375, - 0x620, - 0x700, - 0xfffe, - 0x1ffff, - 0x10ffff, -} - -func TestIsLetter(t *testing.T) { - for i, r := range(upper) { - if !IsLetter(r) { - t.Errorf("IsLetter(%#x) = false, want true\n", r); - } - } - for i, r := range(letter) { - if !IsLetter(r) { - t.Errorf("IsLetter(%#x) = false, want true\n", r); - } - } - for i, r := range(notletter) { - if IsLetter(r) { - t.Errorf("IsLetter(%#x) = true, want false\n", r); - } - } -} - -func TestIsUpper(t *testing.T) { - for i, r := range(upper) { - if !IsUpper(r) { - t.Errorf("IsUpper(%#x) = false, want true\n", r); - } - } - for i, r := range(notupper) { - if IsUpper(r) { - t.Errorf("IsUpper(%#x) = true, want false\n", r); - } - } - for i, r := range(notletter) { - if IsUpper(r) { - t.Errorf("IsUpper(%#x) = true, want false\n", r); - } - } -} diff --git a/src/lib/unsafe/unsafe.go b/src/lib/unsafe/unsafe.go deleted file mode 100644 index b19af405b..000000000 --- a/src/lib/unsafe/unsafe.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2009 The Go 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 unsafe package 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 uintptr can be converted to a Pointer. -// 3) 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 minimum 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 - -// Reflect unpacks an interface value into its internal value word and its type string. -// The boolean indir is true if the value is a pointer to the real value. -func Reflect(i interface {}) (value uint64, typestring string, indir bool) - -// Unreflect inverts Reflect: Given a value word, a type string, and the indirect bit, -// it returns an empty interface value with those contents. -func Unreflect(value uint64, typestring string, indir bool) (ret interface {}) diff --git a/src/lib/utf8/Makefile b/src/lib/utf8/Makefile deleted file mode 100644 index b5ad083b2..000000000 --- a/src/lib/utf8/Makefile +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# DO NOT EDIT. Automatically generated by gobuild. -# gobuild -m >Makefile - -D= - -include $(GOROOT)/src/Make.$(GOARCH) -AR=gopack - -default: packages - -clean: - rm -rf *.[$(OS)] *.a [$(OS)].out _obj - -test: packages - gotest - -coverage: packages - gotest - 6cov -g `pwd` | grep -v '_test\.go:' - -%.$O: %.go - $(GC) -I_obj $*.go - -%.$O: %.c - $(CC) $*.c - -%.$O: %.s - $(AS) $*.s - -O1=\ - utf8.$O\ - - -phases: a1 -_obj$D/utf8.a: phases - -a1: $(O1) - $(AR) grc _obj$D/utf8.a utf8.$O - rm -f $(O1) - - -newpkg: clean - mkdir -p _obj$D - $(AR) grc _obj$D/utf8.a - -$(O1): newpkg -$(O2): a1 - -nuke: clean - rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/utf8.a - -packages: _obj$D/utf8.a - -install: packages - test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D - cp _obj$D/utf8.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/utf8.a diff --git a/src/lib/utf8/utf8.go b/src/lib/utf8/utf8.go deleted file mode 100644 index 9c2ac790d..000000000 --- a/src/lib/utf8/utf8.go +++ /dev/null @@ -1,291 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Functions and constants to support text encoded in UTF-8. -// This package calls a Unicode character a rune for brevity. -package utf8 - -// Numbers fundamental to the encoding. -const ( - RuneError = 0xFFFD; // the "error" Rune or "replacement character". - RuneSelf = 0x80; // characters below Runeself are represented as themselves in a single byte. - RuneMax = 0x10FFFF; // maximum Unicode code point. - 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 { - rune, size, short := decodeRuneInternal(p); - return !short -} - -// FullRuneInString is like FullRune but its input is a string. -func FullRuneInString(s string) bool { - rune, size, 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) { - var short bool; - rune, size, short = decodeRuneInternal(p); - return; -} - -// DecodeRuneInString is like DecodeRune but its input is a string. -func DecodeRuneInString(s string) (rune, size int) { - var short bool; - rune, size, short = decodeRuneInStringInternal(s); - return; -} - -// 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(rune int, p []byte) int { - if rune <= _Rune1Max { - p[0] = byte(rune); - return 1; - } - - if rune <= _Rune2Max { - p[0] = _T2 | byte(rune>>6); - p[1] = _Tx | byte(rune)&_Maskx; - return 2; - } - - if rune > RuneMax { - rune = RuneError - } - - if rune <= _Rune3Max { - p[0] = _T3 | byte(rune>>12); - p[1] = _Tx | byte(rune>>6)&_Maskx; - p[2] = _Tx | byte(rune)&_Maskx; - return 3; - } - - p[0] = _T4 | byte(rune>>18); - p[1] = _Tx | byte(rune>>12)&_Maskx; - p[2] = _Tx | byte(rune>>6)&_Maskx; - p[3] = _Tx | byte(rune)&_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 { - rune, size := DecodeRune(p[i:len(p)]); - i += size; - } - } - return n; -} - -// RuneCountInString is like RuneCount but its input is a string. -func RuneCountInString(s string) int { - ei := len(s); - i := 0; - n := 0; - for n = 0; i < ei; n++ { - if s[i] < RuneSelf { - i++; - } else { - rune, size, short := decodeRuneInStringInternal(s[i:ei]); - i += size; - } - } - return n; -} - diff --git a/src/lib/utf8/utf8_test.go b/src/lib/utf8/utf8_test.go deleted file mode 100644 index f60b0b17e..000000000 --- a/src/lib/utf8/utf8_test.go +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright 2009 The Go Authors. 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 - -import ( - "bytes"; - "fmt"; - "io"; - "testing"; - "utf8"; -) - -type Utf8Map struct { - rune int; - str string; -} - -var utf8map = []Utf8Map { - Utf8Map{ 0x0000, "\x00" }, - Utf8Map{ 0x0001, "\x01" }, - Utf8Map{ 0x007e, "\x7e" }, - Utf8Map{ 0x007f, "\x7f" }, - Utf8Map{ 0x0080, "\xc2\x80" }, - Utf8Map{ 0x0081, "\xc2\x81" }, - Utf8Map{ 0x00bf, "\xc2\xbf" }, - Utf8Map{ 0x00c0, "\xc3\x80" }, - Utf8Map{ 0x00c1, "\xc3\x81" }, - Utf8Map{ 0x00c8, "\xc3\x88" }, - Utf8Map{ 0x00d0, "\xc3\x90" }, - Utf8Map{ 0x00e0, "\xc3\xa0" }, - Utf8Map{ 0x00f0, "\xc3\xb0" }, - Utf8Map{ 0x00f8, "\xc3\xb8" }, - Utf8Map{ 0x00ff, "\xc3\xbf" }, - Utf8Map{ 0x0100, "\xc4\x80" }, - Utf8Map{ 0x07ff, "\xdf\xbf" }, - Utf8Map{ 0x0800, "\xe0\xa0\x80" }, - Utf8Map{ 0x0801, "\xe0\xa0\x81" }, - Utf8Map{ 0xfffe, "\xef\xbf\xbe" }, - Utf8Map{ 0xffff, "\xef\xbf\xbf" }, - Utf8Map{ 0x10000, "\xf0\x90\x80\x80" }, - Utf8Map{ 0x10001, "\xf0\x90\x80\x81" }, - Utf8Map{ 0x10fffe, "\xf4\x8f\xbf\xbe" }, - Utf8Map{ 0x10ffff, "\xf4\x8f\xbf\xbf" }, -} - -// io.StringBytes with one extra byte at end -func makeBytes(s string) []byte { - s += "\x00"; - b := io.StringBytes(s); - return b[0:len(s)-1]; -} - -func TestFullRune(t *testing.T) { - for i := 0; i < len(utf8map); i++ { - m := utf8map[i]; - b := makeBytes(m.str); - if !utf8.FullRune(b) { - t.Errorf("FullRune(%q) (rune %04x) = false, want true", b, m.rune); - } - s := m.str; - if !utf8.FullRuneInString(s) { - t.Errorf("FullRuneInString(%q) (rune %04x) = false, want true", s, m.rune); - } - b1 := b[0:len(b)-1]; - if utf8.FullRune(b1) { - t.Errorf("FullRune(%q) = true, want false", b1); - } - s1 := string(b1); - if utf8.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 := makeBytes(m.str); - var buf [10]byte; - n := utf8.EncodeRune(m.rune, &buf); - b1 := buf[0:n]; - if !bytes.Equal(b, b1) { - t.Errorf("EncodeRune(0x%04x) = %q want %q", m.rune, b1, b); - } - } -} - -func TestDecodeRune(t *testing.T) { - for i := 0; i < len(utf8map); i++ { - m := utf8map[i]; - b := makeBytes(m.str); - rune, size := utf8.DecodeRune(b); - if rune != m.rune || size != len(b) { - t.Errorf("DecodeRune(%q) = 0x%04x, %d want 0x%04x, %d", b, rune, size, m.rune, len(b)); - } - s := m.str; - rune, size = utf8.DecodeRuneInString(s); - if rune != m.rune || size != len(b) { - t.Errorf("DecodeRune(%q) = 0x%04x, %d want 0x%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 = utf8.DecodeRune(b[0:cap(b)]); - if rune != m.rune || size != len(b) { - t.Errorf("DecodeRune(%q) = 0x%04x, %d want 0x%04x, %d", b, rune, size, m.rune, len(b)); - } - s = m.str+"\x00"; - rune, size = utf8.DecodeRuneInString(s); - if rune != m.rune || size != len(b) { - t.Errorf("DecodeRuneInString(%q) = 0x%04x, %d want 0x%04x, %d", s, rune, size, m.rune, len(b)); - } - - // make sure missing bytes fail - wantsize := 1; - if wantsize >= len(b) { - wantsize = 0; - } - rune, size = utf8.DecodeRune(b[0:len(b)-1]); - if rune != RuneError || size != wantsize { - t.Errorf("DecodeRune(%q) = 0x%04x, %d want 0x%04x, %d", b[0:len(b)-1], rune, size, RuneError, wantsize); - } - s = m.str[0:len(m.str)-1]; - rune, size = utf8.DecodeRuneInString(s); - if rune != RuneError || size != wantsize { - t.Errorf("DecodeRuneInString(%q) = 0x%04x, %d want 0x%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 = utf8.DecodeRune(b); - if rune != RuneError || size != 1 { - t.Errorf("DecodeRune(%q) = 0x%04x, %d want 0x%04x, %d", b, rune, size, RuneError, 1); - } - s = string(b); - rune, size = utf8.DecodeRune(b); - if rune != RuneError || size != 1 { - t.Errorf("DecodeRuneInString(%q) = 0x%04x, %d want 0x%04x, %d", s, rune, size, RuneError, 1); - } - } -} - -type RuneCountTest struct { - in string; - out int; -} -var runecounttests = []RuneCountTest { - RuneCountTest{ "abcd", 4 }, - RuneCountTest{ "☺☻☹", 3 }, - RuneCountTest{ "1,2,3,4", 7 }, - RuneCountTest{ "\xe2\x00", 2 }, -} -func TestRuneCount(t *testing.T) { - for i := 0; i < len(runecounttests); i++ { - tt := runecounttests[i]; - if out := utf8.RuneCountInString(tt.in); out != tt.out { - t.Errorf("RuneCountInString(%q) = %d, want %d", tt.in, out, tt.out); - } - if out := utf8.RuneCount(makeBytes(tt.in)); out != tt.out { - t.Errorf("RuneCount(%q) = %d, want %d", tt.in, out, tt.out); - } - } -} diff --git a/src/lib/xml/xml.go b/src/lib/xml/xml.go deleted file mode 100644 index bd944337e..000000000 --- a/src/lib/xml/xml.go +++ /dev/null @@ -1,426 +0,0 @@ -// Copyright 2009 The Go 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(rsc): Actually, this package is just a description -// of an implementation that hasn't been written yet. - -// This package implements an XML parser but relies on -// clients to implement the parsing actions. - -// An XML document is a single XML element. -// -// An XML element is either a start tag and an end tag, -// like ..., or a combined start/end tag . -// The latter is identical in semantics to , -// and this parser does not distinguish them. -// -// The start (or combined start/end) tag can have -// name="value" attributes inside the angle brackets after -// the tag name, as in Google. -// Names are drawn from a fixed set of alphabetic letters; -// Values are strings quoted with single or double quotes. -// -// An element made up of distinct start and end tags can -// contain free-form text and other elements inside it, -// as in Google -// or Google. -// The former is an element with the text "Google" inside it. -// The latter is a element with that element inside it. -// In general, an element can contain a sequence of elements -// and text inside it. In XML, white space inside an element is -// always counted as text--it is never discarded by the parser. -// XML parsers do translate \r and \r\n into \n in text. -// -// This parser reads an XML document and calls methods on a -// Builder interface object in response to the text. -// It calls the builder's StartElement, Text, and EndElement -// methods, mimicking the structure of the text. -// For example, the simple XML document: -// -// -// Google -//
-// -// results in the following sequence of builder calls: -// -// StartElement("a", []Attr(Attr("href", "http://www.google.com"))); -// Text("\n\t"); -// StartElement("img", []Attr(Attr("src", "http://www.google.com/icon.png"), -// Attr("alt", "Google"))); -// EndElement("img"); -// Text("\n"); -// StartElement("br", []Attr()); -// EndElement("br"); -// EndElement("a"); -// -// There are, of course, a few more details, but the story so far -// should be enough for the majority of uses. The details are: -// -// * XML documents typically begin with an XML declaration line like -// . -// This line is strongly recommended, but not strictly required. -// It introduces the XML version and text encoding for the rest -// of the file. XML parsers are required to recognize UTF-8 and -// UTF-16. This parser only recognizes UTF-8 (for now?). -// -// * After the XML declaration comes an optional doctype declaration like -// -// The parser should pass this information on to the client in some -// form, but does not. It discards such lines. -// -// * The XML declaration line is an instance of a more general tag -// called a processing instruction, XML's #pragma. The general form is -// , where target is a name (like "xml") specifying -// the intended recipient of the instruction, and text is the -// instruction itself. This XML parser keeps the declaration -// to itself but passes along other processing instructions using -// the ProcInst method. Processing instructions can appear anywhere -// in an XML document. Most clients will simply ignore them. -// -// * An XML comment can appear anywhere in an XML document. -// Comments have the form . The XML parser passes -// them along by calling the Comment method. Again, most clients -// will simply ignore them. -// -// * Text inside an XML element must be escaped to avoid looking like -// a start/end tag. Specifically, the characters < and & must be -// written as < and &. An alternate quoting mechanism is to -// use the construct . The quoted text ... can contain -// < characters, but not the sequence ]]>. Ampersands must still be -// escaped. For some reason, the existence of the CDATA quoting mechanism -// infects the processing of ordinary unquoted text, which is not allowed -// to contain the literal sequence ]]>. Instead, it would be written -// escaped, as in ]]>. The parser hides all these considerations -// from the library client -- it reports all text, regardless of original -// form and already unescaped, using the Text method. -// -// * A revision to XML 1.0 introduced the concept of name spaces -// for attribute and tag names. A start tag with an attribute -// xmlns:prefix="URL" introduces `prefix' as a shorthand -// for the name space whose identifier is URL. Inside the element -// with that start tag, an element name or attribute prefix:foo -// (as in ) is understood to refer -// to name `foo' in the name space denoted by `URL'. Although -// this is a shorthand, there is no canonical expansion. Thus: -// -// -// text1 -// text2 -// -// -// and -// -// -// text1 -// text2 -// -// -// are equivalent XML documents, and there is no canonical form. -// -// The special attribute xmlns="URL" sets the default name space -// for unprefixed tags (but not attribute names) to URL. -// Thus: -// -// -// text1 -// text2 -// -// -// is another XML document equivalent to the first two, and -// -// -// text1 -// text2 -// -// -// would be equivalent, except that `attr' in attr="value" has no -// associated name space, in contrast to the previous three where it -// is in the http://google.com/bar name space. -// -// The XML parser hides these details from the client by passing -// a Name struct (ns + name pair) for tag and attribute names. -// Tags and attributes without a name space have ns == "". -// -// References: -// Annotated XML spec: http://www.xml.com/axml/testaxml.htm -// XML name spaces: http://www.w3.org/TR/REC-xml-names/ - -package xml - -import ( - "io"; - "os"; -) - -// XML name, annotated with name space URL -type Name struct { - ns, name string; -} - -// XML attribute (name=value). -type Attr struct { - name Name; - value string; -} - -// XML Builder - methods client provides to Parser. -// Parser calls methods on builder as it reads and parses XML. -// If a builder method returns an error, the parse stops. -type Builder interface { - // Called when an element starts. - // Attr is list of attributes given in the tag. - // - // - // xmlns and xmlns:foo attributes are handled internally - // and not passed through to StartElement. - StartElement(name Name, attr []Attr) os.Error; - - // Called when an element ends. - // - // - EndElement(name Name) os.Error; - - // Called for non-empty character data string inside element. - // Can be called multiple times between elements. - // text - // - Text(text []byte) os.Error; - - // Called when a comment is found in the XML. - // - Comment(text []byte) os.Error; - - // Called for a processing instruction - // - ProcInst(target string, text []byte) os.Error; -} - -// Default builder. Implements no-op Builder methods. -// Embed this in your own Builders to handle the calls -// you don't care about (e.g., Comment, ProcInst). -type BaseBuilder struct { -} - -func (b *BaseBuilder) StartElement(name Name, attr []Attr) os.Error { - return nil; -} - -func (b *BaseBuilder) EndElement(name Name) os.Error { - return nil; -} - -func (b *BaseBuilder) Text(text []byte) os.Error { - return nil; -} - -func (b *BaseBuilder) Comment(text []byte) os.Error { - return nil; -} - -func (b *BaseBuilder) ProcInst(target string, text []byte) os.Error { - return nil; -} - -// XML Parser. Calls Builder methods as it parses. -func Parse(r io.Read, b Builder) os.Error { - return os.NewError("unimplemented"); -} - -// Channel interface to XML parser: create a new channel, -// go ParseTokens(r, c), and then read from the channel -// until TokenEnd. This variant has the benefit that -// the process reading the channel can be a recursive -// function instead of a set of callbacks, but it has the -// drawback that the channel interface cannot signal an -// error to cause the parser to stop early. - -// An XML parsing token. -const ( - TokenStartElement = 1 + iota; - TokenEndElement; - TokenText; - TokenComment; - TokenProcInst; - TokenEnd; -) - -type Token struct { - Kind int; // TokenStartElement, TokenEndElement, etc. - Name Name; // name (TokenStartElement, TokenEndElement) - Attr []Attr; // attributes (TokenStartElement) - Target string; // target (TokenProcessingInstruction) - Text []byte; // text (TokenCharData, TokenComment, etc.) - Err os.Error; // error (TokenEnd) -} - -type ChanBuilder chan Token; - -func (c ChanBuilder) StartElement(name Name, attr []Attr) os.Error { - var t Token; - t.Kind = TokenStartElement; - t.Name = name; - t.Attr = attr; - c <- t; - return nil; -} - -func (c ChanBuilder) EndElement(name Name) os.Error { - var t Token; - t.Kind = TokenEndElement; - t.Name = name; - c <- t; - return nil; -} - -func (c ChanBuilder) Text(text []byte) os.Error { - var t Token; - t.Kind = TokenText; - t.Text = text; - c <- t; - return nil; -} - -func (c ChanBuilder) Comment(text []byte) os.Error { - var t Token; - t.Kind = TokenComment; - t.Text = text; - c <- t; - return nil; -} - -func (c ChanBuilder) ProcInst(target string, text []byte) os.Error { - var t Token; - t.Kind = TokenProcInst; - t.Target = target; - t.Text = text; - c <- t; - return nil; -} - -func ParseToChan(r io.Read, c chan Token) { - var t Token; - t.Kind = TokenEnd; - t.Err = Parse(r, ChanBuilder(c)); - c <- t; -} - - -// scribbled notes based on XML spec. - -// document is -// xml decl? -// doctype decl? -// element -// -// if xml decl is present, must be first. after that, -// can have comments and procinsts scattered throughout, -// even after the element is done. -// -// xml decl is: -// -// <\?xml version='[a-zA-Z0-9_.:\-]+'( encoding='[A-Za-z][A-Za-z0-9._\-]*')? -// ( standalone='(yes|no)')? ?\?> -// -// spaces denote [ \r\t\n]+. -// written with '' above but can use "" too. -// -// doctype decl might as well be ]*> -// -// procinst is <\?name( .*?)\?>. name cannot be [Xx][Mm][Ll]. -// -// comment is . -// -// tags are: -// start tag -// combined start/end tag -// end tag -// (the " ?" is an optional space, not a literal question mark.) -// -// plain text is [^<&]* except cannot contain "]]>". -// can also have escaped characters: -// &#[0-9]+; -// &#x[0-9A-Fa-f]+; -// &name; -// -// can use to avoid escaping < characters. -// -// must rewrite \r and \r\n into \n in text. -// -// names are Unicode. valid chars listed below. -// -// attrib is name="value" or name='value'. -// can have spaces around =. -// attribute value text is [^<&"]* for appropriate ". -// can also use the &...; escape sequences above. -// cannot use . -// -// xmlns attributes are name=value where name has form xmlns:name -// (i.e., xmlns:123 is not okay, because 123 is not a name; xmlns:a123 is ok). -// sub-name must not start with : either. -// -// name is first(second)*. -// -// first is -// -// 003A 04D0-04EB 0A59-0A5C 0C35-0C39 0F49-0F69 1E00-1E9B -// 0041-005A 04EE-04F5 0A5E 0C60-0C61 10A0-10C5 1EA0-1EF9 -// 005F 04F8-04F9 0A72-0A74 0C85-0C8C 10D0-10F6 1F00-1F15 -// 0061-007A 0531-0556 0A85-0A8B 0C8E-0C90 1100 1F18-1F1D -// 00C0-00D6 0559 0A8D 0C92-0CA8 1102-1103 1F20-1F45 -// 00D8-00F6 0561-0586 0A8F-0A91 0CAA-0CB3 1105-1107 1F48-1F4D -// 00F8-00FF 05D0-05EA 0A93-0AA8 0CB5-0CB9 1109 1F50-1F57 -// 0100-0131 05F0-05F2 0AAA-0AB0 0CDE 110B-110C 1F59 -// 0134-013E 0621-063A 0AB2-0AB3 0CE0-0CE1 110E-1112 1F5B -// 0141-0148 0641-064A 0AB5-0AB9 0D05-0D0C 113C 1F5D -// 014A-017E 0671-06B7 0ABD 0D0E-0D10 113E 1F5F-1F7D -// 0180-01C3 06BA-06BE 0AE0 0D12-0D28 1140 1F80-1FB4 -// 01CD-01F0 06C0-06CE 0B05-0B0C 0D2A-0D39 114C 1FB6-1FBC -// 01F4-01F5 06D0-06D3 0B0F-0B10 0D60-0D61 114E 1FBE -// 01FA-0217 06D5 0B13-0B28 0E01-0E2E 1150 1FC2-1FC4 -// 0250-02A8 06E5-06E6 0B2A-0B30 0E30 1154-1155 1FC6-1FCC -// 02BB-02C1 0905-0939 0B32-0B33 0E32-0E33 1159 1FD0-1FD3 -// 0386 093D 0B36-0B39 0E40-0E45 115F-1161 1FD6-1FDB -// 0388-038A 0958-0961 0B3D 0E81-0E82 1163 1FE0-1FEC -// 038C 0985-098C 0B5C-0B5D 0E84 1165 1FF2-1FF4 -// 038E-03A1 098F-0990 0B5F-0B61 0E87-0E88 1167 1FF6-1FFC -// 03A3-03CE 0993-09A8 0B85-0B8A 0E8A 1169 2126 -// 03D0-03D6 09AA-09B0 0B8E-0B90 0E8D 116D-116E 212A-212B -// 03DA 09B2 0B92-0B95 0E94-0E97 1172-1173 212E -// 03DC 09B6-09B9 0B99-0B9A 0E99-0E9F 1175 2180-2182 -// 03DE 09DC-09DD 0B9C 0EA1-0EA3 119E 3007 -// 03E0 09DF-09E1 0B9E-0B9F 0EA5 11A8 3021-3029 -// 03E2-03F3 09F0-09F1 0BA3-0BA4 0EA7 11AB 3041-3094 -// 0401-040C 0A05-0A0A 0BA8-0BAA 0EAA-0EAB 11AE-11AF 30A1-30FA -// 040E-044F 0A0F-0A10 0BAE-0BB5 0EAD-0EAE 11B7-11B8 3105-312C -// 0451-045C 0A13-0A28 0BB7-0BB9 0EB0 11BA 4E00-9FA5 -// 045E-0481 0A2A-0A30 0C05-0C0C 0EB2-0EB3 11BC-11C2 AC00-D7A3 -// 0490-04C4 0A32-0A33 0C0E-0C10 0EBD 11EB -// 04C7-04C8 0A35-0A36 0C12-0C28 0EC0-0EC4 11F0 -// 04CB-04CC 0A38-0A39 0C2A-0C33 0F40-0F47 11F9 -// -// second is first plus -// -// 002D 06DD-06DF 09E6-09EF 0B56-0B57 0D3E-0D43 0F3E -// 002E 06E0-06E4 0A02 0B66-0B6F 0D46-0D48 0F3F -// 0030-0039 06E7-06E8 0A3C 0B82-0B83 0D4A-0D4D 0F71-0F84 -// 00B7 06EA-06ED 0A3E 0BBE-0BC2 0D57 0F86-0F8B -// 02D0 06F0-06F9 0A3F 0BC6-0BC8 0D66-0D6F 0F90-0F95 -// 02D1 0901-0903 0A40-0A42 0BCA-0BCD 0E31 0F97 -// 0300-0345 093C 0A47-0A48 0BD7 0E34-0E3A 0F99-0FAD -// 0360-0361 093E-094C 0A4B-0A4D 0BE7-0BEF 0E46 0FB1-0FB7 -// 0387 094D 0A66-0A6F 0C01-0C03 0E47-0E4E 0FB9 -// 0483-0486 0951-0954 0A70-0A71 0C3E-0C44 0E50-0E59 20D0-20DC -// 0591-05A1 0962-0963 0A81-0A83 0C46-0C48 0EB1 20E1 -// 05A3-05B9 0966-096F 0ABC 0C4A-0C4D 0EB4-0EB9 3005 -// 05BB-05BD 0981-0983 0ABE-0AC5 0C55-0C56 0EBB-0EBC 302A-302F -// 05BF 09BC 0AC7-0AC9 0C66-0C6F 0EC6 3031-3035 -// 05C1-05C2 09BE 0ACB-0ACD 0C82-0C83 0EC8-0ECD 3099 -// 05C4 09BF 0AE6-0AEF 0CBE-0CC4 0ED0-0ED9 309A -// 0640 09C0-09C4 0B01-0B03 0CC6-0CC8 0F18-0F19 309D-309E -// 064B-0652 09C7-09C8 0B3C 0CCA-0CCD 0F20-0F29 30FC-30FE -// 0660-0669 09CB-09CD 0B3E-0B43 0CD5-0CD6 0F35 -// 0670 09D7 0B47-0B48 0CE6-0CEF 0F37 -// 06D6-06DC 09E2-09E3 0B4B-0B4D 0D02-0D03 0F39 - diff --git a/src/make.bash b/src/make.bash index f6ee91ad0..841a136c7 100755 --- a/src/make.bash +++ b/src/make.bash @@ -18,7 +18,7 @@ rm -f $HOME/bin/quietgcc cp quietgcc.bash $HOME/bin/quietgcc chmod +x $HOME/bin/quietgcc -for i in lib9 libbio libmach_amd64 libregexp cmd lib cmd/gobuild +for i in lib9 libbio libmach_amd64 libregexp cmd pkg cmd/gobuild do echo; echo; echo %%%% making $i %%%%; echo cd $i diff --git a/src/pkg/Make.deps b/src/pkg/Make.deps new file mode 100644 index 000000000..dd83e8b1c --- /dev/null +++ b/src/pkg/Make.deps @@ -0,0 +1,52 @@ +archive/tar.install: bufio.install bytes.install io.install os.install strconv.install +bignum.install: fmt.install +bufio.install: io.install os.install utf8.install +bytes.install: utf8.install +compress/flate.install: bufio.install io.install os.install strconv.install +compress/gzip.install: bufio.install compress/flate.install hash.install hash/crc32.install io.install os.install +container/list.install: +container/vector.install: +crypto/aes.install: os.install +crypto/block.install: fmt.install io.install os.install +crypto/hmac.install: crypto/md5.install crypto/sha1.install hash.install os.install +crypto/md5.install: hash.install os.install +crypto/sha1.install: hash.install os.install +datafmt.install: container/vector.install fmt.install go/scanner.install go/token.install io.install os.install reflect.install runtime.install strconv.install strings.install +exec.install: os.install strings.install +exvar.install: fmt.install http.install io.install log.install strconv.install sync.install +flag.install: fmt.install os.install strconv.install +fmt.install: io.install os.install reflect.install strconv.install utf8.install +go/ast.install: datafmt.install go/token.install io.install os.install unicode.install utf8.install +go/doc.install: container/vector.install fmt.install go/ast.install go/token.install io.install once.install regexp.install sort.install strings.install template.install +go/parser.install: container/vector.install fmt.install go/ast.install go/scanner.install go/token.install io.install os.install +go/scanner.install: go/token.install strconv.install unicode.install utf8.install +go/token.install: strconv.install +hash.install: io.install +hash/adler32.install: hash.install os.install +hash/crc32.install: hash.install os.install +http.install: bufio.install fmt.install io.install log.install net.install os.install path.install strconv.install strings.install utf8.install +io.install: bytes.install os.install sync.install +json.install: container/vector.install fmt.install io.install math.install reflect.install strconv.install strings.install utf8.install +log.install: fmt.install io.install os.install runtime.install time.install +malloc.install: +math.install: +net.install: fmt.install io.install once.install os.install reflect.install strconv.install strings.install sync.install syscall.install +once.install: sync.install +os.install: once.install syscall.install +path.install: io.install +rand.install: +reflect.install: strconv.install sync.install utf8.install +regexp.install: container/vector.install os.install runtime.install utf8.install +runtime.install: +sort.install: +strconv.install: bytes.install math.install os.install utf8.install +strings.install: utf8.install +sync.install: +syscall.install: sync.install +tabwriter.install: container/vector.install io.install os.install utf8.install +template.install: container/vector.install fmt.install io.install os.install reflect.install runtime.install strings.install +testing.install: flag.install fmt.install os.install regexp.install runtime.install +testing/iotest.install: io.install log.install os.install +time.install: io.install once.install os.install syscall.install +unicode.install: +utf8.install: diff --git a/src/pkg/Makefile b/src/pkg/Makefile new file mode 100644 index 000000000..036a82e38 --- /dev/null +++ b/src/pkg/Makefile @@ -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. + +# 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. + +all: install + +DIRS=\ + archive/tar\ + bignum\ + bufio\ + bytes\ + compress/flate\ + compress/gzip\ + container/list\ + container/vector\ + crypto/aes\ + crypto/block\ + crypto/hmac\ + crypto/md5\ + crypto/sha1\ + datafmt\ + exec\ + exvar\ + flag\ + fmt\ + go/ast\ + go/doc\ + go/parser\ + go/scanner\ + go/token\ + hash\ + hash/adler32\ + hash/crc32\ + http\ + io\ + json\ + log\ + malloc\ + math\ + net\ + once\ + os\ + path\ + rand\ + reflect\ + regexp\ + runtime\ + sort\ + strconv\ + strings\ + sync\ + syscall\ + tabwriter\ + template\ + testing\ + testing/iotest\ + time\ + unicode\ + utf8\ + +TEST=\ + archive/tar\ + bignum\ + bufio\ + compress/flate\ + compress/gzip\ + container/list\ + container/vector\ + crypto/aes\ + crypto/block\ + crypto/md5\ + crypto/sha1\ + datafmt\ + exec\ + exvar\ + flag\ + fmt\ + go/parser\ + go/scanner\ + hash/adler32\ + hash/crc32\ + http\ + io\ + json\ + log\ + math\ + net\ + once\ + os\ + path\ + reflect\ + regexp\ + sort\ + strconv\ + strings\ + sync\ + tabwriter\ + template\ + time\ + unicode\ + utf8\ + +clean.dirs: $(addsuffix .clean, $(DIRS)) +install.dirs: $(addsuffix .install, $(DIRS)) +nuke.dirs: $(addsuffix .nuke, $(DIRS)) +test.dirs: $(addsuffix .test, $(TEST)) + +%.clean: + +cd $* && make clean + +%.install: + +cd $* && make install + +%.nuke: + +cd $* && make nuke + +%.test: + +cd $* && make test + +clean: clean.dirs + +install: install.dirs + +test: test.dirs + +nuke: nuke.dirs + rm -rf $(GOROOT)/pkg/* + +deps: + ./deps.bash + +include Make.deps diff --git a/src/pkg/archive/tar/Makefile b/src/pkg/archive/tar/Makefile new file mode 100644 index 000000000..579ed4c35 --- /dev/null +++ b/src/pkg/archive/tar/Makefile @@ -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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D=/archive/ + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + untar.$O\ + + +phases: a1 +_obj$D/tar.a: phases + +a1: $(O1) + $(AR) grc _obj$D/tar.a untar.$O + rm -f $(O1) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/tar.a + +$(O1): newpkg +$(O2): a1 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/tar.a + +packages: _obj$D/tar.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/tar.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/tar.a 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/test.tar b/src/pkg/archive/tar/testdata/test.tar new file mode 100644 index 000000000..fc899dc8d Binary files /dev/null and b/src/pkg/archive/tar/testdata/test.tar differ diff --git a/src/pkg/archive/tar/untar.go b/src/pkg/archive/tar/untar.go new file mode 100644 index 000000000..300c0f932 --- /dev/null +++ b/src/pkg/archive/tar/untar.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. + +// The tar package implements access to tar archives. +// It aims to cover most of the variations, including those produced +// by GNU and BSD tars (not yet started). +// +// 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 + +// TODO(dsymonds): +// - Make it seekable. +// - Extensions. + +import ( + "bufio"; + "bytes"; + "io"; + "os"; + "strconv"; +) + +var ( + HeaderError os.Error = os.ErrorString("invalid tar header"); +) + +// A tar archive consists of a sequence of files. +// A Reader provides sequential access to the contents of a tar archive. +// 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 := NewTarReader(r); +// for { +// hdr, err := tr.Next(); +// if err != nil { +// // handle error +// } +// if hdr == nil { +// // end of tar archive +// break +// } +// io.Copy(tr, somewhere); +// } +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 +} + +// A Header represents a single header in a tar archive. +// Only some fields may be populated. +type Header struct { + Name string; + Mode int64; + Uid int64; + Gid int64; + Size int64; + Mtime int64; + Typeflag byte; + Linkname string; + Uname string; + Gname string; + Devmajor int64; + Devminor int64; +} + +func (tr *Reader) skipUnread() +func (tr *Reader) readHeader() *Header + +// NewReader creates a new Reader reading the given io.Reader. +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 +} + +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'; +) + +var zeroBlock = make([]byte, blockSize); + +// 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) octalNumber(b []byte) int64 { + x, err := strconv.Btoui64(cString(b), 8); + if err != nil { + tr.err = err; + } + return int64(x) +} + +type ignoreWriter struct {} +func (ignoreWriter) Write(b []byte) (n int, err os.Error) { + return len(b), nil +} + +type seeker interface { + Seek(offset int64, whence int) (ret int64, err os.Error); +} + +// 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 + + var n int64; + if sr, ok := tr.r.(seeker); ok { + n, tr.err = sr.Seek(nr, 1); + } else { + n, tr.err = io.Copyn(tr.r, ignoreWriter{}, nr); + } + tr.nb, tr.pad = 0, 0; +} + +func (tr *Reader) verifyChecksum(header []byte) bool { + given := tr.octalNumber(header[148:156]); + if tr.err != nil { + return false + } + + var computed int64; + for i := 0; i < len(header); i++ { + if i == 148 { + // The chksum field is special: it should be treated as space bytes. + computed += ' ' * 8; + i += 7; + continue + } + computed += int64(header[i]); + } + + return given == computed +} + +type slicer []byte +func (s *slicer) next(n int) (b []byte) { + b, *s = s[0:n], s[n:len(s)]; + return +} + +func (tr *Reader) readHeader() *Header { + header := make([]byte, blockSize); + var n int; + if n, tr.err = io.FullRead(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 n, tr.err = io.FullRead(tr.r, header); tr.err != nil { + return nil + } + if !bytes.Equal(header, zeroBlock[0:blockSize]) { + tr.err = HeaderError; + } + return nil + } + + if !tr.verifyChecksum(header) { + tr.err = HeaderError; + return nil + } + + // Unpack + hdr := new(Header); + s := slicer(header); + + // TODO(dsymonds): The format of the header depends on the value of magic (hdr[257:262]), + // so use that value to do the correct parsing below. + + hdr.Name = cString(s.next(100)); + hdr.Mode = tr.octalNumber(s.next(8)); + hdr.Uid = tr.octalNumber(s.next(8)); + hdr.Gid = tr.octalNumber(s.next(8)); + hdr.Size = tr.octalNumber(s.next(12)); + hdr.Mtime = tr.octalNumber(s.next(12)); + s.next(8); // chksum + hdr.Typeflag = s.next(1)[0]; + hdr.Linkname = cString(s.next(100)); + s.next(8); // magic, version + + 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, nil when it reaches the end of that entry, +// until Next is called to advance to the next entry. +func (tr *Reader) Read(b []uint8) (n int, err os.Error) { + if int64(len(b)) > tr.nb { + b = b[0:tr.nb]; + } + n, err = tr.r.Read(b); + tr.nb -= int64(n); + tr.err = err; + return +} diff --git a/src/pkg/archive/tar/untar_test.go b/src/pkg/archive/tar/untar_test.go new file mode 100644 index 000000000..a9c92dbf0 --- /dev/null +++ b/src/pkg/archive/tar/untar_test.go @@ -0,0 +1,69 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package tar + +import ( + "archive/tar"; + "bytes"; + "fmt"; + "io"; + "os"; + "testing"; +) + +func TestUntar(t *testing.T) { + f, err := os.Open("testdata/test.tar", os.O_RDONLY, 0444); + if err != nil { + t.Fatalf("Unexpected error: %v", err); + } + defer f.Close(); + + tr := NewReader(f); + + // First file + hdr, err := tr.Next(); + if err != nil || hdr == nil { + t.Fatalf("Didn't get first file: %v", err); + } + if hdr.Name != "small.txt" { + t.Errorf(`hdr.Name = %q, want "small.txt"`, hdr.Name); + } + if hdr.Mode != 0640 { + t.Errorf("hdr.Mode = %v, want 0640", hdr.Mode); + } + if hdr.Size != 5 { + t.Errorf("hdr.Size = %v, want 5", hdr.Size); + } + + // Read the first four bytes; Next() should skip the last one. + buf := make([]byte, 4); + if n, err := io.FullRead(tr, buf); err != nil { + t.Fatalf("Unexpected error: %v", err); + } + if expected := io.StringBytes("Kilt"); !bytes.Equal(buf, expected) { + t.Errorf("Contents = %v, want %v", buf, expected); + } + + // Second file + hdr, err = tr.Next(); + if err != nil { + t.Fatalf("Didn't get second file: %v", err); + } + if hdr.Name != "small2.txt" { + t.Errorf(`hdr.Name = %q, want "small2.txt"`, hdr.Name); + } + if hdr.Mode != 0640 { + t.Errorf("hdr.Mode = %v, want 0640", hdr.Mode); + } + if hdr.Size != 11 { + t.Errorf("hdr.Size = %v, want 11", hdr.Size); + } + + + hdr, err = tr.Next(); + if hdr != nil || err != nil { + t.Fatalf("Unexpected third file or error: %v", err); + } +} diff --git a/src/pkg/bignum/Makefile b/src/pkg/bignum/Makefile new file mode 100644 index 000000000..098b90975 --- /dev/null +++ b/src/pkg/bignum/Makefile @@ -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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D= + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + bignum.$O\ + + +phases: a1 +_obj$D/bignum.a: phases + +a1: $(O1) + $(AR) grc _obj$D/bignum.a bignum.$O + rm -f $(O1) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/bignum.a + +$(O1): newpkg +$(O2): a1 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/bignum.a + +packages: _obj$D/bignum.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/bignum.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/bignum.a diff --git a/src/pkg/bignum/bignum.go b/src/pkg/bignum/bignum.go new file mode 100755 index 000000000..b9ea66587 --- /dev/null +++ b/src/pkg/bignum/bignum.go @@ -0,0 +1,1464 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// A package for arbitrary precision arithmethic. +// It implements the following numeric types: +// +// - Natural unsigned integers +// - Integer signed integers +// - Rational rational numbers +// +package bignum + +import "fmt" + + +// ---------------------------------------------------------------------------- +// Internal representation +// +// A natural number of the form +// +// x = x[n-1]*B^(n-1) + x[n-2]*B^(n-2) + ... + x[1]*B + x[0] +// +// with 0 <= x[i] < B and 0 <= i < n is stored in a slice of length n, +// with the digits x[i] as the slice elements. +// +// A natural number is normalized if the slice contains no leading 0 digits. +// During arithmetic operations, denormalized values may occur but are +// always normalized before returning the final result. The normalized +// representation of 0 is the empty slice (length = 0). +// +// The operations for all other numeric types are implemented on top of +// the operations for natural numbers. +// +// The base B is chosen as large as possible on a given platform but there +// are a few constraints besides the size of the largest unsigned integer +// type available: +// +// 1) To improve conversion speed between strings and numbers, the base B +// is chosen such that division and multiplication by 10 (for decimal +// string representation) can be done without using extended-precision +// arithmetic. This makes addition, subtraction, and conversion routines +// twice as fast. It requires a ``buffer'' of 4 bits per operand digit. +// That is, the size of B must be 4 bits smaller then the size of the +// type (digit) in which these operations are performed. Having this +// buffer also allows for trivial (single-bit) carry computation in +// addition and subtraction (optimization suggested by Ken Thompson). +// +// 2) Long division requires extended-precision (2-digit) division per digit. +// Instead of sacrificing the largest base type for all other operations, +// for division the operands are unpacked into ``half-digits'', and the +// results are packed again. For faster unpacking/packing, the base size +// in bits must be even. + +type ( + digit uint64; + digit2 uint32; // half-digits for division +) + + +const ( + _LogW = 64; + _LogH = 4; // bits for a hex digit (= small number) + _LogB = _LogW - _LogH; // largest bit-width available + + // half-digits + _W2 = _LogB / 2; // width + _B2 = 1 << _W2; // base + _M2 = _B2 - 1; // mask + + // full digits + _W = _W2 * 2; // width + _B = 1 << _W; // base + _M = _B - 1; // mask +) + + +// ---------------------------------------------------------------------------- +// Support functions + +func assert(p bool) { + if !p { + panic("assert failed"); + } +} + + +func isSmall(x digit) bool { + return x < 1<<_LogH; +} + + +// For debugging. +func dump(x []digit) { + print("[", len(x), "]"); + for i := len(x) - 1; i >= 0; i-- { + print(" ", x[i]); + } + println(); +} + + +// ---------------------------------------------------------------------------- +// Natural numbers + +// Natural represents an unsigned integer value of arbitrary precision. +// +type Natural []digit; + +var ( + natZero Natural = Natural{}; + natOne Natural = Natural{1}; + natTwo Natural = Natural{2}; + natTen Natural = Natural{10}; +) + + +// Nat creates a small natural number with value x. +// Implementation restriction: At the moment, only values +// x < (1<<60) are supported. +// +func Nat(x uint) Natural { + switch x { + case 0: return natZero; + case 1: return natOne; + case 2: return natTwo; + case 10: return natTen; + } + assert(digit(x) < _B); + return Natural{digit(x)}; +} + + +// IsEven returns true iff x is divisible by 2. +// +func (x Natural) IsEven() bool { + return len(x) == 0 || x[0]&1 == 0; +} + + +// IsOdd returns true iff x is not divisible by 2. +// +func (x Natural) IsOdd() bool { + return len(x) > 0 && x[0]&1 != 0; +} + + +// IsZero returns true iff x == 0. +// +func (x Natural) IsZero() bool { + return len(x) == 0; +} + + +// Operations +// +// Naming conventions +// +// c carry +// x, y operands +// z result +// n, m len(x), len(y) + +func normalize(x Natural) Natural { + n := len(x); + for n > 0 && x[n - 1] == 0 { n-- } + if n < len(x) { + x = x[0 : n]; // trim leading 0's + } + return x; +} + + +// Add returns the sum x + y. +// +func (x Natural) Add(y Natural) Natural { + n := len(x); + m := len(y); + if n < m { + return y.Add(x); + } + + c := digit(0); + z := make(Natural, n + 1); + i := 0; + for i < m { + t := c + x[i] + y[i]; + c, z[i] = t>>_W, t&_M; + i++; + } + for i < n { + t := c + x[i]; + c, z[i] = t>>_W, t&_M; + i++; + } + if c != 0 { + z[i] = c; + i++; + } + + return z[0 : i]; +} + + +// Sub returns the difference x - y for x >= y. +// If x < y, an underflow run-time error occurs (use Cmp to test if x >= y). +// +func (x Natural) Sub(y Natural) Natural { + n := len(x); + m := len(y); + if n < m { + panic("underflow") + } + + c := digit(0); + z := make(Natural, n); + i := 0; + for i < m { + t := c + x[i] - y[i]; + c, z[i] = digit(int64(t)>>_W), t&_M; // requires arithmetic shift! + i++; + } + for i < n { + t := c + x[i]; + c, z[i] = digit(int64(t)>>_W), t&_M; // requires arithmetic shift! + i++; + } + for i > 0 && z[i - 1] == 0 { // normalize + i--; + } + + return z[0 : i]; +} + + +// Returns c = x*y div B, z = x*y mod B. +// +func mul11(x, y digit) (digit, digit) { + // Split x and y into 2 sub-digits each, + // multiply the digits separately while avoiding overflow, + // and return the product as two separate digits. + + // This code also works for non-even bit widths W + // which is why there are separate constants below + // for half-digits. + const W2 = (_W + 1)/2; + const DW = W2*2 - _W; // 0 or 1 + const B2 = 1<>W2, x&M2; + y1, y0 := y>>W2, y&M2; + + // x*y = t2*B2^2 + t1*B2 + t0 + t0 := x0*y0; + t1 := x1*y0 + x0*y1; + t2 := x1*y1; + + // compute the result digits but avoid overflow + // z = z1*B + z0 = x*y + z0 := (t1<>W2)>>(_W-W2); + + return z1, z0; +} + + +// Mul returns the product x * y. +// +func (x Natural) Mul(y Natural) Natural { + n := len(x); + m := len(y); + + z := make(Natural, n + m); + for j := 0; j < m; j++ { + d := y[j]; + if d != 0 { + c := digit(0); + for i := 0; i < n; i++ { + // z[i+j] += c + x[i]*d; + z1, z0 := mul11(x[i], d); + t := c + z[i+j] + z0; + c, z[i+j] = t>>_W, t&_M; + c += z1; + } + z[n+j] = c; + } + } + + return normalize(z); +} + + +// DivMod needs multi-precision division, which is not available if digit +// is already using the largest uint size. Instead, unpack each operand +// into operands with twice as many digits of half the size (digit2), do +// DivMod, and then pack the results again. + +func unpack(x Natural) []digit2 { + n := len(x); + z := make([]digit2, n*2 + 1); // add space for extra digit (used by DivMod) + for i := 0; i < n; i++ { + t := x[i]; + z[i*2] = digit2(t & _M2); + z[i*2 + 1] = digit2(t >> _W2 & _M2); + } + + // normalize result + k := 2*n; + for k > 0 && z[k - 1] == 0 { k-- } + return z[0 : k]; // trim leading 0's +} + + +func pack(x []digit2) Natural { + n := (len(x) + 1) / 2; + z := make(Natural, n); + if len(x) & 1 == 1 { + // handle odd len(x) + n--; + z[n] = digit(x[n*2]); + } + for i := 0; i < n; i++ { + z[i] = digit(x[i*2 + 1]) << _W2 | digit(x[i*2]); + } + return normalize(z); +} + + +func mul1(z, x []digit2, y digit2) digit2 { + n := len(x); + c := digit(0); + f := digit(y); + for i := 0; i < n; i++ { + t := c + digit(x[i])*f; + c, z[i] = t>>_W2, digit2(t&_M2); + } + return digit2(c); +} + + +func div1(z, x []digit2, y digit2) digit2 { + n := len(x); + c := digit(0); + d := digit(y); + for i := n-1; i >= 0; i-- { + t := c*_B2 + digit(x[i]); + c, z[i] = t%d, digit2(t/d); + } + return digit2(c); +} + + +// divmod returns q and r with x = y*q + r and 0 <= r < y. +// x and y are destroyed in the process. +// +// The algorithm used here is based on 1). 2) describes the same algorithm +// in C. A discussion and summary of the relevant theorems can be found in +// 3). 3) also describes an easier way to obtain the trial digit - however +// it relies on tripple-precision arithmetic which is why Knuth's method is +// used here. +// +// 1) D. Knuth, The Art of Computer Programming. Volume 2. Seminumerical +// Algorithms. Addison-Wesley, Reading, 1969. +// (Algorithm D, Sec. 4.3.1) +// +// 2) Henry S. Warren, Jr., Hacker's Delight. Addison-Wesley, 2003. +// (9-2 Multiword Division, p.140ff) +// +// 3) P. Brinch Hansen, ``Multiple-length division revisited: A tour of the +// minefield''. Software - Practice and Experience 24, (June 1994), +// 579-601. John Wiley & Sons, Ltd. + +func divmod(x, y []digit2) ([]digit2, []digit2) { + n := len(x); + m := len(y); + if m == 0 { + panic("division by zero"); + } + assert(n+1 <= cap(x)); // space for one extra digit + x = x[0 : n + 1]; + assert(x[n] == 0); + + if m == 1 { + // division by single digit + // result is shifted left by 1 in place! + x[0] = div1(x[1 : n+1], x[0 : n], y[0]); + + } else if m > n { + // y > x => quotient = 0, remainder = x + // TODO in this case we shouldn't even unpack x and y + m = n; + + } else { + // general case + assert(2 <= m && m <= n); + + // normalize x and y + // TODO Instead of multiplying, it would be sufficient to + // shift y such that the normalization condition is + // satisfied (as done in Hacker's Delight). + f := _B2 / (digit(y[m-1]) + 1); + if f != 1 { + mul1(x, x, digit2(f)); + mul1(y, y, digit2(f)); + } + assert(_B2/2 <= y[m-1] && y[m-1] < _B2); // incorrect scaling + + y1, y2 := digit(y[m-1]), digit(y[m-2]); + d2 := digit(y1)<<_W2 + digit(y2); + for i := n-m; i >= 0; i-- { + k := i+m; + + // compute trial digit (Knuth) + var q digit; + { x0, x1, x2 := digit(x[k]), digit(x[k-1]), digit(x[k-2]); + if x0 != y1 { + q = (x0<<_W2 + x1)/y1; + } else { + q = _B2 - 1; + } + for y2*q > (x0<<_W2 + x1 - y1*q)<<_W2 + x2 { + q-- + } + } + + // subtract y*q + c := digit(0); + for j := 0; j < m; j++ { + t := c + digit(x[i+j]) - digit(y[j])*q; + c, x[i+j] = digit(int64(t) >> _W2), digit2(t & _M2); // requires arithmetic shift! + } + + // correct if trial digit was too large + if c + digit(x[k]) != 0 { + // add y + c := digit(0); + for j := 0; j < m; j++ { + t := c + digit(x[i+j]) + digit(y[j]); + c, x[i+j] = t >> _W2, digit2(t & _M2) + } + assert(c + digit(x[k]) == 0); + // correct trial digit + q--; + } + + x[k] = digit2(q); + } + + // undo normalization for remainder + if f != 1 { + c := div1(x[0 : m], x[0 : m], digit2(f)); + assert(c == 0); + } + } + + return x[m : n+1], x[0 : m]; +} + + +// Div returns the quotient q = x / y for y > 0, +// with x = y*q + r and 0 <= r < y. +// If y == 0, a division-by-zero run-time error occurs. +// +func (x Natural) Div(y Natural) Natural { + q, r := divmod(unpack(x), unpack(y)); + return pack(q); +} + + +// Mod returns the modulus r of the division x / y for y > 0, +// with x = y*q + r and 0 <= r < y. +// If y == 0, a division-by-zero run-time error occurs. +// +func (x Natural) Mod(y Natural) Natural { + q, r := divmod(unpack(x), unpack(y)); + return pack(r); +} + + +// DivMod returns the pair (x.Div(y), x.Mod(y)) for y > 0. +// If y == 0, a division-by-zero run-time error occurs. +// +func (x Natural) DivMod(y Natural) (Natural, Natural) { + q, r := divmod(unpack(x), unpack(y)); + return pack(q), pack(r); +} + + +func shl(z, x []digit, s uint) digit { + assert(s <= _W); + n := len(x); + c := digit(0); + for i := 0; i < n; i++ { + c, z[i] = x[i] >> (_W-s), x[i] << s & _M | c; + } + return c; +} + + +// Shl implements ``shift left'' x << s. It returns x * 2^s. +// +func (x Natural) Shl(s uint) Natural { + n := uint(len(x)); + m := n + s/_W; + z := make(Natural, m+1); + + z[m] = shl(z[m-n : m], x, s%_W); + + return normalize(z); +} + + +func shr(z, x []digit, s uint) digit { + assert(s <= _W); + n := len(x); + c := digit(0); + for i := n - 1; i >= 0; i-- { + c, z[i] = x[i] << (_W-s) & _M, x[i] >> s | c; + } + return c; +} + + +// Shr implements ``shift right'' x >> s. It returns x / 2^s. +// +func (x Natural) Shr(s uint) Natural { + n := uint(len(x)); + m := n - s/_W; + if m > n { // check for underflow + m = 0; + } + z := make(Natural, m); + + shr(z, x[n-m : n], s%_W); + + return normalize(z); +} + + +// And returns the ``bitwise and'' x & y for the binary representation of x and y. +// +func (x Natural) And(y Natural) Natural { + n := len(x); + m := len(y); + if n < m { + return y.And(x); + } + + z := make(Natural, m); + for i := 0; i < m; i++ { + z[i] = x[i] & y[i]; + } + // upper bits are 0 + + return normalize(z); +} + + +func copy(z, x []digit) { + for i, e := range x { + z[i] = e + } +} + + +// Or returns the ``bitwise or'' x | y for the binary representation of x and y. +// +func (x Natural) Or(y Natural) Natural { + n := len(x); + m := len(y); + if n < m { + return y.Or(x); + } + + z := make(Natural, n); + for i := 0; i < m; i++ { + z[i] = x[i] | y[i]; + } + copy(z[m : n], x[m : n]); + + return z; +} + + +// Xor returns the ``bitwise exclusive or'' x ^ y for the binary representation of x and y. +// +func (x Natural) Xor(y Natural) Natural { + n := len(x); + m := len(y); + if n < m { + return y.Xor(x); + } + + z := make(Natural, n); + for i := 0; i < m; i++ { + z[i] = x[i] ^ y[i]; + } + copy(z[m : n], x[m : n]); + + return normalize(z); +} + + +// Cmp compares x and y. The result is an int value +// +// < 0 if x < y +// == 0 if x == y +// > 0 if x > y +// +func (x Natural) Cmp(y Natural) int { + n := len(x); + m := len(y); + + if n != m || n == 0 { + return n - m; + } + + i := n - 1; + for i > 0 && x[i] == y[i] { i--; } + + d := 0; + switch { + case x[i] < y[i]: d = -1; + case x[i] > y[i]: d = 1; + } + + return d; +} + + +func log2(x digit) uint { + assert(x > 0); + n := uint(0); + for x > 0 { + x >>= 1; + n++; + } + return n - 1; +} + + +// Log2 computes the binary logarithm of x for x > 0. +// The result is the integer n for which 2^n <= x < 2^(n+1). +// If x == 0 a run-time error occurs. +// +func (x Natural) Log2() uint { + n := len(x); + if n > 0 { + return (uint(n) - 1)*_W + log2(x[n - 1]); + } + panic("Log2(0)"); +} + + +// Computes x = x div d in place (modifies x) for small d's. +// Returns updated x and x mod d. +// +func divmod1(x Natural, d digit) (Natural, digit) { + assert(0 < d && isSmall(d - 1)); + + c := digit(0); + for i := len(x) - 1; i >= 0; i-- { + t := c<<_W + x[i]; + c, x[i] = t%d, t/d; + } + + return normalize(x), c; +} + + +// ToString converts x to a string for a given base, with 2 <= base <= 16. +// +func (x Natural) ToString(base uint) string { + if len(x) == 0 { + return "0"; + } + + // allocate buffer for conversion + assert(2 <= base && base <= 16); + n := (x.Log2() + 1) / log2(digit(base)) + 1; // +1: round up + s := make([]byte, n); + + // don't destroy x + t := make(Natural, len(x)); + copy(t, x); + + // convert + i := n; + for !t.IsZero() { + i--; + var d digit; + t, d = divmod1(t, digit(base)); + s[i] = "0123456789abcdef"[d]; + }; + + return string(s[i : n]); +} + + +// String converts x to its decimal string representation. +// x.String() is the same as x.ToString(10). +// +func (x Natural) String() string { + return x.ToString(10); +} + + +func fmtbase(c int) uint { + switch c { + case 'b': return 2; + case 'o': return 8; + case 'x': return 16; + } + return 10; +} + + +// Format is a support routine for fmt.Formatter. It accepts +// the formats 'b' (binary), 'o' (octal), and 'x' (hexadecimal). +// +func (x Natural) Format(h fmt.Formatter, c int) { + fmt.Fprintf(h, "%s", x.ToString(fmtbase(c))); +} + + +func hexvalue(ch byte) uint { + d := uint(1 << _LogH); + switch { + case '0' <= ch && ch <= '9': d = uint(ch - '0'); + case 'a' <= ch && ch <= 'f': d = uint(ch - 'a') + 10; + case 'A' <= ch && ch <= 'F': d = uint(ch - 'A') + 10; + } + return d; +} + + +// Computes x = x*d + c for small d's. +// +func muladd1(x Natural, d, c digit) Natural { + assert(isSmall(d-1) && isSmall(c)); + n := len(x); + z := make(Natural, n + 1); + + for i := 0; i < n; i++ { + t := c + x[i]*d; + c, z[i] = t>>_W, t&_M; + } + z[n] = c; + + return normalize(z); +} + + +// NatFromString returns the natural number corresponding to the +// longest possible prefix of s representing a natural number in a +// given conversion base, the actual conversion base used, and the +// prefix length. +// +// If the base argument is 0, the string prefix determines the actual +// conversion base. A prefix of ``0x'' or ``0X'' selects base 16; the +// ``0'' prefix selects base 8. Otherwise the selected base is 10. +// +func NatFromString(s string, base uint) (Natural, uint, int) { + // determine base if necessary + i, n := 0, len(s); + if base == 0 { + base = 10; + if n > 0 && s[0] == '0' { + if n > 1 && (s[1] == 'x' || s[1] == 'X') { + base, i = 16, 2; + } else { + base, i = 8, 1; + } + } + } + + // convert string + assert(2 <= base && base <= 16); + x := Nat(0); + for ; i < n; i++ { + d := hexvalue(s[i]); + if d < base { + x = muladd1(x, digit(base), digit(d)); + } else { + break; + } + } + + return x, base, i; +} + + +// Natural number functions + +func pop1(x digit) uint { + n := uint(0); + for x != 0 { + x &= x-1; + n++; + } + return n; +} + + +// Pop computes the ``population count'' of (the number of 1 bits in) x. +// +func (x Natural) Pop() uint { + n := uint(0); + for i := len(x) - 1; i >= 0; i-- { + n += pop1(x[i]); + } + return n; +} + + +// Pow computes x to the power of n. +// +func (xp Natural) Pow(n uint) Natural { + z := Nat(1); + x := xp; + for n > 0 { + // z * x^n == x^n0 + if n&1 == 1 { + z = z.Mul(x); + } + x, n = x.Mul(x), n/2; + } + return z; +} + + +// MulRange computes the product of all the unsigned integers +// in the range [a, b] inclusively. +// +func MulRange(a, b uint) Natural { + switch { + case a > b: return Nat(1); + case a == b: return Nat(a); + case a + 1 == b: return Nat(a).Mul(Nat(b)); + } + m := (a + b)>>1; + assert(a <= m && m < b); + return MulRange(a, m).Mul(MulRange(m + 1, b)); +} + + +// Fact computes the factorial of n (Fact(n) == MulRange(2, n)). +// +func Fact(n uint) Natural { + // Using MulRange() instead of the basic for-loop + // lead to faster factorial computation. + return MulRange(2, n); +} + + +// Binomial computes the binomial coefficient of (n, k). +// +func Binomial(n, k uint) Natural { + return MulRange(n-k+1, n).Div(MulRange(1, k)); +} + + +// Gcd computes the gcd of x and y. +// +func (x Natural) Gcd(y Natural) Natural { + // Euclidean algorithm. + a, b := x, y; + for !b.IsZero() { + a, b = b, a.Mod(b); + } + return a; +} + + +// ---------------------------------------------------------------------------- +// Integer numbers +// +// Integers are normalized if the mantissa is normalized and the sign is +// false for mant == 0. Use MakeInt to create normalized Integers. + +// Integer represents a signed integer value of arbitrary precision. +// +type Integer struct { + sign bool; + mant Natural; +} + + +// MakeInt makes an integer given a sign and a mantissa. +// The number is positive (>= 0) if sign is false or the +// mantissa is zero; it is negative otherwise. +// +func MakeInt(sign bool, mant Natural) *Integer { + if mant.IsZero() { + sign = false; // normalize + } + return &Integer{sign, mant}; +} + + +// Int creates a small integer with value x. +// Implementation restriction: At the moment, only values +// with an absolute value |x| < (1<<60) are supported. +// +func Int(x int) *Integer { + sign := false; + var ux uint; + if x < 0 { + sign = true; + if -x == x { + // smallest negative integer + t := ^0; + ux = ^(uint(t) >> 1); + } else { + ux = uint(-x); + } + } else { + ux = uint(x); + } + return MakeInt(sign, Nat(ux)); +} + + +// Predicates + +// IsEven returns true iff x is divisible by 2. +// +func (x *Integer) IsEven() bool { + return x.mant.IsEven(); +} + + +// IsOdd returns true iff x is not divisible by 2. +// +func (x *Integer) IsOdd() bool { + return x.mant.IsOdd(); +} + + +// IsZero returns true iff x == 0. +// +func (x *Integer) IsZero() bool { + return x.mant.IsZero(); +} + + +// IsNeg returns true iff x < 0. +// +func (x *Integer) IsNeg() bool { + return x.sign && !x.mant.IsZero() +} + + +// IsPos returns true iff x >= 0. +// +func (x *Integer) IsPos() bool { + return !x.sign && !x.mant.IsZero() +} + + +// Operations + +// Neg returns the negated value of x. +// +func (x *Integer) Neg() *Integer { + return MakeInt(!x.sign, x.mant); +} + + +// Add returns the sum x + y. +// +func (x *Integer) Add(y *Integer) *Integer { + var z *Integer; + if x.sign == y.sign { + // x + y == x + y + // (-x) + (-y) == -(x + y) + z = MakeInt(x.sign, x.mant.Add(y.mant)); + } else { + // x + (-y) == x - y == -(y - x) + // (-x) + y == y - x == -(x - y) + if x.mant.Cmp(y.mant) >= 0 { + z = MakeInt(false, x.mant.Sub(y.mant)); + } else { + z = MakeInt(true, y.mant.Sub(x.mant)); + } + } + if x.sign { + z.sign = !z.sign; + } + return z; +} + + +// Sub returns the difference x - y. +// +func (x *Integer) Sub(y *Integer) *Integer { + var z *Integer; + if x.sign != y.sign { + // x - (-y) == x + y + // (-x) - y == -(x + y) + z = MakeInt(false, x.mant.Add(y.mant)); + } else { + // x - y == x - y == -(y - x) + // (-x) - (-y) == y - x == -(x - y) + if x.mant.Cmp(y.mant) >= 0 { + z = MakeInt(false, x.mant.Sub(y.mant)); + } else { + z = MakeInt(true, y.mant.Sub(x.mant)); + } + } + if x.sign { + z.sign = !z.sign; + } + return z; +} + + +// Mul returns the product x * y. +// +func (x *Integer) Mul(y *Integer) *Integer { + // x * y == x * y + // x * (-y) == -(x * y) + // (-x) * y == -(x * y) + // (-x) * (-y) == x * y + return MakeInt(x.sign != y.sign, x.mant.Mul(y.mant)); +} + + +// MulNat returns the product x * y, where y is a (unsigned) natural number. +// +func (x *Integer) MulNat(y Natural) *Integer { + // x * y == x * y + // (-x) * y == -(x * y) + return MakeInt(x.sign, x.mant.Mul(y)); +} + + +// Quo returns the quotient q = x / y for y != 0. +// If y == 0, a division-by-zero run-time error occurs. +// +// Quo and Rem implement T-division and modulus (like C99): +// +// q = x.Quo(y) = trunc(x/y) (truncation towards zero) +// r = x.Rem(y) = x - y*q +// +// (Daan Leijen, ``Division and Modulus for Computer Scientists''.) +// +func (x *Integer) Quo(y *Integer) *Integer { + // x / y == x / y + // x / (-y) == -(x / y) + // (-x) / y == -(x / y) + // (-x) / (-y) == x / y + return MakeInt(x.sign != y.sign, x.mant.Div(y.mant)); +} + + +// Rem returns the remainder r of the division x / y for y != 0, +// with r = x - y*x.Quo(y). Unless r is zero, its sign corresponds +// to the sign of x. +// If y == 0, a division-by-zero run-time error occurs. +// +func (x *Integer) Rem(y *Integer) *Integer { + // x % y == x % y + // x % (-y) == x % y + // (-x) % y == -(x % y) + // (-x) % (-y) == -(x % y) + return MakeInt(x.sign, x.mant.Mod(y.mant)); +} + + +// QuoRem returns the pair (x.Quo(y), x.Rem(y)) for y != 0. +// If y == 0, a division-by-zero run-time error occurs. +// +func (x *Integer) QuoRem(y *Integer) (*Integer, *Integer) { + q, r := x.mant.DivMod(y.mant); + return MakeInt(x.sign != y.sign, q), MakeInt(x.sign, r); +} + + +// Div returns the quotient q = x / y for y != 0. +// If y == 0, a division-by-zero run-time error occurs. +// +// Div and Mod implement Euclidian division and modulus: +// +// q = x.Div(y) +// r = x.Mod(y) with: 0 <= r < |q| and: y = x*q + r +// +// (Raymond T. Boute, ``The Euclidian definition of the functions +// div and mod''. ACM Transactions on Programming Languages and +// Systems (TOPLAS), 14(2):127-144, New York, NY, USA, 4/1992. +// ACM press.) +// +func (x *Integer) Div(y *Integer) *Integer { + q, r := x.QuoRem(y); + if r.IsNeg() { + if y.IsPos() { + q = q.Sub(Int(1)); + } else { + q = q.Add(Int(1)); + } + } + return q; +} + + +// Mod returns the modulus r of the division x / y for y != 0, +// with r = x - y*x.Div(y). r is always positive. +// If y == 0, a division-by-zero run-time error occurs. +// +func (x *Integer) Mod(y *Integer) *Integer { + r := x.Rem(y); + if r.IsNeg() { + if y.IsPos() { + r = r.Add(y); + } else { + r = r.Sub(y); + } + } + return r; +} + + +// DivMod returns the pair (x.Div(y), x.Mod(y)). +// +func (x *Integer) DivMod(y *Integer) (*Integer, *Integer) { + q, r := x.QuoRem(y); + if r.IsNeg() { + if y.IsPos() { + q = q.Sub(Int(1)); + r = r.Add(y); + } else { + q = q.Add(Int(1)); + r = r.Sub(y); + } + } + return q, r; +} + + +// Shl implements ``shift left'' x << s. It returns x * 2^s. +// +func (x *Integer) Shl(s uint) *Integer { + return MakeInt(x.sign, x.mant.Shl(s)); +} + + +// Shr implements ``shift right'' x >> s. It returns x / 2^s. +// Implementation restriction: Shl is not yet implemented for negative x. +// +func (x *Integer) Shr(s uint) *Integer { + z := MakeInt(x.sign, x.mant.Shr(s)); + if x.IsNeg() { + panic("UNIMPLEMENTED Integer.Shr of negative values"); + } + return z; +} + + +// And returns the ``bitwise and'' x & y for the binary representation of x and y. +// Implementation restriction: And is not implemented for negative x. +// +func (x *Integer) And(y *Integer) *Integer { + var z *Integer; + if !x.sign && !y.sign { + z = MakeInt(false, x.mant.And(y.mant)); + } else { + panic("UNIMPLEMENTED Integer.And of negative values"); + } + return z; +} + + +// Or returns the ``bitwise or'' x | y for the binary representation of x and y. +// Implementation restriction: Or is not implemented for negative x. +// +func (x *Integer) Or(y *Integer) *Integer { + var z *Integer; + if !x.sign && !y.sign { + z = MakeInt(false, x.mant.Or(y.mant)); + } else { + panic("UNIMPLEMENTED Integer.Or of negative values"); + } + return z; +} + + +// Xor returns the ``bitwise xor'' x | y for the binary representation of x and y. +// Implementation restriction: Xor is not implemented for negative integers. +// +func (x *Integer) Xor(y *Integer) *Integer { + var z *Integer; + if !x.sign && !y.sign { + z = MakeInt(false, x.mant.Xor(y.mant)); + } else { + panic("UNIMPLEMENTED Integer.Xor of negative values"); + } + return z; +} + + +// Cmp compares x and y. The result is an int value +// +// < 0 if x < y +// == 0 if x == y +// > 0 if x > y +// +func (x *Integer) Cmp(y *Integer) int { + // x cmp y == x cmp y + // x cmp (-y) == x + // (-x) cmp y == y + // (-x) cmp (-y) == -(x cmp y) + var r int; + switch { + case x.sign == y.sign: + r = x.mant.Cmp(y.mant); + if x.sign { + r = -r; + } + case x.sign: r = -1; + case y.sign: r = 1; + } + return r; +} + + +// ToString converts x to a string for a given base, with 2 <= base <= 16. +// +func (x *Integer) ToString(base uint) string { + if x.mant.IsZero() { + return "0"; + } + var s string; + if x.sign { + s = "-"; + } + return s + x.mant.ToString(base); +} + + +// String converts x to its decimal string representation. +// x.String() is the same as x.ToString(10). +// +func (x *Integer) String() string { + return x.ToString(10); +} + + +// Format is a support routine for fmt.Formatter. It accepts +// the formats 'b' (binary), 'o' (octal), and 'x' (hexadecimal). +// +func (x *Integer) Format(h fmt.Formatter, c int) { + fmt.Fprintf(h, "%s", x.ToString(fmtbase(c))); +} + + +// IntFromString returns the integer corresponding to the +// longest possible prefix of s representing an integer in a +// given conversion base, the actual conversion base used, and +// the prefix length. +// +// If the base argument is 0, the string prefix determines the actual +// conversion base. A prefix of ``0x'' or ``0X'' selects base 16; the +// ``0'' prefix selects base 8. Otherwise the selected base is 10. +// +func IntFromString(s string, base uint) (*Integer, uint, int) { + // skip sign, if any + i0 := 0; + if len(s) > 0 && (s[0] == '-' || s[0] == '+') { + i0 = 1; + } + + mant, base, slen := NatFromString(s[i0 : len(s)], base); + + return MakeInt(i0 > 0 && s[0] == '-', mant), base, i0 + slen; +} + + +// ---------------------------------------------------------------------------- +// Rational numbers + +// Rational represents a quotient a/b of arbitrary precision. +// +type Rational struct { + a *Integer; // numerator + b Natural; // denominator +} + + +// MakeRat makes a rational number given a numerator a and a denominator b. +// +func MakeRat(a *Integer, b Natural) *Rational { + f := a.mant.Gcd(b); // f > 0 + if f.Cmp(Nat(1)) != 0 { + a = MakeInt(a.sign, a.mant.Div(f)); + b = b.Div(f); + } + return &Rational{a, b}; +} + + +// Rat creates a small rational number with value a0/b0. +// Implementation restriction: At the moment, only values a0, b0 +// with an absolute value |a0|, |b0| < (1<<60) are supported. +// +func Rat(a0 int, b0 int) *Rational { + a, b := Int(a0), Int(b0); + if b.sign { + a = a.Neg(); + } + return MakeRat(a, b.mant); +} + + +// Predicates + +// IsZero returns true iff x == 0. +// +func (x *Rational) IsZero() bool { + return x.a.IsZero(); +} + + +// IsNeg returns true iff x < 0. +// +func (x *Rational) IsNeg() bool { + return x.a.IsNeg(); +} + + +// IsPos returns true iff x > 0. +// +func (x *Rational) IsPos() bool { + return x.a.IsPos(); +} + + +// IsInt returns true iff x can be written with a denominator 1 +// in the form x == x'/1; i.e., if x is an integer value. +// +func (x *Rational) IsInt() bool { + return x.b.Cmp(Nat(1)) == 0; +} + + +// Operations + +// Neg returns the negated value of x. +// +func (x *Rational) Neg() *Rational { + return MakeRat(x.a.Neg(), x.b); +} + + +// Add returns the sum x + y. +// +func (x *Rational) Add(y *Rational) *Rational { + return MakeRat((x.a.MulNat(y.b)).Add(y.a.MulNat(x.b)), x.b.Mul(y.b)); +} + + +// Sub returns the difference x - y. +// +func (x *Rational) Sub(y *Rational) *Rational { + return MakeRat((x.a.MulNat(y.b)).Sub(y.a.MulNat(x.b)), x.b.Mul(y.b)); +} + + +// Mul returns the product x * y. +// +func (x *Rational) Mul(y *Rational) *Rational { + return MakeRat(x.a.Mul(y.a), x.b.Mul(y.b)); +} + + +// Quo returns the quotient x / y for y != 0. +// If y == 0, a division-by-zero run-time error occurs. +// +func (x *Rational) Quo(y *Rational) *Rational { + a := x.a.MulNat(y.b); + b := y.a.MulNat(x.b); + if b.IsNeg() { + a = a.Neg(); + } + return MakeRat(a, b.mant); +} + + +// Cmp compares x and y. The result is an int value +// +// < 0 if x < y +// == 0 if x == y +// > 0 if x > y +// +func (x *Rational) Cmp(y *Rational) int { + return (x.a.MulNat(y.b)).Cmp(y.a.MulNat(x.b)); +} + + +// ToString converts x to a string for a given base, with 2 <= base <= 16. +// The string representation is of the form "n" if x is an integer; otherwise +// it is of form "n/d". +// +func (x *Rational) ToString(base uint) string { + s := x.a.ToString(base); + if !x.IsInt() { + s += "/" + x.b.ToString(base); + } + return s; +} + + +// String converts x to its decimal string representation. +// x.String() is the same as x.ToString(10). +// +func (x *Rational) String() string { + return x.ToString(10); +} + + +// Format is a support routine for fmt.Formatter. It accepts +// the formats 'b' (binary), 'o' (octal), and 'x' (hexadecimal). +// +func (x *Rational) Format(h fmt.Formatter, c int) { + fmt.Fprintf(h, "%s", x.ToString(fmtbase(c))); +} + + +// RatFromString returns the rational number corresponding to the +// longest possible prefix of s representing a rational number in a +// given conversion base, the actual conversion base used, and the +// prefix length. +// +// If the base argument is 0, the string prefix determines the actual +// conversion base. A prefix of ``0x'' or ``0X'' selects base 16; the +// ``0'' prefix selects base 8. Otherwise the selected base is 10. +// +func RatFromString(s string, base uint) (*Rational, uint, int) { + // read nominator + a, abase, alen := IntFromString(s, base); + b := Nat(1); + + // read denominator or fraction, if any + var blen int; + if alen < len(s) { + ch := s[alen]; + if ch == '/' { + alen++; + b, base, blen = NatFromString(s[alen : len(s)], base); + } else if ch == '.' { + alen++; + b, base, blen = NatFromString(s[alen : len(s)], abase); + assert(base == abase); + f := Nat(base).Pow(uint(blen)); + a = MakeInt(a.sign, a.mant.Mul(f).Add(b)); + b = f; + } + } + + return MakeRat(a, b), base, alen + blen; +} diff --git a/src/pkg/bignum/bignum_test.go b/src/pkg/bignum/bignum_test.go new file mode 100644 index 000000000..9351c2ebf --- /dev/null +++ b/src/pkg/bignum/bignum_test.go @@ -0,0 +1,482 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bignum_test + +import ( + bignum "bignum"; + fmt "fmt"; + testing "testing"; +) + +const ( + sa = "991"; + sb = "2432902008176640000"; // 20! + sc = "933262154439441526816992388562667004907159682643816214685929" + "638952175999932299156089414639761565182862536979208272237582" + "51185210916864000000000000000000000000"; // 100! + sp = "170141183460469231731687303715884105727"; // prime +) + +func natFromString(s string, base uint, slen *int) bignum.Natural { + x, _, len := bignum.NatFromString(s, base); + if slen != nil { + *slen = len; + } + return x; +} + + +func intFromString(s string, base uint, slen *int) *bignum.Integer { + x, _, len := bignum.IntFromString(s, base); + if slen != nil { + *slen = len; + } + return x; +} + + +func ratFromString(s string, base uint, slen *int) *bignum.Rational { + x, _, len := bignum.RatFromString(s, base); + if slen != nil { + *slen = len; + } + return x; +} + + +var ( + nat_zero = bignum.Nat(0); + nat_one = bignum.Nat(1); + nat_two = bignum.Nat(2); + + a = natFromString(sa, 10, nil); + b = natFromString(sb, 10, nil); + c = natFromString(sc, 10, nil); + p = natFromString(sp, 10, nil); + + int_zero = bignum.Int(0); + int_one = bignum.Int(1); + int_two = bignum.Int(2); + + ip = intFromString(sp, 10, nil); + + rat_zero = bignum.Rat(0, 1); + rat_half = bignum.Rat(1, 2); + rat_one = bignum.Rat(1, 1); + rat_two = bignum.Rat(2, 1); +) + + +var test_msg string; +var tester *testing.T; + +func test(n uint, b bool) { + if !b { + tester.Fatalf("TEST failed: %s (%d)", test_msg, n); + } +} + + +func nat_eq(n uint, x, y bignum.Natural) { + if x.Cmp(y) != 0 { + tester.Fatalf("TEST failed: %s (%d)\nx = %v\ny = %v", test_msg, n, &x, &y); + } +} + + +func int_eq(n uint, x, y *bignum.Integer) { + if x.Cmp(y) != 0 { + tester.Fatalf("TEST failed: %s (%d)\nx = %v\ny = %v", test_msg, n, x, y); + } +} + + +func rat_eq(n uint, x, y *bignum.Rational) { + if x.Cmp(y) != 0 { + tester.Fatalf("TEST failed: %s (%d)\nx = %v\ny = %v", test_msg, n, x, y); + } +} + +func TestNatConv(t *testing.T) { + tester = t; + test_msg = "NatConvA"; + nat_eq(0, a, bignum.Nat(991)); + nat_eq(1, b, bignum.Fact(20)); + nat_eq(2, c, bignum.Fact(100)); + test(3, a.String() == sa); + test(4, b.String() == sb); + test(5, c.String() == sc); + + test_msg = "NatConvB"; + var slen int; + nat_eq(10, natFromString("0", 0, nil), nat_zero); + nat_eq(11, natFromString("123", 0, nil), bignum.Nat(123)); + nat_eq(12, natFromString("077", 0, nil), bignum.Nat(7*8 + 7)); + nat_eq(13, natFromString("0x1f", 0, nil), bignum.Nat(1*16 + 15)); + nat_eq(14, natFromString("0x1fg", 0, &slen), bignum.Nat(1*16 + 15)); + test(4, slen == 4); + + test_msg = "NatConvC"; + tmp := c.Mul(c); + for base := uint(2); base <= 16; base++ { + nat_eq(base, natFromString(tmp.ToString(base), base, nil), tmp); + } + + test_msg = "NatConvD"; + x := bignum.Nat(100); + y, b, _ := bignum.NatFromString(fmt.Sprintf("%b", &x), 2); + nat_eq(100, y, x); +} + + +func TestIntConv(t *testing.T) { + tester = t; + test_msg = "IntConv"; + var slen int; + int_eq(0, intFromString("0", 0, nil), int_zero); + int_eq(1, intFromString("-0", 0, nil), int_zero); + int_eq(2, intFromString("123", 0, nil), bignum.Int(123)); + int_eq(3, intFromString("-123", 0, nil), bignum.Int(-123)); + int_eq(4, intFromString("077", 0, nil), bignum.Int(7*8 + 7)); + int_eq(5, intFromString("-077", 0, nil), bignum.Int(-(7*8 + 7))); + int_eq(6, intFromString("0x1f", 0, nil), bignum.Int(1*16 + 15)); + int_eq(7, intFromString("-0x1f", 0, &slen), bignum.Int(-(1*16 + 15))); + test(7, slen == 5); + int_eq(8, intFromString("+0x1f", 0, &slen), bignum.Int(+(1*16 + 15))); + test(8, slen == 5); + int_eq(9, intFromString("0x1fg", 0, &slen), bignum.Int(1*16 + 15)); + test(9, slen == 4); + int_eq(10, intFromString("-0x1fg", 0, &slen), bignum.Int(-(1*16 + 15))); + test(10, slen == 5); +} + + +func TestRatConv(t *testing.T) { + tester = t; + test_msg = "RatConv"; + var slen int; + rat_eq(0, ratFromString("0", 0, nil), rat_zero); + rat_eq(1, ratFromString("0/1", 0, nil), rat_zero); + rat_eq(2, ratFromString("0/01", 0, nil), rat_zero); + rat_eq(3, ratFromString("0x14/10", 0, &slen), rat_two); + test(4, slen == 7); + rat_eq(5, ratFromString("0.", 0, nil), rat_zero); + rat_eq(6, ratFromString("0.001f", 10, nil), bignum.Rat(1, 1000)); + rat_eq(7, ratFromString("10101.0101", 2, nil), bignum.Rat(0x155, 1<<4)); + rat_eq(8, ratFromString("-0003.145926", 10, &slen), bignum.Rat(-3145926, 1000000)); + test(9, slen == 12); +} + + +func add(x, y bignum.Natural) bignum.Natural { + z1 := x.Add(y); + z2 := y.Add(x); + if z1.Cmp(z2) != 0 { + tester.Fatalf("addition not symmetric:\n\tx = %v\n\ty = %t", x, y); + } + return z1; +} + + +func sum(n uint, scale bignum.Natural) bignum.Natural { + s := nat_zero; + for ; n > 0; n-- { + s = add(s, bignum.Nat(n).Mul(scale)); + } + return s; +} + + +func TestNatAdd(t *testing.T) { + tester = t; + test_msg = "NatAddA"; + nat_eq(0, add(nat_zero, nat_zero), nat_zero); + nat_eq(1, add(nat_zero, c), c); + + test_msg = "NatAddB"; + for i := uint(0); i < 100; i++ { + t := bignum.Nat(i); + nat_eq(i, sum(i, c), t.Mul(t).Add(t).Shr(1).Mul(c)); + } +} + + +func mul(x, y bignum.Natural) bignum.Natural { + z1 := x.Mul(y); + z2 := y.Mul(x); + if z1.Cmp(z2) != 0 { + tester.Fatalf("multiplication not symmetric:\n\tx = %v\n\ty = %t", x, y); + } + if !x.IsZero() && z1.Div(x).Cmp(y) != 0 { + tester.Fatalf("multiplication/division not inverse (A):\n\tx = %v\n\ty = %t", x, y); + } + if !y.IsZero() && z1.Div(y).Cmp(x) != 0 { + tester.Fatalf("multiplication/division not inverse (B):\n\tx = %v\n\ty = %t", x, y); + } + return z1; +} + + +func TestNatSub(t *testing.T) { + tester = t; + test_msg = "NatSubA"; + nat_eq(0, nat_zero.Sub(nat_zero), nat_zero); + nat_eq(1, c.Sub(nat_zero), c); + + test_msg = "NatSubB"; + for i := uint(0); i < 100; i++ { + t := sum(i, c); + for j := uint(0); j <= i; j++ { + t = t.Sub(mul(bignum.Nat(j), c)); + } + nat_eq(i, t, nat_zero); + } +} + + +func TestNatMul(t *testing.T) { + tester = t; + test_msg = "NatMulA"; + nat_eq(0, mul(c, nat_zero), nat_zero); + nat_eq(1, mul(c, nat_one), c); + + test_msg = "NatMulB"; + nat_eq(0, b.Mul(bignum.MulRange(0, 100)), nat_zero); + nat_eq(1, b.Mul(bignum.MulRange(21, 100)), c); + + test_msg = "NatMulC"; + const n = 100; + p := b.Mul(c).Shl(n); + for i := uint(0); i < n; i++ { + nat_eq(i, mul(b.Shl(i), c.Shl(n-i)), p); + } +} + + +func TestNatDiv(t *testing.T) { + tester = t; + test_msg = "NatDivA"; + nat_eq(0, c.Div(nat_one), c); + nat_eq(1, c.Div(bignum.Nat(100)), bignum.Fact(99)); + nat_eq(2, b.Div(c), nat_zero); + nat_eq(4, nat_one.Shl(100).Div(nat_one.Shl(90)), nat_one.Shl(10)); + nat_eq(5, c.Div(b), bignum.MulRange(21, 100)); + + test_msg = "NatDivB"; + const n = 100; + p := bignum.Fact(n); + for i := uint(0); i < n; i++ { + nat_eq(100+i, p.Div(bignum.MulRange(1, i)), bignum.MulRange(i+1, n)); + } +} + + +func TestIntQuoRem(t *testing.T) { + tester = t; + test_msg = "IntQuoRem"; + type T struct { x, y, q, r int }; + a := []T{ + T{+8, +3, +2, +2}, + T{+8, -3, -2, +2}, + T{-8, +3, -2, -2}, + T{-8, -3, +2, -2}, + T{+1, +2, 0, +1}, + T{+1, -2, 0, +1}, + T{-1, +2, 0, -1}, + T{-1, -2, 0, -1}, + }; + for i := uint(0); i < uint(len(a)); i++ { + e := &a[i]; + x, y := bignum.Int(e.x).Mul(ip), bignum.Int(e.y).Mul(ip); + q, r := bignum.Int(e.q), bignum.Int(e.r).Mul(ip); + qq, rr := x.QuoRem(y); + int_eq(4*i+0, x.Quo(y), q); + int_eq(4*i+1, x.Rem(y), r); + int_eq(4*i+2, qq, q); + int_eq(4*i+3, rr, r); + } +} + + +func TestIntDivMod(t *testing.T) { + tester = t; + test_msg = "IntDivMod"; + type T struct { x, y, q, r int }; + a := []T{ + T{+8, +3, +2, +2}, + T{+8, -3, -2, +2}, + T{-8, +3, -3, +1}, + T{-8, -3, +3, +1}, + T{+1, +2, 0, +1}, + T{+1, -2, 0, +1}, + T{-1, +2, -1, +1}, + T{-1, -2, +1, +1}, + }; + for i := uint(0); i < uint(len(a)); i++ { + e := &a[i]; + x, y := bignum.Int(e.x).Mul(ip), bignum.Int(e.y).Mul(ip); + q, r := bignum.Int(e.q), bignum.Int(e.r).Mul(ip); + qq, rr := x.DivMod(y); + int_eq(4*i+0, x.Div(y), q); + int_eq(4*i+1, x.Mod(y), r); + int_eq(4*i+2, qq, q); + int_eq(4*i+3, rr, r); + } +} + + +func TestNatMod(t *testing.T) { + tester = t; + test_msg = "NatModA"; + for i := uint(0); ; i++ { + d := nat_one.Shl(i); + if d.Cmp(c) < 0 { + nat_eq(i, c.Add(d).Mod(c), d); + } else { + nat_eq(i, c.Add(d).Div(c), nat_two); + nat_eq(i, c.Add(d).Mod(c), d.Sub(c)); + break; + } + } +} + + +func TestNatShift(t *testing.T) { + tester = t; + test_msg = "NatShift1L"; + test(0, b.Shl(0).Cmp(b) == 0); + test(1, c.Shl(1).Cmp(c) > 0); + + test_msg = "NatShift1R"; + test(3, b.Shr(0).Cmp(b) == 0); + test(4, c.Shr(1).Cmp(c) < 0); + + test_msg = "NatShift2"; + for i := uint(0); i < 100; i++ { + test(i, c.Shl(i).Shr(i).Cmp(c) == 0); + } + + test_msg = "NatShift3L"; + { const m = 3; + p := b; + f := bignum.Nat(1< 0); + + test_msg = "IntShift1R"; + test(0, ip.Shr(0).Cmp(ip) == 0); + test(1, ip.Shr(1).Cmp(ip) < 0); + + test_msg = "IntShift2"; + for i := uint(0); i < 100; i++ { + test(i, ip.Shl(i).Shr(i).Cmp(ip) == 0); + } + + test_msg = "IntShift3L"; + { const m = 3; + p := ip; + f := bignum.Int(1<> 1)); + //int_eq(1, ip.Neg().Shr(10), ip.Neg().Div(bignum.Int(1).Shl(10))); +} + + +func TestNatCmp(t *testing.T) { + tester = t; + test_msg = "NatCmp"; + test(0, a.Cmp(a) == 0); + test(1, a.Cmp(b) < 0); + test(2, b.Cmp(a) > 0); + test(3, a.Cmp(c) < 0); + d := c.Add(b); + test(4, c.Cmp(d) < 0); + test(5, d.Cmp(c) > 0); +} + + +func TestNatLog2(t *testing.T) { + tester = t; + test_msg = "NatLog2A"; + test(0, nat_one.Log2() == 0); + test(1, nat_two.Log2() == 1); + test(2, bignum.Nat(3).Log2() == 1); + test(3, bignum.Nat(4).Log2() == 2); + + test_msg = "NatLog2B"; + for i := uint(0); i < 100; i++ { + test(i, nat_one.Shl(i).Log2() == i); + } +} + + +func TestNatGcd(t *testing.T) { + tester = t; + test_msg = "NatGcdA"; + f := bignum.Nat(99991); + nat_eq(0, b.Mul(f).Gcd(c.Mul(f)), bignum.MulRange(1, 20).Mul(f)); +} + + +func TestNatPow(t *testing.T) { + tester = t; + test_msg = "NatPowA"; + nat_eq(0, nat_two.Pow(0), nat_one); + + test_msg = "NatPowB"; + for i := uint(0); i < 100; i++ { + nat_eq(i, nat_two.Pow(i), nat_one.Shl(i)); + } +} + + +func TestNatPop(t *testing.T) { + tester = t; + test_msg = "NatPopA"; + test(0, nat_zero.Pop() == 0); + test(1, nat_one.Pop() == 1); + test(2, bignum.Nat(10).Pop() == 2); + test(3, bignum.Nat(30).Pop() == 4); + test(4, bignum.Nat(0x1248f).Shl(33).Pop() == 8); + + test_msg = "NatPopB"; + for i := uint(0); i < 100; i++ { + test(i, nat_one.Shl(i).Sub(nat_one).Pop() == i); + } +} + diff --git a/src/pkg/bufio/Makefile b/src/pkg/bufio/Makefile new file mode 100644 index 000000000..abb826e7f --- /dev/null +++ b/src/pkg/bufio/Makefile @@ -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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D= + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + bufio.$O\ + + +phases: a1 +_obj$D/bufio.a: phases + +a1: $(O1) + $(AR) grc _obj$D/bufio.a bufio.$O + rm -f $(O1) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/bufio.a + +$(O1): newpkg +$(O2): a1 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/bufio.a + +packages: _obj$D/bufio.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/bufio.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/bufio.a diff --git a/src/pkg/bufio/bufio.go b/src/pkg/bufio/bufio.go new file mode 100644 index 000000000..7bfbb089f --- /dev/null +++ b/src/pkg/bufio/bufio.go @@ -0,0 +1,515 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This package implements buffered I/O. It wraps an io.Reader or io.Writer +// object, creating another object (Reader or Writer) that also implements +// the interface but provides buffering and some help for textual I/O. +package bufio + +import ( + "io"; + "os"; + "utf8"; +) + + +// TODO: +// - maybe define an interface +// - Reader: ReadRune, UnreadRune ? +// could make ReadRune generic if we dropped UnreadRune +// - buffered output + +const ( + defaultBufSize = 4096 +) + +// Errors introduced by this package. +type Error struct { + os.ErrorString; +} + +var ( + PhaseError os.Error = &Error{"bufio: phase error"}; + BufferFull os.Error = &Error{"bufio: buffer full"}; + InternalError os.Error = &Error{"bufio: internal error"}; + BadBufSize os.Error = &Error{"bufio: bad buffer size"}; +) + +func copySlice(dst []byte, src []byte) { + for i := 0; i < len(dst); i++ { + dst[i] = src[i] + } +} + + +// 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; +} + +// 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, BadBufSize + } + // 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; + 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("bufio: NewReader: ", err.String()); + } + return b; +} + +//.fill reads a new chunk into the buffer. +func (b *Reader) fill() os.Error { + if b.err != nil { + return b.err + } + + // Slide existing data to beginning. + if b.w > b.r { + copySlice(b.buf[0:b.w-b.r], b.buf[b.r:b.w]); + b.w -= b.r; + } else { + b.w = 0 + } + b.r = 0; + + // Read new data. + n, e := b.rd.Read(b.buf[b.w:len(b.buf)]); + if e != nil { + b.err = e; + return e + } + b.w += n; + return nil +} + +// Read reads data into p. +// It returns the number of bytes read into p. +// If nn < len(p), also returns an error explaining +// why the read is short. At EOF, the count will be +// zero and err will be io.ErrEOF. +func (b *Reader) Read(p []byte) (nn int, err os.Error) { + nn = 0; + for len(p) > 0 { + n := len(p); + if b.w == b.r { + if len(p) >= len(b.buf) { + // Large read, empty buffer. + // Read directly into p to avoid copy. + n, b.err = b.rd.Read(p); + if n > 0 { + b.lastbyte = int(p[n-1]); + } + p = p[n:len(p)]; + nn += n; + if b.err != nil { + return nn, b.err + } + if n == 0 { + return nn, io.ErrEOF + } + continue; + } + b.fill(); + if b.err != nil { + return nn, b.err + } + if b.w == b.r { + return nn, io.ErrEOF + } + } + if n > b.w - b.r { + n = b.w - b.r + } + copySlice(p[0:n], b.buf[b.r:b.r+n]); + p = p[n:len(p)]; + b.r += n; + b.lastbyte = int(b.buf[b.r-1]); + nn += n + } + return nn, 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) { + if b.w == b.r { + b.fill(); + if b.err != nil { + return 0, b.err + } + if b.w == b.r { + return 0, io.ErrEOF + } + } + c = b.buf[b.r]; + b.r++; + b.lastbyte = int(c); + return c, nil +} + +// UnreadByte unreads the last byte. Only one byte may be unread at a given time. +func (b *Reader) UnreadByte() os.Error { + if b.err != nil { + return b.err + } + 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 PhaseError + } + 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]) { + n := b.w - b.r; + b.fill(); + if b.err != nil { + return 0, 0, b.err + } + if b.w - b.r == n { + // no bytes read + if b.r == b.w { + return 0, 0, io.ErrEOF + } + break; + } + } + 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]); + return rune, size, nil +} + +// Helper function: look for byte c in array p, +// returning its index or -1. +func findByte(p []byte, c byte) int { + for i := 0; i < len(p); i++ { + if p[i] == c { + return i + } + } + return -1 +} + +// Buffered returns the number of bytes that can be read from the current buffer. +func (b *Reader) Buffered() int { + return b.w - b.r; +} + +// ReadLineSlice 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. +// Fails if the line doesn't fit in the buffer. +// For internal or advanced use only; most uses should +// call ReadLineString or ReadLineBytes instead. +func (b *Reader) ReadLineSlice(delim byte) (line []byte, err os.Error) { + if b.err != nil { + return nil, b.err + } + + // Look in buffer. + if i := findByte(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 { + n := b.Buffered(); + b.fill(); + if b.err != nil { + return nil, b.err + } + if b.Buffered() == n { // no data added; end of file + line := b.buf[b.r:b.w]; + b.r = b.w; + return line, io.ErrEOF + } + + // Search new part of buffer + if i := findByte(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) { + return nil, BufferFull + } + } + + // BUG 6g bug100 + return nil, nil +} + +// ReadLineBytes reads until the first occurrence of delim in the input, +// returning a new byte array containing the line. +// If an error happens, returns the data (without a delimiter) +// and the error. (It can't leave the data in the buffer because +// it might have read more than the buffer size.) +func (b *Reader) ReadLineBytes(delim byte) (line []byte, err os.Error) { + if b.err != nil { + return nil, b.err + } + + // Use ReadLineSlice to look for array, + // accumulating full buffers. + var frag []byte; + var full [][]byte; + nfull := 0; + err = nil; + + for { + var e os.Error; + frag, e = b.ReadLineSlice(delim); + if e == nil { // got final fragment + break + } + if e != BufferFull { // unexpected error + err = e; + break + } + + // Read bytes out of buffer. + buf := make([]byte, b.Buffered()); + var n int; + n, e = b.Read(buf); + if e != nil { + frag = buf[0:n]; + err = e; + break + } + if n != len(buf) { + frag = buf[0:n]; + err = InternalError; + break + } + + // Grow list if needed. + if full == nil { + full = make([][]byte, 16); + } else if nfull >= len(full) { + newfull := make([][]byte, len(full)*2); + // BUG slice assignment + for i := 0; i < len(full); i++ { + newfull[i] = full[i]; + } + full = newfull + } + + // Save buffer + full[nfull] = buf; + nfull++; + } + + // Allocate new buffer to hold the full pieces and the fragment. + n := 0; + for i := 0; i < nfull; i++ { + n += len(full[i]) + } + n += len(frag); + + // Copy full pieces and fragment in. + buf := make([]byte, n); + n = 0; + for i := 0; i < nfull; i++ { + copySlice(buf[n:n+len(full[i])], full[i]); + n += len(full[i]) + } + copySlice(buf[n:n+len(frag)], frag); + return buf, err +} + +// ReadLineString reads until the first occurrence of delim in the input, +// returning a new string containing the line. +// If savedelim, keep delim in the result; otherwise drop it. +func (b *Reader) ReadLineString(delim byte, savedelim bool) (line string, err os.Error) { + bytes, e := b.ReadLineBytes(delim); + if e != nil { + return string(bytes), e + } + if !savedelim { + bytes = bytes[0:len(bytes)-1] + } + return string(bytes), nil +} + + +// 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, BadBufSize + } + // 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("bufio: NewWriter: ", err.String()); + } + return b; +} + +// Flush writes any buffered data to the underlying io.Writer. +func (b *Writer) Flush() os.Error { + if b.err != nil { + return b.err + } + n, e := b.wr.Write(b.buf[0:b.n]); + if n < b.n && e == nil { + e = io.ErrShortWrite; + } + if e != nil { + if n > 0 && n < b.n { + copySlice(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), also returns an error explaining +// why the write is short. +func (b *Writer) Write(p []byte) (nn int, err os.Error) { + if b.err != nil { + return 0, b.err + } + nn = 0; + for len(p) > 0 { + n := b.Available(); + if n <= 0 { + if b.Flush(); b.err != nil { + break + } + n = b.Available() + } + if b.Available() == 0 && len(p) >= len(b.buf) { + // Large write, empty buffer. + // Write directly from p to avoid copy. + n, b.err = b.wr.Write(p); + nn += n; + p = p[n:len(p)]; + if b.err != nil { + break; + } + continue; + } + if n > len(p) { + n = len(p) + } + copySlice(b.buf[b.n:b.n+n], p[0:n]); + b.n += n; + nn += n; + p = p[n:len(p)] + } + return nn, b.err +} + +// WriteByte writes a single byte. +func (b *Writer) WriteByte(c byte) os.Error { + if b.err != nil { + return b.err + } + if b.Available() <= 0 && b.Flush() != nil { + return b.err + } + b.buf[b.n] = c; + b.n++; + return nil +} + +// 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..6e5135df7 --- /dev/null +++ b/src/pkg/bufio/bufio_test.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 bufio + +import ( + "bufio"; + "fmt"; + "io"; + "os"; + "testing"; + "testing/iotest"; +) + +// 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 == io.ErrEOF { + break + } + if e != nil { + panic("Data: "+e.String()) + } + b[nb] = c; + nb++; + } + return string(b[0:nb]) +} + +func TestReaderSimple(t *testing.T) { + data := io.StringBytes("hello world"); + b := NewReader(io.NewByteReader(data)); + if s := readBytes(b); s != "hello world" { + t.Errorf("simple hello world test failed: got %q", s); + } + + b = NewReader(newRot13Reader(io.NewByteReader(data))); + if s := readBytes(b); s != "uryyb jbeyq" { + t.Error("rot13 hello world test failed: got %q", s); + } +} + + +type readMaker struct { + name string; + fn func(io.Reader) io.Reader; +} +var readMakers = []readMaker { + readMaker{ "full", func(r io.Reader) io.Reader { return r } }, + readMaker{ "byte", iotest.OneByteReader }, + readMaker{ "half", iotest.HalfReader }, +} + +// Call ReadLineString (which ends up calling everything else) +// to accumulate the text of a file. +func readLines(b *Reader) string { + s := ""; + for { + s1, e := b.ReadLineString('\n', true); + if e == io.ErrEOF { + break + } + if e != nil { + panic("GetLines: "+e.String()) + } + s += s1 + } + return s +} + +// Call Read to accumulate the text of a file +func reads(buf *Reader, m int) string { + var b [1000]byte; + nb := 0; + for { + n, e := buf.Read(b[nb:nb+m]); + nb += n; + if e == io.ErrEOF { + break + } + } + return string(b[0:nb]) +} + +type bufReader struct { + name string; + fn func(*Reader) string; +} +var bufreaders = []bufReader { + bufReader{ "1", func(b *Reader) string { return reads(b, 1) } }, + bufReader{ "2", func(b *Reader) string { return reads(b, 2) } }, + bufReader{ "3", func(b *Reader) string { return reads(b, 3) } }, + bufReader{ "4", func(b *Reader) string { return reads(b, 4) } }, + bufReader{ "5", func(b *Reader) string { return reads(b, 5) } }, + bufReader{ "7", func(b *Reader) string { return reads(b, 7) } }, + bufReader{ "bytes", readBytes }, + bufReader{ "lines", readLines }, +} + +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]; + textbytes := io.StringBytes(text); + 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(io.NewByteReader(textbytes)); + buf, e := 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); + } + } + } + } + } +} + +func TestWriter(t *testing.T) { + var data [8192]byte; + + for i := 0; i < len(data); i++ { + data[i] = byte(' '+ i%('~'-' ')); + } + w := new(io.ByteBuffer); + 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.Data(); + 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("%s: wrong bytes written"); + t.Errorf("want=%s", data[0:len(written)]); + t.Errorf("have=%s", 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 { + errorWriterTest{ 0, 1, nil, io.ErrShortWrite }, + errorWriterTest{ 1, 2, nil, io.ErrShortWrite }, + errorWriterTest{ 1, 1, nil, nil }, + errorWriterTest{ 0, 1, os.EPIPE, os.EPIPE }, + errorWriterTest{ 1, 2, os.EPIPE, os.EPIPE }, + errorWriterTest{ 1, 1, os.EPIPE, os.EPIPE }, +} + +func TestWriteErrors(t *testing.T) { + for i, w := range errorWriterTests { + buf := NewWriter(w); + n, e := buf.Write(io.StringBytes("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(io.NewByteReader(io.StringBytes("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(io.ByteBuffer), 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"); + } +} diff --git a/src/pkg/bytes/Makefile b/src/pkg/bytes/Makefile new file mode 100644 index 000000000..5220d2880 --- /dev/null +++ b/src/pkg/bytes/Makefile @@ -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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D= + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + bytes.$O\ + + +phases: a1 +_obj$D/bytes.a: phases + +a1: $(O1) + $(AR) grc _obj$D/bytes.a bytes.$O + rm -f $(O1) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/bytes.a + +$(O1): newpkg +$(O2): a1 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/bytes.a + +packages: _obj$D/bytes.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/bytes.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/bytes.a diff --git a/src/pkg/bytes/bytes.go b/src/pkg/bytes/bytes.go new file mode 100644 index 000000000..dd299a82e --- /dev/null +++ b/src/pkg/bytes/bytes.go @@ -0,0 +1,164 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// A package of simple functions to manipulate arrays of bytes. +// Analagous to the facilities of the strings package. +package bytes + +import "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 { + for i := 0; i < len(a) && i < len(b); i++ { + switch { + case a[i] > b[i]: + return 1 + case a[i] < b[i]: + 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 := 0; i < len(a); i++ { + if a[i] != b[i] { + return false + } + } + return true +} + +// Copy copies the source to the destination, stopping when the source +// is all transferred. The caller must guarantee that there is enough +// room in the destination. It returns the number of bytes copied +func Copy(dst, src []byte) int { + for i, x := range src { + dst[i] = x + } + return len(src) +} + +// Explode splits s into an array of UTF-8 sequences, one per Unicode character (still arrays of bytes). +// Invalid UTF-8 sequences become correct encodings of U+FFF8. +func Explode(s []byte) [][]byte { + a := make([][]byte, utf8.RuneCount(s)); + var size, rune int; + i := 0; + for len(s) > 0 { + rune, size = utf8.DecodeRune(s); + a[i] = s[0:size]; + s = s[size:len(s)]; + i++; + } + return a +} + +// 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 +} + +// Split returns the array representing the subarrays of s separated by sep. Adjacent +// occurrences of sep produce empty subarrays. If sep is empty, it is the same as Explode. +func Split(s, sep []byte) [][]byte { + if len(sep) == 0 { + return Explode(s) + } + c := sep[0]; + start := 0; + n := Count(s, sep)+1; + a := make([][]byte, n); + na := 0; + for i := 0; i+len(sep) <= len(s); i++ { + if s[i] == c && (len(sep) == 1 || Equal(s[i:i+len(sep)], sep)) { + a[na] = s[start:i]; + na++; + start = i+len(sep); + i += len(sep)-1 + } + } + a[na] = s[start:len(s)]; + return a +} + +// Join concatenates the elements of a to create a single byte array. The separator +// sep is placed between elements in the resulting array. +func Join(a [][]byte, sep []byte) []byte { + if len(a) == 0 { + return []byte{} + } + if len(a) == 1 { + return a[0] + } + n := len(sep) * (len(a)-1); + for i := 0; i < len(a); i++ { + n += len(a[i]) + } + + b := make([]byte, n); + bp := 0; + for i := 0; i < len(a); i++ { + s := a[i]; + for j := 0; j < len(s); j++ { + b[bp] = s[j]; + bp++ + } + if i + 1 < len(a) { + s = sep; + for j := 0; j < len(s); j++ { + b[bp] = s[j]; + bp++ + } + } + } + return b +} + +// HasPrefix tests whether the byte array s begins with prefix. +func HasPrefix(s, prefix []byte) bool { + return len(s) >= len(prefix) && Equal(s[0:len(prefix)], prefix) +} + +// HasSuffix tests whether the byte array s ends with suffix. +func HasSuffix(s, suffix []byte) bool { + return len(s) >= len(suffix) && Equal(s[len(s)-len(suffix):len(s)], suffix) +} diff --git a/src/pkg/bytes/bytes_test.go b/src/pkg/bytes/bytes_test.go new file mode 100644 index 000000000..4e7cdfad6 --- /dev/null +++ b/src/pkg/bytes/bytes_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 bytes + +import ( + "bytes"; + "io"; + "testing"; +) + +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 CompareTest struct { + a string; + b string; + cmp int; +} +var comparetests = []CompareTest { + CompareTest{ "", "", 0 }, + CompareTest{ "a", "", 1 }, + CompareTest{ "", "a", -1 }, + CompareTest{ "abc", "abc", 0 }, + CompareTest{ "ab", "abc", -1 }, + CompareTest{ "abc", "ab", 1 }, + CompareTest{ "x", "ab", 1 }, + CompareTest{ "ab", "x", -1 }, + CompareTest{ "x", "a", 1 }, + CompareTest{ "b", "x", -1 }, +} + +func TestCompare(t *testing.T) { + for i := 0; i < len(comparetests); i++ { + tt := comparetests[i]; + a := io.StringBytes(tt.a); + b := io.StringBytes(tt.b); + cmp := Compare(a, b); + eql := Equal(a, b); + if cmp != tt.cmp { + t.Errorf(`Compare(%q, %q) = %v`, tt.a, tt.b, cmp); + } + if eql != (tt.cmp==0) { + t.Errorf(`Equal(%q, %q) = %v`, tt.a, tt.b, eql); + } + } +} + + +type ExplodeTest struct { + s string; + a []string; +} +var explodetests = []ExplodeTest { + ExplodeTest{ abcd, []string{"a", "b", "c", "d"} }, + ExplodeTest{ faces, []string{"☺", "☻", "☹" } }, +} +func TestExplode(t *testing.T) { + for i := 0; i < len(explodetests); i++ { + tt := explodetests[i]; + a := Explode(io.StringBytes(tt.s)); + result := arrayOfString(a); + if !eq(result, tt.a) { + t.Errorf(`Explode("%s") = %v; want %v`, tt.s, result, tt.a); + continue; + } + s := Join(a, []byte{}); + if string(s) != tt.s { + t.Errorf(`Join(Explode("%s"), "") = "%s"`, tt.s, s); + } + } +} + + +type SplitTest struct { + s string; + sep string; + a []string; +} +var splittests = []SplitTest { + SplitTest{ abcd, "a", []string{"", "bcd"} }, + SplitTest{ abcd, "z", []string{"abcd"} }, + SplitTest{ abcd, "", []string{"a", "b", "c", "d"} }, + SplitTest{ commas, ",", []string{"1", "2", "3", "4"} }, + SplitTest{ dots, "...", []string{"1", ".2", ".3", ".4"} }, + SplitTest{ faces, "☹", []string{"☺☻", ""} }, + SplitTest{ faces, "~", []string{faces} }, + SplitTest{ faces, "", []string{"☺", "☻", "☹"} }, +} +func TestSplit(t *testing.T) { + for i := 0; i < len(splittests); i++ { + tt := splittests[i]; + a := Split(io.StringBytes(tt.s), io.StringBytes(tt.sep)); + result := arrayOfString(a); + if !eq(result, tt.a) { + t.Errorf(`Split("%s", "%s") = %v; want %v`, tt.s, tt.sep, result, tt.a); + continue; + } + s := Join(a, io.StringBytes(tt.sep)); + if string(s) != tt.s { + t.Errorf(`Join(Split("%s", "%s"), "%s") = "%s"`, tt.s, tt.sep, tt.sep, s); + } + } +} + +type CopyTest struct { + a string; + b string; + res string; +} +var copytests = []CopyTest { + CopyTest{ "", "", "" }, + CopyTest{ "a", "", "a" }, + CopyTest{ "a", "a", "a" }, + CopyTest{ "a", "b", "b" }, + CopyTest{ "xyz", "abc", "abc" }, + CopyTest{ "wxyz", "abc", "abcz" }, +} + +func TestCopy(t *testing.T) { + for i := 0; i < len(copytests); i++ { + tt := copytests[i]; + dst := io.StringBytes(tt.a); + Copy(dst, io.StringBytes(tt.b)); + result := string(dst); + if result != tt.res { + t.Errorf(`Copy("%s", "%s") = "%s"; want "%s"`, tt.a, tt.b, result, tt.res); + continue; + } + } +} diff --git a/src/pkg/compress/flate/Makefile b/src/pkg/compress/flate/Makefile new file mode 100644 index 000000000..3f73a1932 --- /dev/null +++ b/src/pkg/compress/flate/Makefile @@ -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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D=/compress/ + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + inflate.$O\ + + +phases: a1 +_obj$D/flate.a: phases + +a1: $(O1) + $(AR) grc _obj$D/flate.a inflate.$O + rm -f $(O1) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/flate.a + +$(O1): newpkg +$(O2): a1 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/flate.a + +packages: _obj$D/flate.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/flate.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/flate.a diff --git a/src/pkg/compress/flate/flate_test.go b/src/pkg/compress/flate/flate_test.go new file mode 100644 index 000000000..309606ecb --- /dev/null +++ b/src/pkg/compress/flate/flate_test.go @@ -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. + +// This test tests some internals of the flate package. +// The tests in package compress/gzip serve as the +// end-to-end test of the inflater. + +package flate + +import ( + "bufio"; + "compress/flate"; + "io"; + "os"; + "reflect"; + "strconv"; + "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, + 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); + } + } +} diff --git a/src/pkg/compress/flate/inflate.go b/src/pkg/compress/flate/inflate.go new file mode 100644 index 000000000..c07c94c6e --- /dev/null +++ b/src/pkg/compress/flate/inflate.go @@ -0,0 +1,673 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// The flate package implements the DEFLATE compressed data +// format, described in RFC 1951. The gzip and zlib packages +// implement access to DEFLATE-based file formats. +package flate + +import ( + "bufio"; + "io"; + "os"; + "strconv"; +) + +const ( + maxCodeLen = 16; // max length of Huffman code + maxHist = 32768; // max history required + maxLit = 286; + maxDist = 32; + numCodes = 19; // number of codes in Huffman meta-code +) + +// TODO(rsc): Publish in another package? +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, +} + +// A CorruptInputError reports the presence of corrupt input at a given offset. +type CorruptInputError int64 +func (e CorruptInputError) String() string { + return "flate: corrupt input at 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 Read +} + +func (e *WriteError) String() string { + return "flate: write error at offset " + strconv.Itoa64(e.Offset) + + ": " + e.Error.String(); +} + +// Huffman decoder is based on +// J. Brian Connell, ``A Huffman-Shannon-Fano Code,'' +// Proceedings of the IEEE, 61(7) (July 1973), pp 1046-1047. +type huffmanDecoder struct { + // min, max code length + min, max int; + + // limit[i] = largest code word of length i + // Given code v of length n, + // need more bits if v > limit[n]. + limit [maxCodeLen+1]int; + + // base[i] = smallest code word of length i - seq number + base [maxCodeLen+1]int; + + // codes[seq number] = output code. + // Given code v of length n, value is + // codes[v - base[n]]. + codes []int; +} + +// Initialize Huffman decoding tables from array of code lengths. +func (h *huffmanDecoder) init(bits []int) bool { + // TODO(rsc): Return false sometimes. + + // Count number of codes of each length, + // compute min and max length. + var count [maxCodeLen+1]int; + var min, max int; + for i, 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 NewInflater. +// If the passed in io.Reader does not also have ReadByte, +// the NewInflater will introduce its own buffering. +type Reader interface { + io.Reader; + ReadByte() (c byte, err os.Error); +} + +// Inflate state. +// TODO(rsc): Expose this or not? +type inflater struct { + // Input/output sources. + r Reader; + w io.Writer; + roffset int64; + woffset int64; + + // Input bits, in top of b. + b uint32; + nb uint; + + // Huffman decoders for literal/length, distance. + h1, h2 huffmanDecoder; + + // Length arrays used to define Huffman codes. + bits [maxLit+maxDist]int; + codebits [numCodes]int; + + // Output history, buffer. + hist [maxHist]byte; + hp int; // current output position in buffer + hfull bool; // buffer has filled at least once + + // Temporary buffer (avoids repeated allocation). + buf [4]byte; +} + +// TODO(rsc): This works around a 6g bug. +func (f *inflater) getRoffset() int64 { + return f.roffset; +} + +func (f *inflater) dataBlock() os.Error +func (f *inflater) readHuffman() os.Error +func (f *inflater) decodeBlock(hl, hd *huffmanDecoder) os.Error +func (f *inflater) moreBits() os.Error +func (f *inflater) huffSym(h *huffmanDecoder) (int, os.Error) +func (f *inflater) flush() os.Error + +func (f *inflater) inflate() (err os.Error) { + final := false; + for err == nil && !final { + for f.nb < 1+2 { + if err = f.moreBits(); err != nil { + return; + } + } + final = f.b & 1 == 1; + f.b >>= 1; + typ := f.b & 3; + f.b >>= 2; + f.nb -= 1+2; + switch typ { + case 0: + err = f.dataBlock(); + case 1: + // compressed, fixed Huffman tables + err = f.decodeBlock(&fixedHuffmanDecoder, nil); + case 2: + // compressed, dynamic Huffman tables + if err = f.readHuffman(); err == nil { + err = f.decodeBlock(&f.h1, &f.h2); + } + default: + // 3 is reserved. + // TODO(rsc): Works around the same 6g bug. + var i int64 = f.getRoffset(); + i--; + err = CorruptInputError(i); + } + } + return; +} + +// RFC 1951 section 3.2.7. +// Compression with dynamic Huffman codes + +var codeOrder = [...]int { + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 +} + +func (f *inflater) 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) { + return os.ErrorString("huff and puff"); + } + + // 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.getRoffset()); + } + 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; + f.nb -= nb; + if i+rep > n { + return CorruptInputError(f.getRoffset()); + } + 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.getRoffset()); + } + + 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 assocated with fixed Huffman blocks. +func (f *inflater) decodeBlock(hl, hd *huffmanDecoder) os.Error { + for { + v, err := f.huffSym(hl); + if err != nil { + return err; + } + var n uint; // number of bits extra + var length int; + switch { + case v < 256: + f.hist[f.hp] = byte(v); + f.hp++; + if f.hp == len(f.hist) { + if err = f.flush(); err != nil { + return err; + } + } + continue; + case v == 256: + return nil; + // otherwise, reference to older data + case v < 265: + length = v - (257 - 3); + n = 0; + case v < 269: + length = v*2 - (265*2 - 11); + n = 1; + case v < 273: + length = v*4 - (269*4 - 19); + n = 2; + case v < 277: + length = v*8 - (273*8 - 35); + n = 3; + case v < 281: + length = v*16 - (277*16 - 67); + n = 4; + case v < 285: + length = v*32 - (281*32 - 131); + n = 5; + default: + length = 258; + n = 0; + } + if n > 0 { + for f.nb < n { + if err = f.moreBits(); err != nil { + return err; + } + } + length += int(f.b & uint32(1<>= n; + f.nb -= n; + } + + var dist int; + if hd == nil { + for f.nb < 5 { + if err = f.moreBits(); err != nil { + return err; + } + } + dist = int(f.b & 0x1F); + f.b >>= 5; + f.nb -= 5; + } else { + if dist, err = f.huffSym(hd); err != nil { + return err; + } + } + + switch { + case dist < 4: + dist++; + case dist >= 30: + return CorruptInputError(f.getRoffset()); + default: + nb := uint(dist - 2) >> 1; + // have 1 bit in bottom of dist, need nb more. + extra := (dist&1) << nb; + for f.nb < nb { + if err = f.moreBits(); err != nil { + return err; + } + } + extra |= int(f.b & uint32(1<>= nb; + f.nb -= nb; + dist = 1<<(nb+1) + 1 + extra; + } + + // Copy history[-dist:-dist+length] into output. + if dist > len(f.hist) { + return InternalError("bad history distance"); + } + + // No check on length; encoding can be prescient. + if !f.hfull && dist > f.hp { + return CorruptInputError(f.getRoffset()); + } + + p := f.hp - dist; + if p < 0 { + p += len(f.hist); + } + for i := 0; i < length; i++ { + f.hist[f.hp] = f.hist[p]; + f.hp++; + p++; + if f.hp == len(f.hist) { + if err = f.flush(); err != nil { + return err; + } + } + if p == len(f.hist) { + p = 0; + } + } + } + panic("unreached"); +} + +// Copy a single uncompressed data block from input to output. +func (f *inflater) dataBlock() os.Error { + // Uncompressed. + // Discard current half-byte. + f.nb = 0; + f.b = 0; + + // Length then ones-complement of length. + nr, err := f.r.Read(f.buf[0:4]); + f.roffset += int64(nr); + if nr < 4 && err == nil { + err = io.ErrEOF; + } + if err != nil { + return &ReadError{f.roffset, err}; + } + n := int(f.buf[0]) | int(f.buf[1])<<8; + nn := int(f.buf[2]) | int(f.buf[3])<<8; + if nn != ^n { + return CorruptInputError(f.getRoffset()); + } + + // Read len bytes into history, + // writing as history fills. + for n > 0 { + m := len(f.hist) - f.hp; + if m > n { + m = n; + } + m, err := f.r.Read(f.hist[f.hp:f.hp+m]); + f.roffset += int64(m); + if m == 0 && err == nil { + err = io.ErrEOF; + } + if err != nil { + return &ReadError{f.roffset, err}; + } + n -= m; + f.hp += m; + if f.hp == len(f.hist) { + if err = f.flush(); err != nil { + return err; + } + } + } + return nil; +} + +func (f *inflater) moreBits() os.Error { + c, err := f.r.ReadByte(); + if err != nil { + 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 *inflater) 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<>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.getRoffset()); +} + +// Flush any buffered output to the underlying writer. +func (f *inflater) flush() os.Error { + if f.hp == 0 { + return nil; + } + n, err := f.w.Write(f.hist[0:f.hp]); + if n != f.hp && err == nil { + err = io.ErrShortWrite; + } + if err != nil { + return &WriteError{f.woffset, err}; + } + f.woffset += int64(f.hp); + f.hp = 0; + f.hfull = true; + return nil; +} + +func makeReader(r io.Reader) Reader { + if rr, ok := r.(Reader); ok { + return rr; + } + return bufio.NewReader(r); +} + +// Inflate reads DEFLATE-compressed data from r and writes +// the uncompressed data to w. +func (f *inflater) inflater(r io.Reader, w io.Writer) os.Error { + var ok bool; // TODO(rsc): why not := on next line? + f.r = makeReader(r); + f.w = w; + f.woffset = 0; + if err := f.inflate(); err != nil { + return err; + } + if err := f.flush(); err != nil { + return err; + } + return nil; +} + +// NewInflater 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 ReadClosed when +// finished reading. +func NewInflater(r io.Reader) io.ReadCloser { + var f inflater; + pr, pw := io.Pipe(); + go func() { + pw.CloseWithError(f.inflater(r, pw)); + }(); + return pr; +} diff --git a/src/pkg/compress/gzip/Makefile b/src/pkg/compress/gzip/Makefile new file mode 100644 index 000000000..514118ae0 --- /dev/null +++ b/src/pkg/compress/gzip/Makefile @@ -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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D=/compress/ + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + gunzip.$O\ + + +phases: a1 +_obj$D/gzip.a: phases + +a1: $(O1) + $(AR) grc _obj$D/gzip.a gunzip.$O + rm -f $(O1) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/gzip.a + +$(O1): newpkg +$(O2): a1 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/gzip.a + +packages: _obj$D/gzip.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/gzip.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/gzip.a diff --git a/src/pkg/compress/gzip/gunzip.go b/src/pkg/compress/gzip/gunzip.go new file mode 100644 index 000000000..32cc3ecb0 --- /dev/null +++ b/src/pkg/compress/gzip/gunzip.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. + +// The gzip package implements reading (and eventually writing) of +// gzip format compressed files, as specified in RFC 1952. +package gzip + +import ( + "bufio"; + "compress/flate"; + "hash"; + "hash/crc32"; + "io"; + "os"; +) + +const ( + gzipID1 = 0x1f; + gzipID2 = 0x8b; + + gzipDeflate = 8; + + flagText = 1<<0; + flagHdrCrc = 1<<1; + flagExtra = 1<<2; + flagName = 1<<3; + flagComment = 1<<4; +) + +func makeReader(r io.Reader) flate.Reader { + if rr, ok := r.(flate.Reader); ok { + return rr; + } + return bufio.NewReader(r); +} + +var HeaderError os.Error = os.ErrorString("invalid gzip header") +var ChecksumError os.Error = os.ErrorString("gzip checksum error") + +// A GzipInflater is an io.Reader that can be read to retrieve +// uncompressed data from a gzip-format compressed file. +// The gzip file stores a header giving metadata about the compressed file. +// That header is exposed as the fields of the GzipInflater struct. +// +// In general, a gzip file can be a concatenation of gzip files, +// each with its own header. Reads from the GzipInflater +// return the concatenation of the uncompressed data of each. +// Only the first header is recorded in the GzipInflater fields. +// +// Gzip files store a length and checksum of the uncompressed data. +// The GzipInflater 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 GzipInflater 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 + + r flate.Reader; + inflater io.Reader; + digest hash.Hash32; + size uint32; + flg byte; + buf [512]byte; + err os.Error; + eof bool; +} + +func (z *GzipInflater) readHeader(save bool) os.Error + +// NewGzipInflater creates a new GzipInflater reading the given reader. +// The implementation buffers input and may read more data than necessary from r. +func NewGzipInflater(r io.Reader) (*GzipInflater, os.Error) { + z := new(GzipInflater); + z.r = makeReader(r); + z.digest = crc32.NewIEEE(); + if err := z.readHeader(true); err != nil { + z.err = err; + return nil, err; + } + return z, nil; +} + +func get4(p []byte) uint32 { + return uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24; +} + +func (z *GzipInflater) 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 { + return string(z.buf[0:i]), nil; + } + } + panic("not reached"); +} + +func (z *GzipInflater) read2() (uint32, os.Error) { + _, err := z.r.Read(z.buf[0:2]); + if err != nil { + return 0, err; + } + return uint32(z.buf[0]) | uint32(z.buf[1])<<8, nil; +} + +func (z *GzipInflater) readHeader(save bool) os.Error { + n, err := io.FullRead(z.r, z.buf[0:10]); + if err != nil { + if n != 0 && err == io.ErrEOF { + return HeaderError; + } + 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); + var nn int; + if nn, err = io.FullRead(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.inflater = flate.NewInflater(z.r); + return nil; +} + +func (z *GzipInflater) Read(p []byte) (n int, err os.Error) { + if z.err != nil { + return 0, z.err; + } + if z.eof || len(p) == 0 { + return 0, nil; + } + + n, err = z.inflater.Read(p); + z.digest.Write(p[0:n]); + z.size += uint32(n); + if n != 0 || err != nil { + z.err = err; + return; + } + + // Finished file; check checksum + size. + if _, err := io.FullRead(z.r, z.buf[0:8]); err != nil { + z.err = err; + return 0, err; + } + if 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? + switch err = z.readHeader(false); { + case err == io.ErrEOF: + err = nil; + z.eof = true; + return; + case err != nil: + z.err = err; + return; + } + + // Yes. Reset and read from it. + z.digest.Reset(); + z.size = 0; + return z.Read(p); +} + diff --git a/src/pkg/compress/gzip/gunzip_test.go b/src/pkg/compress/gzip/gunzip_test.go new file mode 100644 index 000000000..a481de927 --- /dev/null +++ b/src/pkg/compress/gzip/gunzip_test.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 gzip + +import ( + "compress/gzip"; + "fmt"; + "io"; + "testing"; + "os"; +) + +type gzipTest struct { + name string; + raw string; + gzip []byte; + err os.Error; +} + +var gzipTests = []gzipTest { + gzipTest { // has 1 empty fixed-huffman block + "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 + }, + gzipTest { // has 1 non-empty fixed huffman block + "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 + }, + gzipTest { // concatenation + "hello.txt", + "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 + }, + gzipTest { // has dynamic huffman blocks + "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 + }, + gzipTest { // has 1 non-empty fixed huffman block then garbage + "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, 'g', 'a', 'r', 'b', 'a', 'g', 'e', '!', + }, + HeaderError, + }, + gzipTest { // has 1 non-empty fixed huffman block but corrupt checksum + "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, 0xff, 0xff, 0xff, 0xff, 0x0c, 0x00, + 0x00, 0x00, + }, + ChecksumError, + }, + gzipTest { // has 1 non-empty fixed huffman block but corrupt size + "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, 0xff, 0x00, + 0x00, 0x00, + }, + ChecksumError, + }, +} + +func TestGzipInflater(t *testing.T) { + b := new(io.ByteBuffer); + for i, tt := range gzipTests { + in := io.NewByteReader(tt.gzip); + gzip, err := NewGzipInflater(in); + if err != nil { + t.Errorf("%s: NewGzipInflater: %s", tt.name, err); + continue; + } + if tt.name != gzip.Name { + t.Errorf("%s: got name %s", tt.name, gzip.Name); + } + b.Reset(); + n, err := io.Copy(gzip, b); + if err != tt.err { + t.Errorf("%s: io.Copy: %s want %s", tt.name, err, tt.err); + } + s := string(b.Data()); + 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/container/list/Makefile b/src/pkg/container/list/Makefile new file mode 100644 index 000000000..2a647eb2a --- /dev/null +++ b/src/pkg/container/list/Makefile @@ -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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D=/container/ + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + list.$O\ + + +phases: a1 +_obj$D/list.a: phases + +a1: $(O1) + $(AR) grc _obj$D/list.a list.$O + rm -f $(O1) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/list.a + +$(O1): newpkg +$(O2): a1 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/list.a + +packages: _obj$D/list.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/list.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/list.a diff --git a/src/pkg/container/list/list.go b/src/pkg/container/list/list.go new file mode 100755 index 000000000..7e8daa65a --- /dev/null +++ b/src/pkg/container/list/list.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. + +// The list package implements a doubly linked list. +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 contents of this list element. + Value interface {}; +} + +// List represents a doubly linked list. +type List struct { + front, back *Element; +} + +// Init initializes or clears a List. +func (l *List) Init() *List { + l.front = nil; + l.back = nil; + return l +} + +// New returns an initialized list. +func New() *List { + return new(List).Init() +} + +// 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. +func (l *List) Remove(e *Element) { + 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; +} + +func (l *List) insertFront(e *Element) { + e.prev = nil; + e.next = l.front; + l.front = e; + if e.next != nil { + e.next.prev = e; + } else { + l.back = e; + } +} + +func (l *List) insertBack(e *Element) { + e.next = nil; + e.prev = l.back; + l.back = e; + if e.prev != nil { + e.prev.next = e; + } else { + l.front = e; + } +} + +// PushFront inserts the value at the front of the list, and returns a new Element containing it. +func (l *List) PushFront(value interface {}) *Element { + e := &Element{ nil, nil, value }; + l.insertFront(e); + return e +} + +// PushBack inserts the value at the back of the list, and returns a new Element containing it. +func (l *List) PushBack(value interface {}) *Element { + e := &Element{ nil, nil, value }; + l.insertBack(e); + return e +} + +// MoveToFront moves the element to the front of the list. +func (l *List) MoveToFront(e *Element) { + if 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 l.back == e { + return + } + l.Remove(e); + l.insertBack(e); +} + +func (l *List) iterate(c chan <- *Element) { + var next *Element; + for e := l.front; e != nil; e = next { + // Save next in case reader of c changes e. + next = e.next; + c <- e; + } + close(c); +} + +func (l *List) Iter() <-chan *Element { + c := make(chan *Element); + go l.iterate(c); + return c +} diff --git a/src/pkg/container/list/list_test.go b/src/pkg/container/list/list_test.go new file mode 100755 index 000000000..d5b2672e0 --- /dev/null +++ b/src/pkg/container/list/list_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 list + +import ( + "container/list"; + "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 := 0; i < len(es); i++ { + e := es[i]; + 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 TestList(t *testing.T) { + l := New(); + checkListPointers(t, l, []*Element{}); + + // Single element list + e := l.PushFront("a"); + checkListPointers(t, l, []*Element{ e }); + l.MoveToFront(e); + checkListPointers(t, l, []*Element{ e }); + l.MoveToBack(e); + checkListPointers(t, l, []*Element{ e }); + l.Remove(e); + checkListPointers(t, l, []*Element{}); + + // 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 }); + + l.Remove(e2); + checkListPointers(t, l, []*Element{ e1, e3, e4 }); + + 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 }); + + // Clear all elements by iterating + for e := range l.Iter() { + l.Remove(e); + } + checkListPointers(t, l, []*Element{}); +} diff --git a/src/pkg/container/vector/Makefile b/src/pkg/container/vector/Makefile new file mode 100644 index 000000000..20490549d --- /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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D=/container/ + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + vector.$O\ + +O2=\ + intvector.$O\ + stringvector.$O\ + + +phases: a1 a2 +_obj$D/vector.a: phases + +a1: $(O1) + $(AR) grc _obj$D/vector.a vector.$O + rm -f $(O1) + +a2: $(O2) + $(AR) grc _obj$D/vector.a intvector.$O stringvector.$O + rm -f $(O2) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/vector.a + +$(O1): newpkg +$(O2): a1 +$(O3): a2 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/vector.a + +packages: _obj$D/vector.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/vector.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/vector.a diff --git a/src/pkg/container/vector/intvector.go b/src/pkg/container/vector/intvector.go new file mode 100644 index 000000000..c3b62f256 --- /dev/null +++ b/src/pkg/container/vector/intvector.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 vector + +import "container/vector" + +// IntVector is a specialization of Vector that hides the wrapping of Elements around ints. +type IntVector struct { + vector.Vector; +} + + +// Init initializes a new or resized vector. The initial length may be <= 0 to +// request a default length. If initial_len is shorter than the current +// length of the IntVector, trailing elements of the IntVector will be cleared. +func (p *IntVector) Init(len int) *IntVector { + p.Vector.Init(len); + return p; +} + + +// NewIntVector returns an initialized new IntVector with length at least len. +func NewIntVector(len int) *IntVector { + return new(IntVector).Init(len) +} + + +// At returns the i'th element of the vector. +func (p *IntVector) At(i int) int { + return p.Vector.At(i).(int) +} + + +// Set sets the i'th element of the vector to value x. +func (p *IntVector) Set(i int, x int) { + p.a[i] = x +} + + +// Last returns the element in the vector of highest index. +func (p *IntVector) Last() int { + return p.Vector.Last().(int) +} + + +// Data returns all the elements as a slice. +func (p *IntVector) Data() []int { + arr := make([]int, p.Len()); + for i, v := range p.a { + arr[i] = v.(int) + } + 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.Vector.Insert(i, x) +} + + +// 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) { + p.Vector.InsertVector(i, &x.Vector) +} + + +// Slice returns a new IntVector 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 { + return &IntVector{ *p.Vector.Slice(i, j) }; +} + + +// Push appends x to the end of the vector. +func (p *IntVector) Push(x int) { + p.Vector.Push(x) +} + + +// Pop deletes and returns the last element of the vector. +func (p *IntVector) Pop() int { + return p.Vector.Pop().(int) +} + + +// AppendVector appends the entire IntVector x to the end of this vector. +func (p *IntVector) AppendVector(x *IntVector) { + p.Vector.InsertVector(len(p.a), &x.Vector); +} + + +// SortInterface 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.At(i) < p.At(j) +} + + +// Iterate over all elements; driver for range +func (p *IntVector) iterate(c chan int) { + for i, v := range p.a { + c <- v.(int) + } + close(c); +} + + +// Channel iterator for range. +func (p *IntVector) Iter() chan int { + c := make(chan int); + go p.iterate(c); + return c; +} diff --git a/src/pkg/container/vector/stringvector.go b/src/pkg/container/vector/stringvector.go new file mode 100644 index 000000000..18ca11a3f --- /dev/null +++ b/src/pkg/container/vector/stringvector.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 vector + +import "container/vector" + +// StringVector is a specialization of Vector that hides the wrapping of Elements around strings. +type StringVector struct { + vector.Vector; +} + + +// Init initializes a new or resized vector. The initial length may be <= 0 to +// request a default length. If initial_len is shorter than the current +// length of the StringVector, trailing elements of the StringVector will be cleared. +func (p *StringVector) Init(len int) *StringVector { + p.Vector.Init(len); + return p; +} + + +// NewStringVector returns an initialized new StringVector with length at least len. +func NewStringVector(len int) *StringVector { + return new(StringVector).Init(len) +} + + +// At returns the i'th element of the vector. +func (p *StringVector) At(i int) string { + return p.Vector.At(i).(string) +} + + +// Set sets the i'th element of the vector to value x. +func (p *StringVector) Set(i int, x string) { + p.a[i] = x +} + + +// Last returns the element in the vector of highest index. +func (p *StringVector) Last() string { + return p.Vector.Last().(string) +} + + +// Data returns all the elements as a slice. +func (p *StringVector) Data() []string { + arr := make([]string, p.Len()); + for i, v := range p.a { + arr[i] = v.(string) + } + 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.Vector.Insert(i, x) +} + + +// 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) { + p.Vector.InsertVector(i, &x.Vector) +} + + +// Slice returns a new StringVector 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 { + return &StringVector{ *p.Vector.Slice(i, j) }; +} + + +// Push appends x to the end of the vector. +func (p *StringVector) Push(x string) { + p.Vector.Push(x) +} + + +// Pop deletes and returns the last element of the vector. +func (p *StringVector) Pop() string { + return p.Vector.Pop().(string) +} + + +// AppendVector appends the entire StringVector x to the end of this vector. +func (p *StringVector) AppendVector(x *StringVector) { + p.Vector.InsertVector(len(p.a), &x.Vector); +} + + +// SortInterface support +// 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.At(i) < p.At(j) +} + + +// Iterate over all elements; driver for range +func (p *StringVector) iterate(c chan string) { + for i, v := range p.a { + c <- v.(string) + } + close(c); +} + + +// Channel iterator for range. +func (p *StringVector) Iter() chan string { + c := make(chan string); + go p.iterate(c); + return c; +} diff --git a/src/pkg/container/vector/vector.go b/src/pkg/container/vector/vector.go new file mode 100644 index 000000000..5b5cad21c --- /dev/null +++ b/src/pkg/container/vector/vector.go @@ -0,0 +1,244 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// The vector package implements an efficient container for managing +// linear arrays of elements. Unlike arrays, vectors can change size dynamically. +package vector + +// Element is an empty-interface object representing the contents of +// a cell in the vector. +type Element interface {} + + +// Vector is the container itself. +type Vector struct { + a []Element +} + + +func copy(dst, src []Element) { + for i := 0; i < len(src); i++ { + dst[i] = src[i] + } +} + + +// Insert n elements at position i. +func expand(a []Element, i, n int) []Element { + // 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 + b := make([]Element, len1, capb); + copy(b, a); + a = b + } + + // make a hole + for j := len0-1; j >= i ; j-- { + a[j+n] = a[j] + } + return a +} + + +// Init initializes a new or resized vector. The initial_len may be <= 0 to +// request a default length. If initial_len is shorter than the current +// length of the Vector, trailing elements of the Vector will be cleared. +func (p *Vector) Init(initial_len int) *Vector { + a := p.a; + + if cap(a) == 0 || cap(a) < initial_len { + n := 8; // initial capacity + if initial_len > n { + n = initial_len + } + a = make([]Element, n); + } else { + // nil out entries + for j := len(a) - 1; j >= 0; j-- { + a[j] = nil + } + } + + p.a = a[0 : initial_len]; + return p +} + + +// New returns an initialized new Vector with length at least len. +func New(len int) *Vector { + return new(Vector).Init(len) +} + + +// Len returns the number of elements in the vector. +// Len is 0 if p == nil. +func (p *Vector) Len() int { + if p == nil { + return 0; + } + return len(p.a) +} + + +// At returns the i'th element of the vector. +func (p *Vector) At(i int) Element { + return p.a[i] +} + + +// Set sets the i'th element of the vector to value x. +func (p *Vector) Set(i int, x Element) { + p.a[i] = x +} + + +// Last returns the element in the vector of highest index. +func (p *Vector) Last() Element { + return p.a[len(p.a) - 1] +} + + +// Data returns all the elements as a slice. +func (p *Vector) Data() []Element { + arr := make([]Element, p.Len()); + for i, v := range p.a { + arr[i] = v + } + 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 Element) { + p.a = expand(p.a, i, 1); + p.a[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.a; + n := len(a); + + copy(a[i : n-1], a[i+1 : n]); + a[n-1] = nil; // support GC, nil out entry + p.a = 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) { + p.a = expand(p.a, i, len(x.a)); + copy(p.a[i : i + len(x.a)], x.a); +} + + +// Cut deletes elements i through j-1, inclusive. +func (p *Vector) Cut(i, j int) { + a := p.a; + n := len(a); + m := n - (j - i); + + copy(a[i : m], a[j : n]); + for k := m; k < n; k++ { + a[k] = nil // support GC, nil out entries + } + + p.a = a[0 : m]; +} + + +// Slice returns a new 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 { + s := New(j - i); // will fail in Init() if j < j + copy(s.a, p.a[i : j]); + return s; +} + + +// Do calls function f for each element of the vector, in order. +// The function should not change the indexing of the vector underfoot. +func (p *Vector) Do(f func(elem Element)) { + for i := 0; i < len(p.a); i++ { + f(p.a[i]) // not too safe if f changes the Vector + } +} + + +// Convenience wrappers + +// Push appends x to the end of the vector. +func (p *Vector) Push(x Element) { + p.Insert(len(p.a), x) +} + + +// Pop deletes the last element of the vector. +func (p *Vector) Pop() Element { + i := len(p.a) - 1; + x := p.a[i]; + p.a[i] = nil; // support GC, nil out entry + p.a = 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.a), x); +} + + +// Partial SortInterface support + +// LessInterface provides partial support of the SortInterface. +type LessInterface interface { + Less(y Element) 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.a[i].(LessInterface).Less(p.a[j]) +} + + +// Swap exchanges the elements at indexes i and j. +func (p *Vector) Swap(i, j int) { + a := p.a; + a[i], a[j] = a[j], a[i] +} + + +// Iterate over all elements; driver for range +func (p *Vector) iterate(c chan Element) { + for i, v := range p.a { + c <- v + } + close(c); +} + + +// Channel iterator for range. +func (p *Vector) Iter() chan Element { + c := make(chan Element); + go p.iterate(c); + return c; +} diff --git a/src/pkg/container/vector/vector_test.go b/src/pkg/container/vector/vector_test.go new file mode 100644 index 000000000..2a9819394 --- /dev/null +++ b/src/pkg/container/vector/vector_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 vector + +import "container/vector" +import "testing" +import "sort" +import "fmt" + + +func TestZeroLen(t *testing.T) { + var a *vector.Vector; + if a.Len() != 0 { t.Errorf("A) expected 0, got %d", a.Len()); } + a = vector.New(0); + if a.Len() != 0 { t.Errorf("B) expected 0, got %d", a.Len()); } +} + + +func TestInit(t *testing.T) { + var a vector.Vector; + if a.Init(0).Len() != 0 { t.Error("A") } + if a.Init(1).Len() != 1 { t.Error("B") } + if a.Init(10).Len() != 10 { t.Error("C") } +} + + +func TestNew(t *testing.T) { + if vector.New(0).Len() != 0 { t.Error("A") } + if vector.New(1).Len() != 1 { t.Error("B") } + if vector.New(10).Len() != 10 { t.Error("C") } +} + + +func val(i int) int { + return i*991 - 1234 +} + + +func TestAccess(t *testing.T) { + const n = 100; + var a vector.Vector; + a.Init(n); + for i := 0; i < n; i++ { + a.Set(i, val(i)); + } + for i := 0; i < n; i++ { + if a.At(i).(int) != val(i) { t.Error(i) } + } +} + + +func TestInsertDeleteClear(t *testing.T) { + const n = 100; + a := vector.New(0); + + for i := 0; i < n; i++ { + if a.Len() != i { t.Errorf("A) wrong len %d (expected %d)", a.Len(), i) } + a.Insert(0, val(i)); + if a.Last().(int) != val(0) { t.Error("B") } + } + for i := n-1; i >= 0; i-- { + if a.Last().(int) != val(0) { t.Error("C") } + if a.At(0).(int) != val(i) { t.Error("D") } + a.Delete(0); + if a.Len() != i { t.Errorf("E) wrong len %d (expected %d)", a.Len(), i) } + } + + if a.Len() != 0 { t.Errorf("F) wrong len %d (expected 0)", a.Len()) } + for i := 0; i < n; i++ { + a.Push(val(i)); + if a.Len() != i+1 { t.Errorf("G) wrong len %d (expected %d)", a.Len(), i+1) } + if a.Last().(int) != val(i) { t.Error("H") } + } + a.Init(0); + if a.Len() != 0 { t.Errorf("I wrong len %d (expected 0)", a.Len()) } + + const m = 5; + for j := 0; j < m; j++ { + a.Push(j); + for i := 0; i < n; i++ { + x := val(i); + a.Push(x); + if a.Pop().(int) != x { t.Error("J") } + if a.Len() != j+1 { t.Errorf("K) wrong len %d (expected %d)", a.Len(), j+1) } + } + } + if a.Len() != m { t.Errorf("L) wrong len %d (expected %d)", a.Len(), m) } +} + + +func verify_slice(t *testing.T, x *vector.Vector, elt, i, j int) { + for k := i; k < j; k++ { + if x.At(k).(int) != elt { + t.Errorf("M) wrong [%d] element %d (expected %d)", k, x.At(k).(int), elt) + } + } + + s := x.Slice(i, j); + for k, n := 0, j-i; k < n; k++ { + if s.At(k).(int) != elt { + t.Errorf("N) wrong [%d] element %d (expected %d)", k, x.At(k).(int), elt) + } + } +} + + +func verify_pattern(t *testing.T, x *vector.Vector, a, b, c int) { + n := a + b + c; + if x.Len() != n { + t.Errorf("O) wrong len %d (expected %d)", x.Len(), 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.Vector { + x := vector.New(len); + for i := 0; i < len; i++ { + x.Set(i, 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); +} + + +// This also tests IntVector and StringVector +func TestSorting(t *testing.T) { + const n = 100; + + a := vector.NewIntVector(n); + for i := n-1; i >= 0; i-- { + a.Set(i, n-1-i); + } + if sort.IsSorted(a) { t.Error("int vector not sorted") } + + b := vector.NewStringVector(n); + 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 TestDo(t *testing.T) { + const n = 25; + const salt = 17; + a := vector.NewIntVector(n); + for i := 0; i < n; i++ { + a.Set(i, salt * i); + } + count := 0; + a.Do( + func(e vector.Element) { + i := e.(int); + if i != count*salt { + t.Error("value at", count, "should be", count*salt, "not", i) + } + count++; + } + ); + if count != n { + t.Error("should visit", n, "values; did visit", count) + } +} + +func TestIter(t *testing.T) { + const Len = 100; + x := vector.New(Len); + for i := 0; i < Len; i++ { + x.Set(i, i*i); + } + i := 0; + for v := range x.Iter() { + if v.(int) != i*i { + t.Error("Iter expected", i*i, "got", v.(int)) + } + i++; + } + if i != Len { + t.Error("Iter stopped at", i, "not", Len) + } +} diff --git a/src/pkg/crypto/aes/Makefile b/src/pkg/crypto/aes/Makefile new file mode 100644 index 000000000..c62275b3c --- /dev/null +++ b/src/pkg/crypto/aes/Makefile @@ -0,0 +1,76 @@ +# Copyright 2009 The Go Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D=/crypto/ + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + const.$O\ + +O2=\ + block.$O\ + +O3=\ + cipher.$O\ + + +phases: a1 a2 a3 +_obj$D/aes.a: phases + +a1: $(O1) + $(AR) grc _obj$D/aes.a const.$O + rm -f $(O1) + +a2: $(O2) + $(AR) grc _obj$D/aes.a block.$O + rm -f $(O2) + +a3: $(O3) + $(AR) grc _obj$D/aes.a cipher.$O + rm -f $(O3) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/aes.a + +$(O1): newpkg +$(O2): a1 +$(O3): a2 +$(O4): a3 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/aes.a + +packages: _obj$D/aes.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/aes.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/aes.a diff --git a/src/pkg/crypto/aes/aes_test.go b/src/pkg/crypto/aes/aes_test.go new file mode 100644 index 000000000..2f6cb4a92 --- /dev/null +++ b/src/pkg/crypto/aes/aes_test.go @@ -0,0 +1,353 @@ +// Copyright 2009 The Go Authors. 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 ( + "crypto/aes"; + "fmt"; + "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<>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 { + 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, + }, + }, + KeyTest { + // A.2. Expansion of a 192-bit Cipher Key + []byte { + 0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5, + 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, + }, + KeyTest { + // A.3. Expansion of a 256-bit Cipher Key + []byte { + 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, + 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 { + CryptTest { + // Appendix B. + []byte { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c, }, + []byte { 0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d, 0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34, }, + []byte { 0x39, 0x25, 0x84, 0x1d, 0x02, 0xdc, 0x09, 0xfb, 0xdc, 0x11, 0x85, 0x97, 0x19, 0x6a, 0x0b, 0x32, }, + }, + CryptTest { + // Appendix C.1. AES-128 + []byte { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, }, + []byte { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, }, + []byte { 0x69, 0xc4, 0xe0, 0xd8, 0x6a, 0x7b, 0x04, 0x30, 0xd8, 0xcd, 0xb7, 0x80, 0x70, 0xb4, 0xc5, 0x5a, }, + }, + CryptTest { + // Appendix C.2. AES-192 + []byte { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, }, + []byte { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, }, + []byte { 0xdd, 0xa9, 0x7c, 0xa4, 0x86, 0x4c, 0xdf, 0xe0, 0x6e, 0xaf, 0x70, 0xa0, 0xec, 0x0d, 0x71, 0x91, }, + }, + CryptTest { + // Appendix C.3. AES-256 + []byte { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, }, + []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, tt.in, out); + 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, tt.out, plain); + 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(tt.in, out); + 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(tt.out, plain); + 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..3c67d1c3c --- /dev/null +++ b/src/pkg/crypto/aes/block.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. + +// 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 +// @author Antoon Bosselaers +// @author Paulo Barreto +// +// 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 + +import "crypto/aes" + +// Encrypt one block from src into dst, using the expanded key xk. +func encryptBlock(xk []uint32, src, dst []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, src, dst []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..fd8e43e16 --- /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 ( + "crypto/aes"; + "os"; +) + +// 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; +} + +// 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) { + switch len(key) { + default: + return nil, os.ErrorString("crypto/aes: invalid key size"); + case 16, 24, 32: + break; + } + + n := len(key) + 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 Key interface in the +// package "crypto/modes". +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 AESCBC (see modes.go). +func (c *Cipher) Encrypt(src, dst []byte) { + encryptBlock(c.enc, src, dst); +} + +// Decrypt decrypts the 16-byte buffer src using the key k +// and stores the result in dst. +func (c *Cipher) Decrypt(src, dst []byte) { + decryptBlock(c.dec, src, dst); +} + +// 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..9167d602d --- /dev/null +++ b/src/pkg/crypto/aes/const.go @@ -0,0 +1,363 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// AES constants - 8720 bytes of initialized data. + +// This package implements AES encryption (formerly Rijndael), +// as defined in U.S. Federal Information Processing Standards Publication 197. +package aes + +// http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf + +// AES is based on the mathematical behavior of binary polynomials +// (polynomials over GF(2)) modulo the irreducible polynomial x⁸ + x⁴ + x² + x + 1. +// Addition of these binary polynomials corresponds to binary xor. +// Reducing mod poly corresponds to binary xor with poly every +// time a 0x100 bit appears. +const poly = 1<<8 | 1<<4 | 1<<3 | 1<<1 | 1<<0; // x⁸ + x⁴ + x² + x + 1 + +// Powers of x mod poly in GF(2). +var powx = [16]byte{ + 0x01, + 0x02, + 0x04, + 0x08, + 0x10, + 0x20, + 0x40, + 0x80, + 0x1b, + 0x36, + 0x6c, + 0xd8, + 0xab, + 0x4d, + 0x9a, + 0x2f, +} + +// FIPS-197 Figure 7. S-box substitution values in hexadecimal format. +var sbox0 = [256]byte { + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16, +} + +// FIPS-197 Figure 14. Inverse S-box substitution values in hexadecimal format. +var sbox1 = [256]byte { + 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, + 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, + 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, + 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, + 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, + 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, + 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, + 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, + 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, + 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, + 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, + 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, + 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, + 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, + 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d, +} + +// Lookup tables for encryption. +// These can be recomputed by adapting the tests in aes_test.go. + +var te = [4][256]uint32 { + [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, + }, + [256]uint32 { + 0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b, 0x0dfff2f2, 0xbdd66b6b, 0xb1de6f6f, 0x5491c5c5, + 0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b, 0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676, + 0x458fcaca, 0x9d1f8282, 0x4089c9c9, 0x87fa7d7d, 0x15effafa, 0xebb25959, 0xc98e4747, 0x0bfbf0f0, + 0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf, 0xbf239c9c, 0xf753a4a4, 0x96e47272, 0x5b9bc0c0, + 0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626, 0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc, + 0x5c683434, 0xf451a5a5, 0x34d1e5e5, 0x08f9f1f1, 0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515, + 0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3, 0x28301818, 0xa1379696, 0x0f0a0505, 0xb52f9a9a, + 0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2, 0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575, + 0x1b120909, 0x9e1d8383, 0x74582c2c, 0x2e341a1a, 0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0, + 0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3, 0x7b522929, 0x3edde3e3, 0x715e2f2f, 0x97138484, + 0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded, 0x60402020, 0x1fe3fcfc, 0xc879b1b1, 0xedb65b5b, + 0xbed46a6a, 0x468dcbcb, 0xd967bebe, 0x4b723939, 0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf, + 0x6bbbd0d0, 0x2ac5efef, 0xe54faaaa, 0x16edfbfb, 0xc5864343, 0xd79a4d4d, 0x55663333, 0x94118585, + 0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f, 0xf0a05050, 0x44783c3c, 0xba259f9f, 0xe34ba8a8, + 0xf3a25151, 0xfe5da3a3, 0xc0804040, 0x8a058f8f, 0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5, + 0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121, 0x30201010, 0x1ae5ffff, 0x0efdf3f3, 0x6dbfd2d2, + 0x4c81cdcd, 0x14180c0c, 0x35261313, 0x2fc3ecec, 0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717, + 0x5793c4c4, 0xf255a7a7, 0x82fc7e7e, 0x477a3d3d, 0xacc86464, 0xe7ba5d5d, 0x2b321919, 0x95e67373, + 0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc, 0x66442222, 0x7e542a2a, 0xab3b9090, 0x830b8888, + 0xca8c4646, 0x29c7eeee, 0xd36bb8b8, 0x3c281414, 0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb, + 0x3bdbe0e0, 0x56643232, 0x4e743a3a, 0x1e140a0a, 0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c, + 0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262, 0xa8399191, 0xa4319595, 0x37d3e4e4, 0x8bf27979, + 0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d, 0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9, + 0xb4d86c6c, 0xfaac5656, 0x07f3f4f4, 0x25cfeaea, 0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808, + 0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e, 0x24381c1c, 0xf157a6a6, 0xc773b4b4, 0x5197c6c6, + 0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f, 0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a, + 0x90e07070, 0x427c3e3e, 0xc471b5b5, 0xaacc6666, 0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e, + 0xa3c26161, 0x5f6a3535, 0xf9ae5757, 0xd069b9b9, 0x91178686, 0x5899c1c1, 0x273a1d1d, 0xb9279e9e, + 0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111, 0xbbd26969, 0x70a9d9d9, 0x89078e8e, 0xa7339494, + 0xb62d9b9b, 0x223c1e1e, 0x92158787, 0x20c9e9e9, 0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf, + 0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d, 0xda65bfbf, 0x31d7e6e6, 0xc6844242, 0xb8d06868, + 0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f, 0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616, + }, + [256]uint32 { + 0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b, 0xf20dfff2, 0x6bbdd66b, 0x6fb1de6f, 0xc55491c5, + 0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b, 0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76, + 0xca458fca, 0x829d1f82, 0xc94089c9, 0x7d87fa7d, 0xfa15effa, 0x59ebb259, 0x47c98e47, 0xf00bfbf0, + 0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af, 0x9cbf239c, 0xa4f753a4, 0x7296e472, 0xc05b9bc0, + 0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26, 0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc, + 0x345c6834, 0xa5f451a5, 0xe534d1e5, 0xf108f9f1, 0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15, + 0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3, 0x18283018, 0x96a13796, 0x050f0a05, 0x9ab52f9a, + 0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2, 0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75, + 0x091b1209, 0x839e1d83, 0x2c74582c, 0x1a2e341a, 0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0, + 0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3, 0x297b5229, 0xe33edde3, 0x2f715e2f, 0x84971384, + 0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed, 0x20604020, 0xfc1fe3fc, 0xb1c879b1, 0x5bedb65b, + 0x6abed46a, 0xcb468dcb, 0xbed967be, 0x394b7239, 0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf, + 0xd06bbbd0, 0xef2ac5ef, 0xaae54faa, 0xfb16edfb, 0x43c58643, 0x4dd79a4d, 0x33556633, 0x85941185, + 0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f, 0x50f0a050, 0x3c44783c, 0x9fba259f, 0xa8e34ba8, + 0x51f3a251, 0xa3fe5da3, 0x40c08040, 0x8f8a058f, 0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5, + 0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221, 0x10302010, 0xff1ae5ff, 0xf30efdf3, 0xd26dbfd2, + 0xcd4c81cd, 0x0c14180c, 0x13352613, 0xec2fc3ec, 0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17, + 0xc45793c4, 0xa7f255a7, 0x7e82fc7e, 0x3d477a3d, 0x64acc864, 0x5de7ba5d, 0x192b3219, 0x7395e673, + 0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc, 0x22664422, 0x2a7e542a, 0x90ab3b90, 0x88830b88, + 0x46ca8c46, 0xee29c7ee, 0xb8d36bb8, 0x143c2814, 0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb, + 0xe03bdbe0, 0x32566432, 0x3a4e743a, 0x0a1e140a, 0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c, + 0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462, 0x91a83991, 0x95a43195, 0xe437d3e4, 0x798bf279, + 0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d, 0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9, + 0x6cb4d86c, 0x56faac56, 0xf407f3f4, 0xea25cfea, 0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008, + 0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e, 0x1c24381c, 0xa6f157a6, 0xb4c773b4, 0xc65197c6, + 0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f, 0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a, + 0x7090e070, 0x3e427c3e, 0xb5c471b5, 0x66aacc66, 0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e, + 0x61a3c261, 0x355f6a35, 0x57f9ae57, 0xb9d069b9, 0x86911786, 0xc15899c1, 0x1d273a1d, 0x9eb9279e, + 0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211, 0x69bbd269, 0xd970a9d9, 0x8e89078e, 0x94a73394, + 0x9bb62d9b, 0x1e223c1e, 0x87921587, 0xe920c9e9, 0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df, + 0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d, 0xbfda65bf, 0xe631d7e6, 0x42c68442, 0x68b8d068, + 0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f, 0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16, + }, + [256]uint32 { + 0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6, 0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491, + 0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56, 0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec, + 0xcaca458f, 0x82829d1f, 0xc9c94089, 0x7d7d87fa, 0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb, + 0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45, 0x9c9cbf23, 0xa4a4f753, 0x727296e4, 0xc0c05b9b, + 0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c, 0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83, + 0x34345c68, 0xa5a5f451, 0xe5e534d1, 0xf1f108f9, 0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a, + 0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d, 0x18182830, 0x9696a137, 0x05050f0a, 0x9a9ab52f, + 0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf, 0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea, + 0x09091b12, 0x83839e1d, 0x2c2c7458, 0x1a1a2e34, 0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b, + 0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d, 0x29297b52, 0xe3e33edd, 0x2f2f715e, 0x84849713, + 0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1, 0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6, + 0x6a6abed4, 0xcbcb468d, 0xbebed967, 0x39394b72, 0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85, + 0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed, 0x4343c586, 0x4d4dd79a, 0x33335566, 0x85859411, + 0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe, 0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b, + 0x5151f3a2, 0xa3a3fe5d, 0x4040c080, 0x8f8f8a05, 0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1, + 0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342, 0x10103020, 0xffff1ae5, 0xf3f30efd, 0xd2d26dbf, + 0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3, 0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e, + 0xc4c45793, 0xa7a7f255, 0x7e7e82fc, 0x3d3d477a, 0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6, + 0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3, 0x22226644, 0x2a2a7e54, 0x9090ab3b, 0x8888830b, + 0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28, 0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad, + 0xe0e03bdb, 0x32325664, 0x3a3a4e74, 0x0a0a1e14, 0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8, + 0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4, 0x9191a839, 0x9595a431, 0xe4e437d3, 0x79798bf2, + 0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da, 0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049, + 0x6c6cb4d8, 0x5656faac, 0xf4f407f3, 0xeaea25cf, 0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810, + 0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c, 0x1c1c2438, 0xa6a6f157, 0xb4b4c773, 0xc6c65197, + 0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e, 0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f, + 0x707090e0, 0x3e3e427c, 0xb5b5c471, 0x6666aacc, 0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c, + 0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069, 0x86869117, 0xc1c15899, 0x1d1d273a, 0x9e9eb927, + 0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322, 0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733, + 0x9b9bb62d, 0x1e1e223c, 0x87879215, 0xe9e920c9, 0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5, + 0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a, 0xbfbfda65, 0xe6e631d7, 0x4242c684, 0x6868b8d0, + 0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e, 0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c, + }, +} + +// Lookup tables for decryption. +// These can be recomputed by adapting the tests in aes_test.go. + +var td = [4][256]uint32 { + [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, + }, + [256]uint32 { + 0x5051f4a7, 0x537e4165, 0xc31a17a4, 0x963a275e, 0xcb3bab6b, 0xf11f9d45, 0xabacfa58, 0x934be303, + 0x552030fa, 0xf6ad766d, 0x9188cc76, 0x25f5024c, 0xfc4fe5d7, 0xd7c52acb, 0x80263544, 0x8fb562a3, + 0x49deb15a, 0x6725ba1b, 0x9845ea0e, 0xe15dfec0, 0x02c32f75, 0x12814cf0, 0xa38d4697, 0xc66bd3f9, + 0xe7038f5f, 0x9515929c, 0xebbf6d7a, 0xda955259, 0x2dd4be83, 0xd3587421, 0x2949e069, 0x448ec9c8, + 0x6a75c289, 0x78f48e79, 0x6b99583e, 0xdd27b971, 0xb6bee14f, 0x17f088ad, 0x66c920ac, 0xb47dce3a, + 0x1863df4a, 0x82e51a31, 0x60975133, 0x4562537f, 0xe0b16477, 0x84bb6bae, 0x1cfe81a0, 0x94f9082b, + 0x58704868, 0x198f45fd, 0x8794de6c, 0xb7527bf8, 0x23ab73d3, 0xe2724b02, 0x57e31f8f, 0x2a6655ab, + 0x07b2eb28, 0x032fb5c2, 0x9a86c57b, 0xa5d33708, 0xf2302887, 0xb223bfa5, 0xba02036a, 0x5ced1682, + 0x2b8acf1c, 0x92a779b4, 0xf0f307f2, 0xa14e69e2, 0xcd65daf4, 0xd50605be, 0x1fd13462, 0x8ac4a6fe, + 0x9d342e53, 0xa0a2f355, 0x32058ae1, 0x75a4f6eb, 0x390b83ec, 0xaa4060ef, 0x065e719f, 0x51bd6e10, + 0xf93e218a, 0x3d96dd06, 0xaedd3e05, 0x464de6bd, 0xb591548d, 0x0571c45d, 0x6f0406d4, 0xff605015, + 0x241998fb, 0x97d6bde9, 0xcc894043, 0x7767d99e, 0xbdb0e842, 0x8807898b, 0x38e7195b, 0xdb79c8ee, + 0x47a17c0a, 0xe97c420f, 0xc9f8841e, 0x00000000, 0x83098086, 0x48322bed, 0xac1e1170, 0x4e6c5a72, + 0xfbfd0eff, 0x560f8538, 0x1e3daed5, 0x27362d39, 0x640a0fd9, 0x21685ca6, 0xd19b5b54, 0x3a24362e, + 0xb10c0a67, 0x0f9357e7, 0xd2b4ee96, 0x9e1b9b91, 0x4f80c0c5, 0xa261dc20, 0x695a774b, 0x161c121a, + 0x0ae293ba, 0xe5c0a02a, 0x433c22e0, 0x1d121b17, 0x0b0e090d, 0xadf28bc7, 0xb92db6a8, 0xc8141ea9, + 0x8557f119, 0x4caf7507, 0xbbee99dd, 0xfda37f60, 0x9ff70126, 0xbc5c72f5, 0xc544663b, 0x345bfb7e, + 0x768b4329, 0xdccb23c6, 0x68b6edfc, 0x63b8e4f1, 0xcad731dc, 0x10426385, 0x40139722, 0x2084c611, + 0x7d854a24, 0xf8d2bb3d, 0x11aef932, 0x6dc729a1, 0x4b1d9e2f, 0xf3dcb230, 0xec0d8652, 0xd077c1e3, + 0x6c2bb316, 0x99a970b9, 0xfa119448, 0x2247e964, 0xc4a8fc8c, 0x1aa0f03f, 0xd8567d2c, 0xef223390, + 0xc787494e, 0xc1d938d1, 0xfe8ccaa2, 0x3698d40b, 0xcfa6f581, 0x28a57ade, 0x26dab78e, 0xa43fadbf, + 0xe42c3a9d, 0x0d507892, 0x9b6a5fcc, 0x62547e46, 0xc2f68d13, 0xe890d8b8, 0x5e2e39f7, 0xf582c3af, + 0xbe9f5d80, 0x7c69d093, 0xa96fd52d, 0xb3cf2512, 0x3bc8ac99, 0xa710187d, 0x6ee89c63, 0x7bdb3bbb, + 0x09cd2678, 0xf46e5918, 0x01ec9ab7, 0xa8834f9a, 0x65e6956e, 0x7eaaffe6, 0x0821bccf, 0xe6ef15e8, + 0xd9bae79b, 0xce4a6f36, 0xd4ea9f09, 0xd629b07c, 0xaf31a4b2, 0x312a3f23, 0x30c6a594, 0xc035a266, + 0x37744ebc, 0xa6fc82ca, 0xb0e090d0, 0x1533a7d8, 0x4af10498, 0xf741ecda, 0x0e7fcd50, 0x2f1791f6, + 0x8d764dd6, 0x4d43efb0, 0x54ccaa4d, 0xdfe49604, 0xe39ed1b5, 0x1b4c6a88, 0xb8c12c1f, 0x7f466551, + 0x049d5eea, 0x5d018c35, 0x73fa8774, 0x2efb0b41, 0x5ab3671d, 0x5292dbd2, 0x33e91056, 0x136dd647, + 0x8c9ad761, 0x7a37a10c, 0x8e59f814, 0x89eb133c, 0xeecea927, 0x35b761c9, 0xede11ce5, 0x3c7a47b1, + 0x599cd2df, 0x3f55f273, 0x791814ce, 0xbf73c737, 0xea53f7cd, 0x5b5ffdaa, 0x14df3d6f, 0x867844db, + 0x81caaff3, 0x3eb968c4, 0x2c382434, 0x5fc2a340, 0x72161dc3, 0x0cbce225, 0x8b283c49, 0x41ff0d95, + 0x7139a801, 0xde080cb3, 0x9cd8b4e4, 0x906456c1, 0x617bcb84, 0x70d532b6, 0x74486c5c, 0x42d0b857, + }, + [256]uint32 { + 0xa75051f4, 0x65537e41, 0xa4c31a17, 0x5e963a27, 0x6bcb3bab, 0x45f11f9d, 0x58abacfa, 0x03934be3, + 0xfa552030, 0x6df6ad76, 0x769188cc, 0x4c25f502, 0xd7fc4fe5, 0xcbd7c52a, 0x44802635, 0xa38fb562, + 0x5a49deb1, 0x1b6725ba, 0x0e9845ea, 0xc0e15dfe, 0x7502c32f, 0xf012814c, 0x97a38d46, 0xf9c66bd3, + 0x5fe7038f, 0x9c951592, 0x7aebbf6d, 0x59da9552, 0x832dd4be, 0x21d35874, 0x692949e0, 0xc8448ec9, + 0x896a75c2, 0x7978f48e, 0x3e6b9958, 0x71dd27b9, 0x4fb6bee1, 0xad17f088, 0xac66c920, 0x3ab47dce, + 0x4a1863df, 0x3182e51a, 0x33609751, 0x7f456253, 0x77e0b164, 0xae84bb6b, 0xa01cfe81, 0x2b94f908, + 0x68587048, 0xfd198f45, 0x6c8794de, 0xf8b7527b, 0xd323ab73, 0x02e2724b, 0x8f57e31f, 0xab2a6655, + 0x2807b2eb, 0xc2032fb5, 0x7b9a86c5, 0x08a5d337, 0x87f23028, 0xa5b223bf, 0x6aba0203, 0x825ced16, + 0x1c2b8acf, 0xb492a779, 0xf2f0f307, 0xe2a14e69, 0xf4cd65da, 0xbed50605, 0x621fd134, 0xfe8ac4a6, + 0x539d342e, 0x55a0a2f3, 0xe132058a, 0xeb75a4f6, 0xec390b83, 0xefaa4060, 0x9f065e71, 0x1051bd6e, + 0x8af93e21, 0x063d96dd, 0x05aedd3e, 0xbd464de6, 0x8db59154, 0x5d0571c4, 0xd46f0406, 0x15ff6050, + 0xfb241998, 0xe997d6bd, 0x43cc8940, 0x9e7767d9, 0x42bdb0e8, 0x8b880789, 0x5b38e719, 0xeedb79c8, + 0x0a47a17c, 0x0fe97c42, 0x1ec9f884, 0x00000000, 0x86830980, 0xed48322b, 0x70ac1e11, 0x724e6c5a, + 0xfffbfd0e, 0x38560f85, 0xd51e3dae, 0x3927362d, 0xd9640a0f, 0xa621685c, 0x54d19b5b, 0x2e3a2436, + 0x67b10c0a, 0xe70f9357, 0x96d2b4ee, 0x919e1b9b, 0xc54f80c0, 0x20a261dc, 0x4b695a77, 0x1a161c12, + 0xba0ae293, 0x2ae5c0a0, 0xe0433c22, 0x171d121b, 0x0d0b0e09, 0xc7adf28b, 0xa8b92db6, 0xa9c8141e, + 0x198557f1, 0x074caf75, 0xddbbee99, 0x60fda37f, 0x269ff701, 0xf5bc5c72, 0x3bc54466, 0x7e345bfb, + 0x29768b43, 0xc6dccb23, 0xfc68b6ed, 0xf163b8e4, 0xdccad731, 0x85104263, 0x22401397, 0x112084c6, + 0x247d854a, 0x3df8d2bb, 0x3211aef9, 0xa16dc729, 0x2f4b1d9e, 0x30f3dcb2, 0x52ec0d86, 0xe3d077c1, + 0x166c2bb3, 0xb999a970, 0x48fa1194, 0x642247e9, 0x8cc4a8fc, 0x3f1aa0f0, 0x2cd8567d, 0x90ef2233, + 0x4ec78749, 0xd1c1d938, 0xa2fe8cca, 0x0b3698d4, 0x81cfa6f5, 0xde28a57a, 0x8e26dab7, 0xbfa43fad, + 0x9de42c3a, 0x920d5078, 0xcc9b6a5f, 0x4662547e, 0x13c2f68d, 0xb8e890d8, 0xf75e2e39, 0xaff582c3, + 0x80be9f5d, 0x937c69d0, 0x2da96fd5, 0x12b3cf25, 0x993bc8ac, 0x7da71018, 0x636ee89c, 0xbb7bdb3b, + 0x7809cd26, 0x18f46e59, 0xb701ec9a, 0x9aa8834f, 0x6e65e695, 0xe67eaaff, 0xcf0821bc, 0xe8e6ef15, + 0x9bd9bae7, 0x36ce4a6f, 0x09d4ea9f, 0x7cd629b0, 0xb2af31a4, 0x23312a3f, 0x9430c6a5, 0x66c035a2, + 0xbc37744e, 0xcaa6fc82, 0xd0b0e090, 0xd81533a7, 0x984af104, 0xdaf741ec, 0x500e7fcd, 0xf62f1791, + 0xd68d764d, 0xb04d43ef, 0x4d54ccaa, 0x04dfe496, 0xb5e39ed1, 0x881b4c6a, 0x1fb8c12c, 0x517f4665, + 0xea049d5e, 0x355d018c, 0x7473fa87, 0x412efb0b, 0x1d5ab367, 0xd25292db, 0x5633e910, 0x47136dd6, + 0x618c9ad7, 0x0c7a37a1, 0x148e59f8, 0x3c89eb13, 0x27eecea9, 0xc935b761, 0xe5ede11c, 0xb13c7a47, + 0xdf599cd2, 0x733f55f2, 0xce791814, 0x37bf73c7, 0xcdea53f7, 0xaa5b5ffd, 0x6f14df3d, 0xdb867844, + 0xf381caaf, 0xc43eb968, 0x342c3824, 0x405fc2a3, 0xc372161d, 0x250cbce2, 0x498b283c, 0x9541ff0d, + 0x017139a8, 0xb3de080c, 0xe49cd8b4, 0xc1906456, 0x84617bcb, 0xb670d532, 0x5c74486c, 0x5742d0b8, + }, + [256]uint32 { + 0xf4a75051, 0x4165537e, 0x17a4c31a, 0x275e963a, 0xab6bcb3b, 0x9d45f11f, 0xfa58abac, 0xe303934b, + 0x30fa5520, 0x766df6ad, 0xcc769188, 0x024c25f5, 0xe5d7fc4f, 0x2acbd7c5, 0x35448026, 0x62a38fb5, + 0xb15a49de, 0xba1b6725, 0xea0e9845, 0xfec0e15d, 0x2f7502c3, 0x4cf01281, 0x4697a38d, 0xd3f9c66b, + 0x8f5fe703, 0x929c9515, 0x6d7aebbf, 0x5259da95, 0xbe832dd4, 0x7421d358, 0xe0692949, 0xc9c8448e, + 0xc2896a75, 0x8e7978f4, 0x583e6b99, 0xb971dd27, 0xe14fb6be, 0x88ad17f0, 0x20ac66c9, 0xce3ab47d, + 0xdf4a1863, 0x1a3182e5, 0x51336097, 0x537f4562, 0x6477e0b1, 0x6bae84bb, 0x81a01cfe, 0x082b94f9, + 0x48685870, 0x45fd198f, 0xde6c8794, 0x7bf8b752, 0x73d323ab, 0x4b02e272, 0x1f8f57e3, 0x55ab2a66, + 0xeb2807b2, 0xb5c2032f, 0xc57b9a86, 0x3708a5d3, 0x2887f230, 0xbfa5b223, 0x036aba02, 0x16825ced, + 0xcf1c2b8a, 0x79b492a7, 0x07f2f0f3, 0x69e2a14e, 0xdaf4cd65, 0x05bed506, 0x34621fd1, 0xa6fe8ac4, + 0x2e539d34, 0xf355a0a2, 0x8ae13205, 0xf6eb75a4, 0x83ec390b, 0x60efaa40, 0x719f065e, 0x6e1051bd, + 0x218af93e, 0xdd063d96, 0x3e05aedd, 0xe6bd464d, 0x548db591, 0xc45d0571, 0x06d46f04, 0x5015ff60, + 0x98fb2419, 0xbde997d6, 0x4043cc89, 0xd99e7767, 0xe842bdb0, 0x898b8807, 0x195b38e7, 0xc8eedb79, + 0x7c0a47a1, 0x420fe97c, 0x841ec9f8, 0x00000000, 0x80868309, 0x2bed4832, 0x1170ac1e, 0x5a724e6c, + 0x0efffbfd, 0x8538560f, 0xaed51e3d, 0x2d392736, 0x0fd9640a, 0x5ca62168, 0x5b54d19b, 0x362e3a24, + 0x0a67b10c, 0x57e70f93, 0xee96d2b4, 0x9b919e1b, 0xc0c54f80, 0xdc20a261, 0x774b695a, 0x121a161c, + 0x93ba0ae2, 0xa02ae5c0, 0x22e0433c, 0x1b171d12, 0x090d0b0e, 0x8bc7adf2, 0xb6a8b92d, 0x1ea9c814, + 0xf1198557, 0x75074caf, 0x99ddbbee, 0x7f60fda3, 0x01269ff7, 0x72f5bc5c, 0x663bc544, 0xfb7e345b, + 0x4329768b, 0x23c6dccb, 0xedfc68b6, 0xe4f163b8, 0x31dccad7, 0x63851042, 0x97224013, 0xc6112084, + 0x4a247d85, 0xbb3df8d2, 0xf93211ae, 0x29a16dc7, 0x9e2f4b1d, 0xb230f3dc, 0x8652ec0d, 0xc1e3d077, + 0xb3166c2b, 0x70b999a9, 0x9448fa11, 0xe9642247, 0xfc8cc4a8, 0xf03f1aa0, 0x7d2cd856, 0x3390ef22, + 0x494ec787, 0x38d1c1d9, 0xcaa2fe8c, 0xd40b3698, 0xf581cfa6, 0x7ade28a5, 0xb78e26da, 0xadbfa43f, + 0x3a9de42c, 0x78920d50, 0x5fcc9b6a, 0x7e466254, 0x8d13c2f6, 0xd8b8e890, 0x39f75e2e, 0xc3aff582, + 0x5d80be9f, 0xd0937c69, 0xd52da96f, 0x2512b3cf, 0xac993bc8, 0x187da710, 0x9c636ee8, 0x3bbb7bdb, + 0x267809cd, 0x5918f46e, 0x9ab701ec, 0x4f9aa883, 0x956e65e6, 0xffe67eaa, 0xbccf0821, 0x15e8e6ef, + 0xe79bd9ba, 0x6f36ce4a, 0x9f09d4ea, 0xb07cd629, 0xa4b2af31, 0x3f23312a, 0xa59430c6, 0xa266c035, + 0x4ebc3774, 0x82caa6fc, 0x90d0b0e0, 0xa7d81533, 0x04984af1, 0xecdaf741, 0xcd500e7f, 0x91f62f17, + 0x4dd68d76, 0xefb04d43, 0xaa4d54cc, 0x9604dfe4, 0xd1b5e39e, 0x6a881b4c, 0x2c1fb8c1, 0x65517f46, + 0x5eea049d, 0x8c355d01, 0x877473fa, 0x0b412efb, 0x671d5ab3, 0xdbd25292, 0x105633e9, 0xd647136d, + 0xd7618c9a, 0xa10c7a37, 0xf8148e59, 0x133c89eb, 0xa927eece, 0x61c935b7, 0x1ce5ede1, 0x47b13c7a, + 0xd2df599c, 0xf2733f55, 0x14ce7918, 0xc737bf73, 0xf7cdea53, 0xfdaa5b5f, 0x3d6f14df, 0x44db8678, + 0xaff381ca, 0x68c43eb9, 0x24342c38, 0xa3405fc2, 0x1dc37216, 0xe2250cbc, 0x3c498b28, 0x0d9541ff, + 0xa8017139, 0x0cb3de08, 0xb4e49cd8, 0x56c19064, 0xcb84617b, 0x32b670d5, 0x6c5c7448, 0xb85742d0, + }, +} + diff --git a/src/pkg/crypto/block/Makefile b/src/pkg/crypto/block/Makefile new file mode 100644 index 000000000..e8bc8e907 --- /dev/null +++ b/src/pkg/crypto/block/Makefile @@ -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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D=/crypto/ + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + cipher.$O\ + xor.$O\ + +O2=\ + cmac.$O\ + ctr.$O\ + ecb.$O\ + ofb.$O\ + +O3=\ + cbc.$O\ + cfb.$O\ + eax.$O\ + + +phases: a1 a2 a3 +_obj$D/block.a: phases + +a1: $(O1) + $(AR) grc _obj$D/block.a cipher.$O xor.$O + rm -f $(O1) + +a2: $(O2) + $(AR) grc _obj$D/block.a cmac.$O ctr.$O ecb.$O ofb.$O + rm -f $(O2) + +a3: $(O3) + $(AR) grc _obj$D/block.a cbc.$O cfb.$O eax.$O + rm -f $(O3) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/block.a + +$(O1): newpkg +$(O2): a1 +$(O3): a2 +$(O4): a3 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/block.a + +packages: _obj$D/block.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/block.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/block.a diff --git a/src/pkg/crypto/block/cbc.go b/src/pkg/crypto/block/cbc.go new file mode 100644 index 000000000..85a746b72 --- /dev/null +++ b/src/pkg/crypto/block/cbc.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. + +// Cipher block chaining (CBC) mode. + +// CBC provides confidentiality by xoring (chaining) each plaintext block +// with the previous ciphertext block before applying the block cipher. + +// See NIST SP 800-38A, pp 10-11 + +package block + +import ( + "crypto/block"; + "io"; +) + +type cbcCipher struct { + c Cipher; + blockSize int; + iv []byte; + tmp []byte; +} + +func newCBC(c Cipher, iv []byte) *cbcCipher { + n := c.BlockSize(); + x := new(cbcCipher); + x.c = c; + x.blockSize = n; + x.iv = copy(iv); + x.tmp = make([]byte, n); + return x; +} + +func (x *cbcCipher) BlockSize() int { + return x.blockSize; +} + +func (x *cbcCipher) Encrypt(src, dst []byte) { + for i := 0; i < x.blockSize; i++ { + x.iv[i] ^= src[i]; + } + x.c.Encrypt(x.iv, x.iv); + for i := 0; i < x.blockSize; i++ { + dst[i] = x.iv[i]; + } +} + +func (x *cbcCipher) Decrypt(src, dst []byte) { + x.c.Decrypt(src, x.tmp); + for i := 0; i < x.blockSize; i++ { + x.tmp[i] ^= x.iv[i]; + x.iv[i] = src[i]; + dst[i] = x.tmp[i]; + } +} + +// NewCBCDecrypter returns a reader that reads data from r and decrypts it using c +// in cipher block chaining (CBC) mode with the initialization vector iv. +// The returned Reader does not buffer or read ahead except +// as required by the cipher's block size. +func NewCBCDecrypter(c Cipher, iv []byte, r io.Reader) io.Reader { + return NewECBDecrypter(newCBC(c, iv), r); +} + +// NewCBCEncrypter returns a writer that encrypts data using c +// in cipher block chaining (CBC) mode with the initialization vector iv +// and writes the encrypted data to w. +// The returned Writer does no buffering except as required +// by the cipher's block size, so there is no need for a Flush method. +func NewCBCEncrypter(c Cipher, iv []byte, w io.Writer) io.Writer { + return NewECBEncrypter(newCBC(c, iv), w); +} + diff --git a/src/pkg/crypto/block/cbc_aes_test.go b/src/pkg/crypto/block/cbc_aes_test.go new file mode 100644 index 000000000..4681c1c07 --- /dev/null +++ b/src/pkg/crypto/block/cbc_aes_test.go @@ -0,0 +1,107 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// 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 block + +// gobuild: $GC ecb_aes_test.go + +import ( + "crypto/aes"; + "crypto/block"; + "io"; + "os"; + "testing"; + + "./ecb_aes_test"; +) + +type cbcTest struct { + name string; + key []byte; + iv []byte; + in []byte; + out []byte; +} + +var cbcAESTests = []cbcTest { + // NIST SP 800-38A pp 27-29 + cbcTest { + "CBC-AES128", + commonKey128, + commonIV, + 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, + }, + }, + cbcTest { + "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, + }, + }, + cbcTest { + "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 i, 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; + } + + var crypt io.ByteBuffer; + w := NewCBCEncrypter(c, tt.iv, &crypt); + var r io.Reader = io.NewByteReader(tt.in); + n, err := io.Copy(r, w); + if n != int64(len(tt.in)) || err != nil { + t.Errorf("%s: CBCEncrypter io.Copy = %d, %v want %d, nil", test, n, err, len(tt.in)); + } else if d := crypt.Data(); !same(tt.out, d) { + t.Errorf("%s: CBCEncrypter\nhave %x\nwant %x", test, d, tt.out); + } + + var plain io.ByteBuffer; + r = NewCBCDecrypter(c, tt.iv, io.NewByteReader(tt.out)); + w = &plain; + n, err = io.Copy(r, w); + if n != int64(len(tt.out)) || err != nil { + t.Errorf("%s: CBCDecrypter io.Copy = %d, %v want %d, nil", test, n, err, len(tt.out)); + } else if d := plain.Data(); !same(tt.in, d) { + t.Errorf("%s: CBCDecrypter\nhave %x\nwant %x", test, d, tt.in); + } + + if t.Failed() { + break; + } + } +} diff --git a/src/pkg/crypto/block/cfb.go b/src/pkg/crypto/block/cfb.go new file mode 100644 index 000000000..5c4c09a1b --- /dev/null +++ b/src/pkg/crypto/block/cfb.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. + +// Cipher feedback (CFB) mode. + +// CFB provides confidentiality by feeding a fraction of +// the previous ciphertext in as the plaintext for the next +// block operation. + +// See NIST SP 800-38A, pp 11-13 + +package block + +import ( + "crypto/block"; + "io"; +) + +type cfbCipher struct { + c Cipher; + blockSize int; // our block size (s/8) + cipherSize int; // underlying cipher block size + iv []byte; + tmp []byte; +} + +func newCFB(c Cipher, s int, iv []byte) *cfbCipher { + if s == 0 || s % 8 != 0 { + panicln("crypto/block: invalid CFB mode", s); + } + b := c.BlockSize(); + x := new(cfbCipher); + x.c = c; + x.blockSize = s/8; + x.cipherSize = b; + x.iv = copy(iv); + x.tmp = make([]byte, b); + return x; +} + +func (x *cfbCipher) BlockSize() int { + return x.blockSize; +} + +func (x *cfbCipher) Encrypt(src, dst []byte) { + // Encrypt old IV and xor prefix with src to make dst. + x.c.Encrypt(x.iv, x.tmp); + for i := 0; i < x.blockSize; i++ { + dst[i] = src[i] ^ x.tmp[i]; + } + + // Slide unused IV pieces down and insert dst at end. + for i := 0; i < x.cipherSize - x.blockSize; i++ { + x.iv[i] = x.iv[i + x.blockSize]; + } + off := x.cipherSize - x.blockSize; + for i := off; i < x.cipherSize; i++ { + x.iv[i] = dst[i - off]; + } +} + +func (x *cfbCipher) Decrypt(src, dst []byte) { + // Encrypt [sic] old IV and xor prefix with src to make dst. + x.c.Encrypt(x.iv, x.tmp); + for i := 0; i < x.blockSize; i++ { + dst[i] = src[i] ^ x.tmp[i]; + } + + // Slide unused IV pieces down and insert src at top. + for i := 0; i < x.cipherSize - x.blockSize; i++ { + x.iv[i] = x.iv[i + x.blockSize]; + } + off := x.cipherSize - x.blockSize; + for i := off; i < x.cipherSize; i++ { + // Reconstruct src = dst ^ x.tmp + // in case we overwrote src (src == dst). + x.iv[i] = dst[i - off] ^ x.tmp[i - off]; + } +} + +// NewCFBDecrypter returns a reader that reads data from r and decrypts it using c +// in s-bit cipher feedback (CFB) mode with the initialization vector iv. +// The returned Reader does not buffer or read ahead except +// as required by the cipher's block size. +// Modes for s not a multiple of 8 are unimplemented. +func NewCFBDecrypter(c Cipher, s int, iv []byte, r io.Reader) io.Reader { + return NewECBDecrypter(newCFB(c, s, iv), r); +} + +// NewCFBEncrypter returns a writer that encrypts data using c +// in s-bit cipher feedback (CFB) mode with the initialization vector iv +// and writes the encrypted data to w. +// The returned Writer does no buffering except as required +// by the cipher's block size, so there is no need for a Flush method. +// Modes for s not a multiple of 8 are unimplemented. +func NewCFBEncrypter(c Cipher, s int, iv []byte, w io.Writer) io.Writer { + return NewECBEncrypter(newCFB(c, s, iv), w); +} + diff --git a/src/pkg/crypto/block/cfb_aes_test.go b/src/pkg/crypto/block/cfb_aes_test.go new file mode 100644 index 000000000..6c793dba8 --- /dev/null +++ b/src/pkg/crypto/block/cfb_aes_test.go @@ -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. + +// CFB AES test vectors. + +// See U.S. National Institute of Standards and Technology (NIST) +// Special Publication 800-38A, ``Recommendation for Block Cipher +// Modes of Operation,'' 2001 Edition, pp. 29-52. + +package block + +// gobuild: $GC ecb_aes_test.go + +import ( + "crypto/aes"; + "crypto/block"; + "io"; + "os"; + "testing"; + + "./ecb_aes_test"; +) + +type cfbTest struct { + name string; + s int; + key []byte; + iv []byte; + in []byte; + out []byte; +} + +var cfbAESTests = []cfbTest { + cfbTest { + "CFB1-AES128", + 1, + commonKey128, + commonIV, + []byte{ + 0<<7 | 1<<6 | 1<<5 | 0<<4 | 1<<3 | 0<<2 | 1<<1, + 1<<7 | 1<<6 | 0<<5 | 0<<4 | 0<<3 | 0<<2 | 0<<1, + }, + []byte{ + 0<<7 | 1<<6 | 1<<5 | 0<<4 | 1<<3 | 0<<2 | 0<<1, + 1<<7 | 0<<6 | 1<<5 | 1<<4 | 0<<3 | 0<<2 | 1<<1, + }, + }, + cfbTest { + "CFB1-AES192", + 1, + commonKey192, + commonIV, + []byte{ + 0<<7 | 1<<6 | 1<<5 | 0<<4 | 1<<3 | 0<<2 | 1<<1, + 1<<7 | 1<<6 | 0<<5 | 0<<4 | 0<<3 | 0<<2 | 0<<1, + }, + []byte{ + 1<<7 | 0<<6 | 0<<5 | 1<<4 | 0<<3 | 0<<2 | 1<<1, + 0<<7 | 1<<6 | 0<<5 | 1<<4 | 1<<3 | 0<<2 | 0<<1, + }, + }, + cfbTest { + "CFB1-AES256", + 1, + commonKey256, + commonIV, + []byte{ + 0<<7 | 1<<6 | 1<<5 | 0<<4 | 1<<3 | 0<<2 | 1<<1, + 1<<7 | 1<<6 | 0<<5 | 0<<4 | 0<<3 | 0<<2 | 0<<1, + }, + []byte{ + 1<<7 | 0<<6 | 0<<5 | 1<<4 | 0<<3 | 0<<2 | 0<<1, + 0<<7 | 0<<6 | 1<<5 | 0<<4 | 1<<3 | 0<<2 | 0<<1, + }, + }, + + cfbTest { + "CFB8-AES128", + 8, + commonKey128, + commonIV, + []byte{ + 0x6b, + 0xc1, + 0xbe, + 0xe2, + 0x2e, + 0x40, + 0x9f, + 0x96, + 0xe9, + 0x3d, + 0x7e, + 0x11, + 0x73, + 0x93, + 0x17, + 0x2a, + 0xae, + 0x2d, + }, + []byte{ + 0x3b, + 0x79, + 0x42, + 0x4c, + 0x9c, + 0x0d, + 0xd4, + 0x36, + 0xba, + 0xce, + 0x9e, + 0x0e, + 0xd4, + 0x58, + 0x6a, + 0x4f, + 0x32, + 0xb9, + }, + }, + + cfbTest { + "CFB8-AES192", + 8, + commonKey192, + commonIV, + []byte{ + 0x6b, + 0xc1, + 0xbe, + 0xe2, + 0x2e, + 0x40, + 0x9f, + 0x96, + 0xe9, + 0x3d, + 0x7e, + 0x11, + 0x73, + 0x93, + 0x17, + 0x2a, + 0xae, + 0x2d, + }, + []byte{ + 0xcd, + 0xa2, + 0x52, + 0x1e, + 0xf0, + 0xa9, + 0x05, + 0xca, + 0x44, + 0xcd, + 0x05, + 0x7c, + 0xbf, + 0x0d, + 0x47, + 0xa0, + 0x67, + 0x8a, + }, + }, + + cfbTest { + "CFB8-AES256", + 8, + commonKey256, + commonIV, + []byte{ + 0x6b, + 0xc1, + 0xbe, + 0xe2, + 0x2e, + 0x40, + 0x9f, + 0x96, + 0xe9, + 0x3d, + 0x7e, + 0x11, + 0x73, + 0x93, + 0x17, + 0x2a, + 0xae, + 0x2d, + }, + []byte{ + 0xdc, + 0x1f, + 0x1a, + 0x85, + 0x20, + 0xa6, + 0x4d, + 0xb5, + 0x5f, + 0xcc, + 0x8a, + 0xc5, + 0x54, + 0x84, + 0x4e, + 0x88, + 0x97, + 0x00, + }, + }, + + cfbTest { + "CFB128-AES128", + 128, + commonKey128, + commonIV, + []byte{ + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10, + }, + []byte{ + 0x3b, 0x3f, 0xd9, 0x2e, 0xb7, 0x2d, 0xad, 0x20, 0x33, 0x34, 0x49, 0xf8, 0xe8, 0x3c, 0xfb, 0x4a, + 0xc8, 0xa6, 0x45, 0x37, 0xa0, 0xb3, 0xa9, 0x3f, 0xcd, 0xe3, 0xcd, 0xad, 0x9f, 0x1c, 0xe5, 0x8b, + 0x26, 0x75, 0x1f, 0x67, 0xa3, 0xcb, 0xb1, 0x40, 0xb1, 0x80, 0x8c, 0xf1, 0x87, 0xa4, 0xf4, 0xdf, + 0xc0, 0x4b, 0x05, 0x35, 0x7c, 0x5d, 0x1c, 0x0e, 0xea, 0xc4, 0xc6, 0x6f, 0x9f, 0xf7, 0xf2, 0xe6, + }, + }, + + cfbTest { + "CFB128-AES192", + 128, + commonKey192, + commonIV, + []byte{ + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10, + }, + []byte{ + 0xcd, 0xc8, 0x0d, 0x6f, 0xdd, 0xf1, 0x8c, 0xab, 0x34, 0xc2, 0x59, 0x09, 0xc9, 0x9a, 0x41, 0x74, + 0x67, 0xce, 0x7f, 0x7f, 0x81, 0x17, 0x36, 0x21, 0x96, 0x1a, 0x2b, 0x70, 0x17, 0x1d, 0x3d, 0x7a, + 0x2e, 0x1e, 0x8a, 0x1d, 0xd5, 0x9b, 0x88, 0xb1, 0xc8, 0xe6, 0x0f, 0xed, 0x1e, 0xfa, 0xc4, 0xc9, + 0xc0, 0x5f, 0x9f, 0x9c, 0xa9, 0x83, 0x4f, 0xa0, 0x42, 0xae, 0x8f, 0xba, 0x58, 0x4b, 0x09, 0xff, + }, + }, + + cfbTest { + "CFB128-AES256", + 128, + commonKey256, + commonIV, + []byte{ + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10, + }, + []byte{ + 0xdc, 0x7e, 0x84, 0xbf, 0xda, 0x79, 0x16, 0x4b, 0x7e, 0xcd, 0x84, 0x86, 0x98, 0x5d, 0x38, 0x60, + 0x39, 0xff, 0xed, 0x14, 0x3b, 0x28, 0xb1, 0xc8, 0x32, 0x11, 0x3c, 0x63, 0x31, 0xe5, 0x40, 0x7b, + 0xdf, 0x10, 0x13, 0x24, 0x15, 0xe5, 0x4b, 0x92, 0xa1, 0x3e, 0xd0, 0xa8, 0x26, 0x7a, 0xe2, 0xf9, + 0x75, 0xa3, 0x85, 0x74, 0x1a, 0xb9, 0xce, 0xf8, 0x20, 0x31, 0x62, 0x3d, 0x55, 0xb1, 0xe4, 0x71, + }, + }, +} + +func TestCFB_AES(t *testing.T) { + for i, tt := range cfbAESTests { + test := tt.name; + + if tt.s == 1 { + // 1-bit CFB not implemented + continue; + } + + c, err := aes.NewCipher(tt.key); + if err != nil { + t.Errorf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err); + continue; + } + + var crypt io.ByteBuffer; + w := NewCFBEncrypter(c, tt.s, tt.iv, &crypt); + var r io.Reader = io.NewByteReader(tt.in); + n, err := io.Copy(r, w); + if n != int64(len(tt.in)) || err != nil { + t.Errorf("%s: CFBEncrypter io.Copy = %d, %v want %d, nil", test, n, err, len(tt.in)); + } else if d := crypt.Data(); !same(tt.out, d) { + t.Errorf("%s: CFBEncrypter\nhave %x\nwant %x", test, d, tt.out); + } + + var plain io.ByteBuffer; + r = NewCFBDecrypter(c, tt.s, tt.iv, io.NewByteReader(tt.out)); + w = &plain; + n, err = io.Copy(r, w); + if n != int64(len(tt.out)) || err != nil { + t.Errorf("%s: CFBDecrypter io.Copy = %d, %v want %d, nil", test, n, err, len(tt.out)); + } else if d := plain.Data(); !same(tt.in, d) { + t.Errorf("%s: CFBDecrypter\nhave %x\nwant %x", test, d, tt.in); + } + + if t.Failed() { + break; + } + } +} diff --git a/src/pkg/crypto/block/cipher.go b/src/pkg/crypto/block/cipher.go new file mode 100644 index 000000000..7ea035db9 --- /dev/null +++ b/src/pkg/crypto/block/cipher.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. + +// The block package implements standard block cipher modes +// that can be wrapped around low-level block cipher implementations. +// See http://csrc.nist.gov/groups/ST/toolkit/BCM/current_modes.html +// and NIST Special Publication 800-38A. +package block + +import "io"; + +// A Cipher represents an implementation of block cipher +// using a given key. It provides the capability to encrypt +// or decrypt individual blocks. The mode implementations +// extend that capability to streams of blocks. +type Cipher interface { + // BlockSize returns the cipher's block size. + BlockSize() int; + + // Encrypt encrypts the first block in src into dst. + // Src and dst may point at the same memory. + Encrypt(src, dst []byte); + + // Decrypt decrypts the first block in src into dst. + // Src and dst may point at the same memory. + Decrypt(src, dst []byte); +} + +// TODO(rsc): Digest belongs elsewhere. + +// A Digest is an implementation of a message digest algorithm. +// Write data to it and then call Sum to retreive the digest. +// Calling Reset resets the internal state, as though no data has +// been written. +type Digest interface { + io.Writer; + Sum() []byte; + Reset(); +} + + + +// Utility routines + +func shift1(src, dst []byte) byte { + var b byte; + for i := len(src)-1; i >= 0; i-- { + bb := src[i]>>7; + dst[i] = src[i]<<1 | b; + b = bb; + } + return b; +} + +func same(p, q []byte) bool { + if len(p) != len(q) { + return false; + } + for i := 0; i < len(p); i++ { + if p[i] != q[i] { + return false; + } + } + return true; +} + +func copy(p []byte) []byte { + q := make([]byte, len(p)); + for i, b := range p { + q[i] = b; + } + return q; +} diff --git a/src/pkg/crypto/block/cmac.go b/src/pkg/crypto/block/cmac.go new file mode 100644 index 000000000..40697cabd --- /dev/null +++ b/src/pkg/crypto/block/cmac.go @@ -0,0 +1,105 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// CMAC message authentication code, defined in +// NIST Special Publication SP 800-38B. + +package block + +import ( + "crypto/block"; + "io"; + "os"; +) + +const ( + // minimal irreducible polynomial of degree b + r64 = 0x1b; + r128 = 0x87; +) + +type cmac struct { + k1, k2, ci, digest []byte; + p int; // position in ci + c Cipher; +} + +// TODO(rsc): Should this return an error instead of panic? + +// NewCMAC returns a new instance of a CMAC message authentication code +// digest using the given Cipher. +func NewCMAC(c Cipher) Digest { + var r byte; + n := c.BlockSize(); + switch n { + case 64/8: + r = r64; + case 128/8: + r = r128; + default: + panic("crypto/block: NewCMAC: invalid cipher block size", n); + } + + d := new(cmac); + d.c = c; + d.k1 = make([]byte, n); + d.k2 = make([]byte, n); + d.ci = make([]byte, n); + d.digest = make([]byte, n); + + // Subkey generation, p. 7 + c.Encrypt(d.k1, d.k1); + if shift1(d.k1, d.k1) != 0 { + d.k1[n-1] ^= r; + } + if shift1(d.k1, d.k2) != 0 { + d.k2[n-1] ^= r; + } + + return d; +} + +// Reset clears the digest state, starting a new digest. +func (d *cmac) Reset() { + for i := range d.ci { + d.ci[i] = 0; + } + d.p = 0; +} + +// Write adds the given data to the digest state. +func (d *cmac) Write(p []byte) (n int, err os.Error) { + // Xor input into ci. + for i, c := range p { + // If ci is full, encrypt and start over. + if d.p >= len(d.ci) { + d.c.Encrypt(d.ci, d.ci); + d.p = 0; + } + d.ci[d.p] ^= c; + d.p++; + } + return len(p), nil; +} + +// Sum returns the CMAC digest, one cipher block in length, +// of the data written with Write. +func (d *cmac) Sum() []byte { + // Finish last block, mix in key, encrypt. + // Don't edit ci, in case caller wants + // to keep digesting after call to Sum. + k := d.k1; + if d.p < len(d.digest) { + k = d.k2; + } + for i := 0; i < len(d.ci); i++ { + d.digest[i] = d.ci[i] ^ k[i]; + } + if d.p < len(d.digest) { + d.digest[d.p] ^= 0x80; + } + d.c.Encrypt(d.digest, d.digest); + return d.digest; +} + diff --git a/src/pkg/crypto/block/cmac_aes_test.go b/src/pkg/crypto/block/cmac_aes_test.go new file mode 100644 index 000000000..9284ac40a --- /dev/null +++ b/src/pkg/crypto/block/cmac_aes_test.go @@ -0,0 +1,165 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// CMAC test vectors. See NIST SP 800-38B, Appendix D. + +package block + +// gobuild: $GC ecb_aes_test.go + +import ( + "crypto/aes"; + "crypto/block"; + "testing"; + + "./ecb_aes_test"; +) + +type cmacAESTest struct { + key []byte; + in []byte; + digest []byte; +} + +var cmacAESTests = []cmacAESTest { + cmacAESTest { + commonKey128, + nil, + []byte { + 0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28, 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46, + } + }, + cmacAESTest { + commonKey128, + []byte { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + }, + []byte { + 0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44, 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c, + } + }, + cmacAESTest { + commonKey128, + []byte { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + }, + []byte { + 0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30, 0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27, + } + }, + cmacAESTest { + commonKey128, + []byte { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10, + }, + []byte { + 0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92, 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe, + } + }, + cmacAESTest { + commonKey192, + nil, + []byte { + 0xd1, 0x7d, 0xdf, 0x46, 0xad, 0xaa, 0xcd, 0xe5, 0x31, 0xca, 0xc4, 0x83, 0xde, 0x7a, 0x93, 0x67, + } + }, + cmacAESTest { + commonKey192, + []byte { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + }, + []byte { + 0x9e, 0x99, 0xa7, 0xbf, 0x31, 0xe7, 0x10, 0x90, 0x06, 0x62, 0xf6, 0x5e, 0x61, 0x7c, 0x51, 0x84, + } + }, + cmacAESTest { + commonKey192, + []byte { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + }, + []byte { + 0x8a, 0x1d, 0xe5, 0xbe, 0x2e, 0xb3, 0x1a, 0xad, 0x08, 0x9a, 0x82, 0xe6, 0xee, 0x90, 0x8b, 0x0e, + } + }, + cmacAESTest { + commonKey192, + []byte { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10, + }, + []byte { + 0xa1, 0xd5, 0xdf, 0x0e, 0xed, 0x79, 0x0f, 0x79, 0x4d, 0x77, 0x58, 0x96, 0x59, 0xf3, 0x9a, 0x11, + } + }, + cmacAESTest { + commonKey256, + nil, + []byte { + 0x02, 0x89, 0x62, 0xf6, 0x1b, 0x7b, 0xf8, 0x9e, 0xfc, 0x6b, 0x55, 0x1f, 0x46, 0x67, 0xd9, 0x83, + } + }, + cmacAESTest { + commonKey256, + []byte { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + }, + []byte { + 0x28, 0xa7, 0x02, 0x3f, 0x45, 0x2e, 0x8f, 0x82, 0xbd, 0x4b, 0xf2, 0x8d, 0x8c, 0x37, 0xc3, 0x5c, + } + }, + cmacAESTest { + commonKey256, + []byte { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + }, + []byte { + 0xaa, 0xf3, 0xd8, 0xf1, 0xde, 0x56, 0x40, 0xc2, 0x32, 0xf5, 0xb1, 0x69, 0xb9, 0xc9, 0x11, 0xe6, + } + }, + cmacAESTest { + commonKey256, + []byte { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10, + }, + []byte { + 0xe1, 0x99, 0x21, 0x90, 0x54, 0x9f, 0x6e, 0xd5, 0x69, 0x6a, 0x2c, 0x05, 0x6c, 0x31, 0x54, 0x10, + } + } +} + +func TestCMAC_AES(t *testing.T) { + for i, tt := range cmacAESTests { + c, err := aes.NewCipher(tt.key); + if err != nil { + t.Errorf("test %d: NewCipher: %s", i, err); + continue; + } + d := NewCMAC(c); + n, err := d.Write(tt.in); + if err != nil || n != len(tt.in) { + t.Errorf("test %d: Write %d: %d, %s", i, len(tt.in), n, err); + continue; + } + sum := d.Sum(); + if !same(sum, tt.digest) { + x := d.(*cmac); + t.Errorf("test %d: digest mismatch\n\twant %x\n\thave %x\n\tk1 %x\n\tk2 %x", i, tt.digest, sum, x.k1, x.k2); + continue; + } + } +} diff --git a/src/pkg/crypto/block/ctr.go b/src/pkg/crypto/block/ctr.go new file mode 100644 index 000000000..eecb615ad --- /dev/null +++ b/src/pkg/crypto/block/ctr.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. + +// Counter (CTR) mode. + +// CTR converts a block cipher into a stream cipher by +// repeatedly encrypting an incrementing counter and +// xoring the resulting stream of data with the input. + +// See NIST SP 800-38A, pp 13-15 + +package block + +import ( + "crypto/block"; + "io"; +) + +type ctrStream struct { + c Cipher; + ctr []byte; + out []byte; +} + +func newCTRStream(c Cipher, ctr []byte) *ctrStream { + x := new(ctrStream); + x.c = c; + x.ctr = copy(ctr); + x.out = make([]byte, len(ctr)); + return x; +} + +func (x *ctrStream) Next() []byte { + // Next block is encryption of counter. + x.c.Encrypt(x.ctr, x.out); + + // Increment counter + for i := len(x.ctr) - 1; i >= 0; i-- { + x.ctr[i]++; + if x.ctr[i] != 0 { + break; + } + } + + return x.out; +} + +// NewCTRReader returns a reader that reads data from r, decrypts (or encrypts) +// it using c in counter (CTR) mode with the initialization vector iv. +// The returned Reader does not buffer and has no block size. +// In CTR mode, encryption and decryption are the same operation: +// a CTR reader applied to an encrypted stream produces a decrypted +// stream and vice versa. +func NewCTRReader(c Cipher, iv []byte, r io.Reader) io.Reader { + return newXorReader(newCTRStream(c, iv), r); +} + +// NewCTRWriter returns a writer that encrypts (or decrypts) data using c +// in counter (CTR) mode with the initialization vector iv +// and writes the encrypted data to w. +// The returned Writer does not buffer and has no block size. +// In CTR mode, encryption and decryption are the same operation: +// a CTR writer applied to an decrypted stream produces an encrypted +// stream and vice versa. +func NewCTRWriter(c Cipher, iv []byte, w io.Writer) io.Writer { + return newXorWriter(newCTRStream(c, iv), w); +} + diff --git a/src/pkg/crypto/block/ctr_aes_test.go b/src/pkg/crypto/block/ctr_aes_test.go new file mode 100644 index 000000000..a3da1b5bf --- /dev/null +++ b/src/pkg/crypto/block/ctr_aes_test.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. + +// 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 block + +import ( + "crypto/aes"; + "crypto/block"; + "io"; + "os"; + "testing"; + + "./ecb_aes_test"; +) + +type ctrTest struct { + name string; + key []byte; + iv []byte; + in []byte; + out []byte; +} + +var commonCounter = []byte { + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, +} + +var ctrAESTests = []ctrTest { + // NIST SP 800-38A pp 55-58 + ctrTest { + "CTR-AES128", + commonKey128, + commonCounter, + 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, + }, + }, + ctrTest { + "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, + }, + }, + ctrTest { + "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 i, 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 { + var crypt io.ByteBuffer; + in := tt.in[0:len(tt.in) - j]; + w := block.NewCTRWriter(c, tt.iv, &crypt); + var r io.Reader = io.NewByteReader(in); + n, err := io.Copy(r, w); + if n != int64(len(in)) || err != nil { + t.Errorf("%s/%d: CTRWriter io.Copy = %d, %v want %d, nil", test, len(in), n, err, len(in)); + } else if d, out := crypt.Data(), tt.out[0:len(in)]; !same(out, d) { + t.Errorf("%s/%d: CTRWriter\ninpt %x\nhave %x\nwant %x", test, len(in), in, d, out); + } + } + + for j := 0; j <= 7; j += 7 { + var plain io.ByteBuffer; + out := tt.out[0:len(tt.out) - j]; + r := block.NewCTRReader(c, tt.iv, io.NewByteReader(out)); + w := &plain; + n, err := io.Copy(r, w); + if n != int64(len(out)) || err != nil { + t.Errorf("%s/%d: CTRReader io.Copy = %d, %v want %d, nil", test, len(out), n, err, len(out)); + } else if d, in := plain.Data(), tt.in[0:len(out)]; !same(in, d) { + t.Errorf("%s/%d: CTRReader\nhave %x\nwant %x", test, len(out), d, in); + } + } + + if t.Failed() { + break; + } + } +} diff --git a/src/pkg/crypto/block/eax.go b/src/pkg/crypto/block/eax.go new file mode 100644 index 000000000..7e1d7475c --- /dev/null +++ b/src/pkg/crypto/block/eax.go @@ -0,0 +1,254 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// EAX mode, not a NIST standard (yet). +// EAX provides encryption and authentication. +// EAX targets the same uses as NIST's CCM mode, +// but EAX adds the ability to run in streaming mode. + +// See +// http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/eax/eax-spec.pdf +// http://www.cs.ucdavis.edu/~rogaway/papers/eax.pdf +// What those papers call OMAC is now called CMAC. + +package block + +import ( + "crypto/block"; + "fmt"; + "io"; + "os"; +) + +// An EAXTagError is returned when the message has failed to authenticate, +// because the tag at the end of the message stream (Read) does not match +// the tag computed from the message itself (Computed). +type EAXTagError struct { + Read []byte; + Computed []byte; +} + +func (e *EAXTagError) String() string { + return fmt.Sprintf("crypto/block: EAX tag mismatch: read %x but computed %x", e.Read, e.Computed); +} + +func setupEAX(c Cipher, iv, hdr []byte, tagBytes int) (ctrIV, tag []byte, cmac Digest) { + n := len(iv); + if n != c.BlockSize() { + panicln("crypto/block: EAX: iv length", n, "!=", c.BlockSize()); + } + buf := make([]byte, n); // zeroed + + // tag = CMAC(0 + iv) ^ CMAC(1 + hdr) ^ CMAC(2 + data) + cmac = NewCMAC(c); + cmac.Write(buf); // 0 + cmac.Write(iv); + sum := cmac.Sum(); + ctrIV = copy(sum); + tag = copy(sum[0:tagBytes]); + + cmac.Reset(); + buf[n-1] = 1; + cmac.Write(buf); // 1 + cmac.Write(hdr); + sum = cmac.Sum(); + for i := 0; i < tagBytes; i++ { + tag[i] ^= sum[i]; + } + + cmac.Reset(); + buf[n-1] = 2; // 2 + cmac.Write(buf); + + return; +} + +func finishEAX(tag []byte, cmac Digest) { + // Finish CMAC #2 and xor into tag. + sum := cmac.Sum(); + for i := range tag { + tag[i] ^= sum[i]; + } +} + +// Writer adapter. Tees writes into both w and cmac. +// Knows that cmac never returns write errors. +type cmacWriter struct { + w io.Writer; + cmac Digest; +} + +func (cw *cmacWriter) Write(p []byte) (n int, err os.Error) { + n, err = cw.w.Write(p); + cw.cmac.Write(p[0:n]); + return; +} + +// An eaxEncrypter implements the EAX encryption mode. +type eaxEncrypter struct { + ctr io.Writer; // CTR encrypter + cw cmacWriter; // CTR's output stream + tag []byte; +} + +// NewEAXEncrypter creates and returns a new EAX encrypter +// using the given cipher c, initialization vector iv, associated data hdr, +// and tag length tagBytes. The encrypter's Write method encrypts +// the data it receives and writes that data to w. +// The encrypter's Close method writes a final authenticating tag to w. +func NewEAXEncrypter(c Cipher, iv []byte, hdr []byte, tagBytes int, w io.Writer) io.WriteCloser { + x := new(eaxEncrypter); + + // Create new CTR instance writing to both + // w for encrypted output and cmac for digesting. + x.cw.w = w; + var ctrIV []byte; + ctrIV, x.tag, x.cw.cmac = setupEAX(c, iv, hdr, tagBytes); + x.ctr = NewCTRWriter(c, ctrIV, &x.cw); + return x; +} + +func (x *eaxEncrypter) Write(p []byte) (n int, err os.Error) { + return x.ctr.Write(p); +} + +func (x *eaxEncrypter) Close() os.Error { + x.ctr = nil; // crash if Write is called again + + // Write tag. + finishEAX(x.tag, x.cw.cmac); + n, err := x.cw.w.Write(x.tag); + if n != len(x.tag) && err == nil { + err = io.ErrShortWrite; + } + + return err; +} + +// Reader adapter. Returns data read from r but hangs +// on to the last len(tag) bytes for itself (returns EOF len(tag) +// bytes early). Also tees all data returned from Read into +// the cmac digest. The "don't return the last t bytes" +// and the "tee into digest" functionality could be separated, +// but the latter half is trivial. +type cmacReader struct { + r io.Reader; + cmac Digest; + tag []byte; + tmp []byte; +} + +func (cr *cmacReader) Read(p []byte) (n int, err os.Error) { + // TODO(rsc): Maybe fall back to simpler code if + // we recognize the underlying r as a ByteBuffer + // or ByteReader. Then we can just take the last piece + // off at the start. + + // First, read a tag-sized chunk. + // It's probably not the tag (unless there's no data). + tag := cr.tag; + if len(tag) < cap(tag) { + nt := len(tag); + nn, err1 := io.FullRead(cr.r, tag[nt:cap(tag)]); + tag = tag[0:nt+nn]; + cr.tag = tag; + if err1 != nil { + return 0, err1; + } + } + + tagBytes := len(tag); + if len(p) > 4*tagBytes { + // If p is big, try to read directly into p to avoid a copy. + n, err = cr.r.Read(p[tagBytes:len(p)]); + if n == 0 { + goto out; + } + // copy old tag into p + for i := 0; i < tagBytes; i++ { + p[i] = tag[i]; + } + // copy new tag out of p + for i := 0; i < tagBytes; i++ { + tag[i] = p[n+i]; + } + goto out; + } + + // Otherwise, read into p and then slide data + n, err = cr.r.Read(p); + if n == 0 { + goto out; + } + + // copy tag+p into p+tmp and then swap tmp, tag + tmp := cr.tmp; + for i := n + tagBytes - 1; i >= 0; i-- { + var c byte; + if i < tagBytes { + c = tag[i]; + } else { + c = p[i - tagBytes]; + } + if i < n { + p[i] = c; + } else { + tmp[i] = c; + } + } + cr.tmp, cr.tag = tag, tmp; + +out: + cr.cmac.Write(p[0:n]); + return; +} + +type eaxDecrypter struct { + ctr io.Reader; + cr cmacReader; + tag []byte; +} + +// NewEAXDecrypter creates and returns a new EAX decrypter +// using the given cipher c, initialization vector iv, associated data hdr, +// and tag length tagBytes. The encrypter's Read method decrypts and +// returns data read from r. At r's EOF, the encrypter checks the final +// authenticating tag and returns an EAXTagError if the tag is invalid. +// In that case, the message should be discarded. +// Note that the data stream returned from Read cannot be +// assumed to be valid, authenticated data until Read returns +// 0, nil to signal the end of the data. +func NewEAXDecrypter(c Cipher, iv []byte, hdr []byte, tagBytes int, r io.Reader) io.Reader { + x := new(eaxDecrypter); + + x.cr.r = r; + x.cr.tag = make([]byte, 0, tagBytes); + x.cr.tmp = make([]byte, 0, tagBytes); + var ctrIV []byte; + ctrIV, x.tag, x.cr.cmac = setupEAX(c, iv, hdr, tagBytes); + x.ctr = NewCTRReader(c, ctrIV, &x.cr); + return x; +} + +func (x *eaxDecrypter) checkTag() os.Error { + x.ctr = nil; // crash if Read is called again + + finishEAX(x.tag, x.cr.cmac); + if !same(x.tag, x.cr.tag) { + e := new(EAXTagError); + e.Computed = copy(x.tag); + e.Read = copy(x.cr.tag); + return e; + } + return nil; +} + +func (x *eaxDecrypter) Read(p []byte) (n int, err os.Error) { + n, err = x.ctr.Read(p); + if n == 0 && err == nil { + err = x.checkTag(); + } + return n, err; +} + diff --git a/src/pkg/crypto/block/eax_aes_test.go b/src/pkg/crypto/block/eax_aes_test.go new file mode 100644 index 000000000..f0453be80 --- /dev/null +++ b/src/pkg/crypto/block/eax_aes_test.go @@ -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. + +package block + +import ( + "crypto/aes"; + "crypto/block"; + "fmt"; + "io"; + "testing"; +) + +// Test vectors from http://www.cs.ucdavis.edu/~rogaway/papers/eax.pdf + +type eaxAESTest struct { + msg []byte; + key []byte; + nonce []byte; + header []byte; + cipher []byte; +} + +var eaxAESTests = []eaxAESTest { + eaxAESTest { + []byte { + }, + []byte { + 0x23, 0x39, 0x52, 0xDE, 0xE4, 0xD5, 0xED, 0x5F, 0x9B, 0x9C, 0x6D, 0x6F, 0xF8, 0x0F, 0xF4, 0x78, + }, + []byte { + 0x62, 0xEC, 0x67, 0xF9, 0xC3, 0xA4, 0xA4, 0x07, 0xFC, 0xB2, 0xA8, 0xC4, 0x90, 0x31, 0xA8, 0xB3, + }, + []byte { + 0x6B, 0xFB, 0x91, 0x4F, 0xD0, 0x7E, 0xAE, 0x6B, + }, + []byte { + 0xE0, 0x37, 0x83, 0x0E, 0x83, 0x89, 0xF2, 0x7B, 0x02, 0x5A, 0x2D, 0x65, 0x27, 0xE7, 0x9D, 0x01, + }, + }, + eaxAESTest { + []byte { + 0xF7, 0xFB, + }, + []byte { + 0x91, 0x94, 0x5D, 0x3F, 0x4D, 0xCB, 0xEE, 0x0B, 0xF4, 0x5E, 0xF5, 0x22, 0x55, 0xF0, 0x95, 0xA4, + }, + []byte { + 0xBE, 0xCA, 0xF0, 0x43, 0xB0, 0xA2, 0x3D, 0x84, 0x31, 0x94, 0xBA, 0x97, 0x2C, 0x66, 0xDE, 0xBD, + }, + []byte { + 0xFA, 0x3B, 0xFD, 0x48, 0x06, 0xEB, 0x53, 0xFA, + }, + []byte { + 0x19, 0xDD, 0x5C, 0x4C, 0x93, 0x31, 0x04, 0x9D, 0x0B, 0xDA, 0xB0, 0x27, 0x74, 0x08, 0xF6, 0x79, 0x67, 0xE5, + }, + }, + eaxAESTest { + []byte { + 0x1A, 0x47, 0xCB, 0x49, 0x33, + }, + []byte { + 0x01, 0xF7, 0x4A, 0xD6, 0x40, 0x77, 0xF2, 0xE7, 0x04, 0xC0, 0xF6, 0x0A, 0xDA, 0x3D, 0xD5, 0x23, + }, + []byte { + 0x70, 0xC3, 0xDB, 0x4F, 0x0D, 0x26, 0x36, 0x84, 0x00, 0xA1, 0x0E, 0xD0, 0x5D, 0x2B, 0xFF, 0x5E, + }, + []byte { + 0x23, 0x4A, 0x34, 0x63, 0xC1, 0x26, 0x4A, 0xC6, + }, + []byte { + 0xD8, 0x51, 0xD5, 0xBA, 0xE0, 0x3A, 0x59, 0xF2, 0x38, 0xA2, 0x3E, 0x39, 0x19, 0x9D, 0xC9, 0x26, 0x66, 0x26, 0xC4, 0x0F, 0x80, + }, + }, + eaxAESTest { + []byte { + 0x48, 0x1C, 0x9E, 0x39, 0xB1, + }, + []byte { + 0xD0, 0x7C, 0xF6, 0xCB, 0xB7, 0xF3, 0x13, 0xBD, 0xDE, 0x66, 0xB7, 0x27, 0xAF, 0xD3, 0xC5, 0xE8, + }, + []byte { + 0x84, 0x08, 0xDF, 0xFF, 0x3C, 0x1A, 0x2B, 0x12, 0x92, 0xDC, 0x19, 0x9E, 0x46, 0xB7, 0xD6, 0x17, + }, + []byte { + 0x33, 0xCC, 0xE2, 0xEA, 0xBF, 0xF5, 0xA7, 0x9D, + }, + []byte { + 0x63, 0x2A, 0x9D, 0x13, 0x1A, 0xD4, 0xC1, 0x68, 0xA4, 0x22, 0x5D, 0x8E, 0x1F, 0xF7, 0x55, 0x93, 0x99, 0x74, 0xA7, 0xBE, 0xDE, + }, + }, + eaxAESTest { + []byte { + 0x40, 0xD0, 0xC0, 0x7D, 0xA5, 0xE4, + }, + []byte { + 0x35, 0xB6, 0xD0, 0x58, 0x00, 0x05, 0xBB, 0xC1, 0x2B, 0x05, 0x87, 0x12, 0x45, 0x57, 0xD2, 0xC2, + }, + []byte { + 0xFD, 0xB6, 0xB0, 0x66, 0x76, 0xEE, 0xDC, 0x5C, 0x61, 0xD7, 0x42, 0x76, 0xE1, 0xF8, 0xE8, 0x16, + }, + []byte { + 0xAE, 0xB9, 0x6E, 0xAE, 0xBE, 0x29, 0x70, 0xE9, + }, + []byte { + 0x07, 0x1D, 0xFE, 0x16, 0xC6, 0x75, 0xCB, 0x06, 0x77, 0xE5, 0x36, 0xF7, 0x3A, 0xFE, 0x6A, 0x14, 0xB7, 0x4E, 0xE4, 0x98, 0x44, 0xDD, + }, + }, + eaxAESTest { + []byte { + 0x4D, 0xE3, 0xB3, 0x5C, 0x3F, 0xC0, 0x39, 0x24, 0x5B, 0xD1, 0xFB, 0x7D, + }, + []byte { + 0xBD, 0x8E, 0x6E, 0x11, 0x47, 0x5E, 0x60, 0xB2, 0x68, 0x78, 0x4C, 0x38, 0xC6, 0x2F, 0xEB, 0x22, + }, + []byte { + 0x6E, 0xAC, 0x5C, 0x93, 0x07, 0x2D, 0x8E, 0x85, 0x13, 0xF7, 0x50, 0x93, 0x5E, 0x46, 0xDA, 0x1B, + }, + []byte { + 0xD4, 0x48, 0x2D, 0x1C, 0xA7, 0x8D, 0xCE, 0x0F, + }, + []byte { + 0x83, 0x5B, 0xB4, 0xF1, 0x5D, 0x74, 0x3E, 0x35, 0x0E, 0x72, 0x84, 0x14, 0xAB, 0xB8, 0x64, 0x4F, 0xD6, 0xCC, 0xB8, 0x69, 0x47, 0xC5, 0xE1, 0x05, 0x90, 0x21, 0x0A, 0x4F, + }, + }, + eaxAESTest { + []byte { + 0x8B, 0x0A, 0x79, 0x30, 0x6C, 0x9C, 0xE7, 0xED, 0x99, 0xDA, 0xE4, 0xF8, 0x7F, 0x8D, 0xD6, 0x16, 0x36, + }, + []byte { + 0x7C, 0x77, 0xD6, 0xE8, 0x13, 0xBE, 0xD5, 0xAC, 0x98, 0xBA, 0xA4, 0x17, 0x47, 0x7A, 0x2E, 0x7D, + }, + []byte { + 0x1A, 0x8C, 0x98, 0xDC, 0xD7, 0x3D, 0x38, 0x39, 0x3B, 0x2B, 0xF1, 0x56, 0x9D, 0xEE, 0xFC, 0x19, + }, + []byte { + 0x65, 0xD2, 0x01, 0x79, 0x90, 0xD6, 0x25, 0x28, + }, + []byte { + 0x02, 0x08, 0x3E, 0x39, 0x79, 0xDA, 0x01, 0x48, 0x12, 0xF5, 0x9F, 0x11, 0xD5, 0x26, 0x30, 0xDA, 0x30, 0x13, 0x73, 0x27, 0xD1, 0x06, 0x49, 0xB0, 0xAA, 0x6E, 0x1C, 0x18, 0x1D, 0xB6, 0x17, 0xD7, 0xF2, + }, + }, + eaxAESTest { + []byte { + 0x1B, 0xDA, 0x12, 0x2B, 0xCE, 0x8A, 0x8D, 0xBA, 0xF1, 0x87, 0x7D, 0x96, 0x2B, 0x85, 0x92, 0xDD, 0x2D, 0x56, + }, + []byte { + 0x5F, 0xFF, 0x20, 0xCA, 0xFA, 0xB1, 0x19, 0xCA, 0x2F, 0xC7, 0x35, 0x49, 0xE2, 0x0F, 0x5B, 0x0D, + }, + []byte { + 0xDD, 0xE5, 0x9B, 0x97, 0xD7, 0x22, 0x15, 0x6D, 0x4D, 0x9A, 0xFF, 0x2B, 0xC7, 0x55, 0x98, 0x26, + }, + []byte { + 0x54, 0xB9, 0xF0, 0x4E, 0x6A, 0x09, 0x18, 0x9A, + }, + []byte { + 0x2E, 0xC4, 0x7B, 0x2C, 0x49, 0x54, 0xA4, 0x89, 0xAF, 0xC7, 0xBA, 0x48, 0x97, 0xED, 0xCD, 0xAE, 0x8C, 0xC3, 0x3B, 0x60, 0x45, 0x05, 0x99, 0xBD, 0x02, 0xC9, 0x63, 0x82, 0x90, 0x2A, 0xEF, 0x7F, 0x83, 0x2A, + }, + }, + eaxAESTest { + []byte { + 0x6C, 0xF3, 0x67, 0x20, 0x87, 0x2B, 0x85, 0x13, 0xF6, 0xEA, 0xB1, 0xA8, 0xA4, 0x44, 0x38, 0xD5, 0xEF, 0x11, + }, + []byte { + 0xA4, 0xA4, 0x78, 0x2B, 0xCF, 0xFD, 0x3E, 0xC5, 0xE7, 0xEF, 0x6D, 0x8C, 0x34, 0xA5, 0x61, 0x23, + }, + []byte { + 0xB7, 0x81, 0xFC, 0xF2, 0xF7, 0x5F, 0xA5, 0xA8, 0xDE, 0x97, 0xA9, 0xCA, 0x48, 0xE5, 0x22, 0xEC, + }, + []byte { + 0x89, 0x9A, 0x17, 0x58, 0x97, 0x56, 0x1D, 0x7E, + }, + []byte { + 0x0D, 0xE1, 0x8F, 0xD0, 0xFD, 0xD9, 0x1E, 0x7A, 0xF1, 0x9F, 0x1D, 0x8E, 0xE8, 0x73, 0x39, 0x38, 0xB1, 0xE8, 0xE7, 0xF6, 0xD2, 0x23, 0x16, 0x18, 0x10, 0x2F, 0xDB, 0x7F, 0xE5, 0x5F, 0xF1, 0x99, 0x17, 0x00, + }, + }, + eaxAESTest { + []byte { + 0xCA, 0x40, 0xD7, 0x44, 0x6E, 0x54, 0x5F, 0xFA, 0xED, 0x3B, 0xD1, 0x2A, 0x74, 0x0A, 0x65, 0x9F, 0xFB, 0xBB, 0x3C, 0xEA, 0xB7, + }, + []byte { + 0x83, 0x95, 0xFC, 0xF1, 0xE9, 0x5B, 0xEB, 0xD6, 0x97, 0xBD, 0x01, 0x0B, 0xC7, 0x66, 0xAA, 0xC3, + }, + []byte { + 0x22, 0xE7, 0xAD, 0xD9, 0x3C, 0xFC, 0x63, 0x93, 0xC5, 0x7E, 0xC0, 0xB3, 0xC1, 0x7D, 0x6B, 0x44, + }, + []byte { + 0x12, 0x67, 0x35, 0xFC, 0xC3, 0x20, 0xD2, 0x5A, + }, + []byte { + 0xCB, 0x89, 0x20, 0xF8, 0x7A, 0x6C, 0x75, 0xCF, 0xF3, 0x96, 0x27, 0xB5, 0x6E, 0x3E, 0xD1, 0x97, 0xC5, 0x52, 0xD2, 0x95, 0xA7, 0xCF, 0xC4, 0x6A, 0xFC, 0x25, 0x3B, 0x46, 0x52, 0xB1, 0xAF, 0x37, 0x95, 0xB1, 0x24, 0xAB, 0x6E, + }, + }, +} + +func TestEAXEncrypt_AES(t *testing.T) { + b := new(io.ByteBuffer); + for i, tt := range eaxAESTests { + test := fmt.Sprintf("test %d", i); + c, err := aes.NewCipher(tt.key); + if err != nil { + t.Fatalf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err); + } + b.Reset(); + enc := NewEAXEncrypter(c, tt.nonce, tt.header, 16, b); + n, err := io.Copy(io.NewByteReader(tt.msg), enc); + if n != int64(len(tt.msg)) || err != nil { + t.Fatalf("%s: io.Copy into encrypter: %d, %s", test, n, err); + } + err = enc.Close(); + if err != nil { + t.Fatalf("%s: enc.Close: %s", test, err); + } + if d := b.Data(); !same(d, tt.cipher) { + t.Fatalf("%s: got %x want %x", test, d, tt.cipher); + } + } +} + +func TestEAXDecrypt_AES(t *testing.T) { + b := new(io.ByteBuffer); + for i, tt := range eaxAESTests { + test := fmt.Sprintf("test %d", i); + c, err := aes.NewCipher(tt.key); + if err != nil { + t.Fatalf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err); + } + b.Reset(); + dec := NewEAXDecrypter(c, tt.nonce, tt.header, 16, io.NewByteReader(tt.cipher)); + n, err := io.Copy(dec, b); + if n != int64(len(tt.msg)) || err != nil { + t.Fatalf("%s: io.Copy into decrypter: %d, %s", test, n, err); + } + if d := b.Data(); !same(d, tt.msg) { + t.Fatalf("%s: got %x want %x", test, d, tt.msg); + } + } +} diff --git a/src/pkg/crypto/block/ecb.go b/src/pkg/crypto/block/ecb.go new file mode 100644 index 000000000..141d38cc8 --- /dev/null +++ b/src/pkg/crypto/block/ecb.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. + +// Electronic codebook (ECB) mode. +// ECB is a fancy name for ``encrypt and decrypt each block separately.'' +// It's a pretty bad thing to do for any large amount of data (more than one block), +// because the individual blocks can still be identified, duplicated, and reordered. +// The ECB implementation exists mainly to provide buffering for +// the other modes, which wrap it by providing modified Ciphers. + +// See NIST SP 800-38A, pp 9-10 + +package block + +import ( + "crypto/block"; + "io"; + "os"; +) + +type ecbDecrypter struct { + c Cipher; + r io.Reader; + blockSize int; // block size + + // Buffered data. + // The buffer buf is used as storage for both + // plain or crypt; at least one of those is nil at any given time. + buf []byte; + plain []byte; // plain text waiting to be read + crypt []byte; // ciphertext waiting to be decrypted +} + +// Read into x.crypt until it has a full block or EOF or an error happens. +func (x *ecbDecrypter) fillCrypt() os.Error { + var err os.Error; + for len(x.crypt) < x.blockSize { + off := len(x.crypt); + var m int; + m, err = x.r.Read(x.crypt[off:x.blockSize]); + x.crypt = x.crypt[0:off+m]; + if m == 0 { + break; + } + + // If an error happened but we got enough + // data to do some decryption, we can decrypt + // first and report the error (with some data) later. + // But if we don't have enough to decrypt, + // have to stop now. + if err != nil && len(x.crypt) < x.blockSize { + break; + } + } + return err; +} + +// Read from plain text buffer into p. +func (x *ecbDecrypter) readPlain(p []byte) int { + n := len(x.plain); + if n > len(p) { + n = len(p); + } + for i := 0; i < n; i++ { + p[i] = x.plain[i]; + } + if n < len(x.plain) { + x.plain = x.plain[n:len(x.plain)]; + } else { + x.plain = nil; + } + return n; +} + +func (x *ecbDecrypter) Read(p []byte) (n int, err os.Error) { + if len(p) == 0 { + return; + } + + // If there's no plaintext waiting and p is not big enough + // to hold a whole cipher block, we'll have to work in the + // cipher text buffer. Set it to non-nil so that the + // code below will fill it. + if x.plain == nil && len(p) < x.blockSize && x.crypt == nil { + x.crypt = x.buf[0:0]; + } + + // If there is a leftover cipher text buffer, + // try to accumulate a full block. + if x.crypt != nil { + err = x.fillCrypt(); + if err != nil || len(x.crypt) == 0 { + return; + } + x.c.Decrypt(x.crypt, x.crypt); + x.plain = x.crypt; + x.crypt = nil; + } + + // If there is a leftover plain text buffer, read from it. + if x.plain != nil { + n = x.readPlain(p); + return; + } + + // Read and decrypt directly in caller's buffer. + n, err = io.ReadAtLeast(x.r, p, x.blockSize); + if err == io.ErrEOF && n == 0 { + // EOF is okay on block boundary + err = nil; + return; + } + var i int; + for i = 0; i+x.blockSize <= n; i += x.blockSize { + a := p[i:i+x.blockSize]; + x.c.Decrypt(a, a); + } + + // There might be an encrypted fringe remaining. + // Save it for next time. + if i < n { + p = p[i:n]; + for j, v := range p { + x.buf[j] = p[j]; + } + x.crypt = x.buf[0:len(p)]; + n = i; + } + + return; +} + +// NewECBDecrypter returns a reader that reads data from r and decrypts it using c. +// It decrypts by calling c.Decrypt on each block in sequence; +// this mode is known as electronic codebook mode, or ECB. +// The returned Reader does not buffer or read ahead except +// as required by the cipher's block size. +func NewECBDecrypter(c Cipher, r io.Reader) io.Reader { + x := new(ecbDecrypter); + x.c = c; + x.r = r; + x.blockSize = c.BlockSize(); + x.buf = make([]byte, x.blockSize); + return x; +} + +type ecbEncrypter struct { + c Cipher; + w io.Writer; + blockSize int; + + // Buffered data. + // The buffer buf is used as storage for both + // plain or crypt. If both are non-nil, plain + // follows crypt in buf. + buf []byte; + plain []byte; // plain text waiting to be encrypted + crypt []byte; // encrypted text waiting to be written +} + +// Flush the x.crypt buffer to x.w. +func (x *ecbEncrypter) flushCrypt() os.Error { + if len(x.crypt) == 0 { + return nil; + } + n, err := x.w.Write(x.crypt); + if n < len(x.crypt) { + x.crypt = x.crypt[n:len(x.crypt)]; + if err == nil { + err = io.ErrShortWrite; + } + } + if err != nil { + return err; + } + x.crypt = nil; + return nil; +} + +// Slide x.plain down to the beginning of x.buf. +// Plain is known to have less than one block of data, +// so this is cheap enough. +func (x *ecbEncrypter) slidePlain() { + if len(x.plain) == 0 { + x.plain = x.buf[0:0]; + } else if cap(x.plain) < cap(x.buf) { + // plain and buf share same data, + // but buf is before plain, so forward loop is correct + for i := 0; i < len(x.plain); i++ { + x.buf[i] = x.plain[i]; + } + x.plain = x.buf[0:len(x.plain)]; + } +} + +// Fill x.plain from the data in p. +// Return the number of bytes copied. +func (x *ecbEncrypter) fillPlain(p []byte) int { + off := len(x.plain); + n := len(p); + if max := cap(x.plain) - off; n > max { + n = max; + } + x.plain = x.plain[0:off+n]; + for i := 0; i < n; i++ { + x.plain[off + i] = p[i]; + } + return n; +} + +// Encrypt x.plain; record encrypted range as x.crypt. +func (x *ecbEncrypter) encrypt() { + var i int; + n := len(x.plain); + for i = 0; i+x.blockSize <= n; i += x.blockSize { + a := x.plain[i:i+x.blockSize]; + x.c.Encrypt(a, a); + } + x.crypt = x.plain[0:i]; + x.plain = x.plain[i:n]; +} + +func (x *ecbEncrypter) Write(p []byte) (n int, err os.Error) { + for { + // If there is data waiting to be written, write it. + // This can happen on the first iteration + // if a write failed in an earlier call. + if err = x.flushCrypt(); err != nil { + return; + } + + // Now that encrypted data is gone (flush ran), + // perhaps we need to slide the plaintext down. + x.slidePlain(); + + // Fill plaintext buffer from p. + m := x.fillPlain(p); + if m == 0 { + break; + } + n += m; + p = p[m:len(p)]; + + // Encrypt, adjusting crypt and plain. + x.encrypt(); + + // Write x.crypt. + if err = x.flushCrypt(); err != nil { + break; + } + } + return; +} + +// NewECBEncrypter returns a writer that encrypts data using c and writes it to w. +// It encrypts by calling c.Encrypt on each block in sequence; +// this mode is known as electronic codebook mode, or ECB. +// The returned Writer does no buffering except as required +// by the cipher's block size, so there is no need for a Flush method. +func NewECBEncrypter(c Cipher, w io.Writer) io.Writer { + x := new(ecbEncrypter); + x.c = c; + x.w = w; + x.blockSize = c.BlockSize(); + + // Create a buffer that is an integral number of blocks. + x.buf = make([]byte, 8192/x.blockSize * x.blockSize); + return x; +} + diff --git a/src/pkg/crypto/block/ecb_aes_test.go b/src/pkg/crypto/block/ecb_aes_test.go new file mode 100644 index 000000000..de8a624b9 --- /dev/null +++ b/src/pkg/crypto/block/ecb_aes_test.go @@ -0,0 +1,136 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// ECB AES test vectors. + +// See U.S. National Institute of Standards and Technology (NIST) +// Special Publication 800-38A, ``Recommendation for Block Cipher +// Modes of Operation,'' 2001 Edition, pp. 24-27. + +package block + +import ( + "crypto/aes"; + "crypto/block"; + "io"; + "os"; + "testing"; +) + +type ecbTest struct { + name string; + key []byte; + in []byte; + out []byte; +} + +var commonInput = []byte { + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10, +} + +var commonKey128 = []byte { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c, +} + +var commonKey192 = []byte { + 0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5, + 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b, +} + +var commonKey256 = []byte { + 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, + 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4, +} + +var commonIV = []byte { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, +} + +var ecbAESTests = []ecbTest { + // FIPS 197, Appendix B, C + ecbTest { + "FIPS-197 Appendix B", + commonKey128, + []byte { + 0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d, 0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34, + }, + []byte { + 0x39, 0x25, 0x84, 0x1d, 0x02, 0xdc, 0x09, 0xfb, 0xdc, 0x11, 0x85, 0x97, 0x19, 0x6a, 0x0b, 0x32, + } + }, + + // NIST SP 800-38A pp 24-27 + ecbTest { + "ECB-AES128", + commonKey128, + commonInput, + []byte { + 0x3a, 0xd7, 0x7b, 0xb4, 0x0d, 0x7a, 0x36, 0x60, 0xa8, 0x9e, 0xca, 0xf3, 0x24, 0x66, 0xef, 0x97, + 0xf5, 0xd3, 0xd5, 0x85, 0x03, 0xb9, 0x69, 0x9d, 0xe7, 0x85, 0x89, 0x5a, 0x96, 0xfd, 0xba, 0xaf, + 0x43, 0xb1, 0xcd, 0x7f, 0x59, 0x8e, 0xce, 0x23, 0x88, 0x1b, 0x00, 0xe3, 0xed, 0x03, 0x06, 0x88, + 0x7b, 0x0c, 0x78, 0x5e, 0x27, 0xe8, 0xad, 0x3f, 0x82, 0x23, 0x20, 0x71, 0x04, 0x72, 0x5d, 0xd4, + } + }, + ecbTest { + "ECB-AES192", + commonKey192, + commonInput, + []byte { + 0xbd, 0x33, 0x4f, 0x1d, 0x6e, 0x45, 0xf2, 0x5f, 0xf7, 0x12, 0xa2, 0x14, 0x57, 0x1f, 0xa5, 0xcc, + 0x97, 0x41, 0x04, 0x84, 0x6d, 0x0a, 0xd3, 0xad, 0x77, 0x34, 0xec, 0xb3, 0xec, 0xee, 0x4e, 0xef, + 0xef, 0x7a, 0xfd, 0x22, 0x70, 0xe2, 0xe6, 0x0a, 0xdc, 0xe0, 0xba, 0x2f, 0xac, 0xe6, 0x44, 0x4e, + 0x9a, 0x4b, 0x41, 0xba, 0x73, 0x8d, 0x6c, 0x72, 0xfb, 0x16, 0x69, 0x16, 0x03, 0xc1, 0x8e, 0x0e, + } + }, + ecbTest { + "ECB-AES256", + commonKey256, + commonInput, + []byte { + 0xf3, 0xee, 0xd1, 0xbd, 0xb5, 0xd2, 0xa0, 0x3c, 0x06, 0x4b, 0x5a, 0x7e, 0x3d, 0xb1, 0x81, 0xf8, + 0x59, 0x1c, 0xcb, 0x10, 0xd4, 0x10, 0xed, 0x26, 0xdc, 0x5b, 0xa7, 0x4a, 0x31, 0x36, 0x28, 0x70, + 0xb6, 0xed, 0x21, 0xb9, 0x9c, 0xa6, 0xf4, 0xf9, 0xf1, 0x53, 0xe7, 0xb1, 0xbe, 0xaf, 0xed, 0x1d, + 0x23, 0x30, 0x4b, 0x7a, 0x39, 0xf9, 0xf3, 0xff, 0x06, 0x7d, 0x8d, 0x8f, 0x9e, 0x24, 0xec, 0xc7, + } + } +} + +func TestECB_AES(t *testing.T) { + for i, tt := range ecbAESTests { + test := tt.name; + + c, err := aes.NewCipher(tt.key); + if err != nil { + t.Errorf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err); + continue; + } + + var crypt io.ByteBuffer; + w := NewECBEncrypter(c, &crypt); + var r io.Reader = io.NewByteReader(tt.in); + n, err := io.Copy(r, w); + if n != int64(len(tt.in)) || err != nil { + t.Errorf("%s: ECBReader io.Copy = %d, %v want %d, nil", test, n, err, len(tt.in)); + } else if d := crypt.Data(); !same(tt.out, d) { + t.Errorf("%s: ECBReader\nhave %x\nwant %x", test, d, tt.out); + } + + var plain io.ByteBuffer; + r = NewECBDecrypter(c, io.NewByteReader(tt.out)); + w = &plain; + n, err = io.Copy(r, w); + if n != int64(len(tt.out)) || err != nil { + t.Errorf("%s: ECBWriter io.Copy = %d, %v want %d, nil", test, n, err, len(tt.out)); + } else if d := plain.Data(); !same(tt.in, d) { + t.Errorf("%s: ECBWriter\nhave %x\nwant %x", test, d, tt.in); + } + + if t.Failed() { + break; + } + } +} diff --git a/src/pkg/crypto/block/ecb_test.go b/src/pkg/crypto/block/ecb_test.go new file mode 100644 index 000000000..968893a9b --- /dev/null +++ b/src/pkg/crypto/block/ecb_test.go @@ -0,0 +1,183 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package block + +import ( + "crypto/block"; + "fmt"; + "io"; + "testing"; + "testing/iotest"; +) + +// Simple Cipher for testing: adds an incrementing amount +// to each byte in each +type IncCipher struct { + blockSize int; + delta byte; + encrypting bool; +} + +func (c *IncCipher) BlockSize() int { + return c.blockSize; +} + +func (c *IncCipher) Encrypt(src, dst []byte) { + if !c.encrypting { + panicln("encrypt: not encrypting"); + } + if len(src) != c.blockSize || len(dst) != c.blockSize { + panicln("encrypt: wrong block size", c.blockSize, len(src), len(dst)); + } + c.delta++; + for i, b := range src { + dst[i] = b + c.delta; + } +} + +func (c *IncCipher) Decrypt(src, dst []byte) { + if c.encrypting { + panicln("decrypt: not decrypting"); + } + if len(src) != c.blockSize || len(dst) != c.blockSize { + panicln("decrypt: wrong block size", c.blockSize, len(src), len(dst)); + } + c.delta--; + for i, b := range src { + dst[i] = b + c.delta; + } +} + +func TestECBEncrypter(t *testing.T) { + var plain, crypt [256]byte; + for i := 0; i < len(plain); i++ { + plain[i] = byte(i); + } + b := new(io.ByteBuffer); + for block := 1; block <= 64; block *= 2 { + // compute encrypted version + delta := byte(0); + for i := 0; i < len(crypt); i++ { + if i % block == 0 { + delta++; + } + crypt[i] = plain[i] + delta; + } + + for frag := 0; frag < 2; frag++ { + c := &IncCipher{block, 0, true}; + b.Reset(); + r := io.NewByteReader(&plain); + w := NewECBEncrypter(c, b); + + // copy plain into w in increasingly large chunks: 1, 1, 2, 4, 8, ... + // if frag != 0, move the 1 to the end to cause fragmentation. + if frag == 0 { + nn, err := io.Copyn(r, w, 1); + if err != nil { + t.Errorf("block=%d frag=0: first Copyn: %s", block, err); + continue; + } + } + for n := 1; n <= len(plain)/2; n *= 2 { + nn, err := io.Copyn(r, w, int64(n)); + if err != nil { + t.Errorf("block=%d frag=%d: Copyn %d: %s", block, frag, n, err); + } + } + if frag != 0 { + nn, err := io.Copyn(r, w, 1); + if err != nil { + t.Errorf("block=%d frag=1: last Copyn: %s", block, err); + continue; + } + } + + // check output + data := b.Data(); + if len(data) != len(crypt) { + t.Errorf("block=%d frag=%d: want %d bytes, got %d", block, frag, len(crypt), len(data)); + continue; + } + + if string(data) != string(&crypt) { + t.Errorf("block=%d frag=%d: want %x got %x", block, frag, data, crypt); + } + } + } +} + +func testECBDecrypter(t *testing.T, maxio int) { + var readers = []func(io.Reader) io.Reader { + func (r io.Reader) io.Reader { return r }, + iotest.OneByteReader, + iotest.HalfReader, + }; + var plain, crypt [256]byte; + for i := 0; i < len(plain); i++ { + plain[i] = byte(255 - i); + } + b := new(io.ByteBuffer); + for block := 1; block <= 64 && block <= maxio; block *= 2 { + // compute encrypted version + delta := byte(0); + for i := 0; i < len(crypt); i++ { + if i % block == 0 { + delta++; + } + crypt[i] = plain[i] + delta; + } + + for mode := 0; mode < len(readers); mode++ { + for frag := 0; frag < 2; frag++ { + test := fmt.Sprintf("block=%d mode=%d frag=%d maxio=%d", block, mode, frag, maxio); + c := &IncCipher{block, 0, false}; + b.Reset(); + r := NewECBDecrypter(c, readers[mode](io.NewByteReader(crypt[0:maxio]))); + + // read from crypt in increasingly large chunks: 1, 1, 2, 4, 8, ... + // if frag == 1, move the 1 to the end to cause fragmentation. + if frag == 0 { + nn, err := io.Copyn(r, b, 1); + if err != nil { + t.Errorf("%s: first Copyn: %s", test, err); + continue; + } + } + for n := 1; n <= maxio/2; n *= 2 { + nn, err := io.Copyn(r, b, int64(n)); + if err != nil { + t.Errorf("%s: Copyn %d: %s", test, n, err); + } + } + if frag != 0 { + nn, err := io.Copyn(r, b, 1); + if err != nil { + t.Errorf("%s: last Copyn: %s", test, err); + continue; + } + } + + // check output + data := b.Data(); + if len(data) != maxio { + t.Errorf("%s: want %d bytes, got %d", test, maxio, len(data)); + continue; + } + + if string(data) != string(plain[0:maxio]) { + t.Errorf("%s: input=%x want %x got %x", test, crypt[0:maxio], plain[0:maxio], data); + } + } + } + } +} + +func TestECBDecrypter(t *testing.T) { + // Do shorter I/O sizes first; they're easier to debug. + for n := 1; n <= 256 && !t.Failed(); n *= 2 { + testECBDecrypter(t, n); + } +} diff --git a/src/pkg/crypto/block/ofb.go b/src/pkg/crypto/block/ofb.go new file mode 100644 index 000000000..084274a08 --- /dev/null +++ b/src/pkg/crypto/block/ofb.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. + +// Output feedback (OFB) mode. + +// OFB converts a block cipher into a stream cipher by +// repeatedly encrypting an initialization vector and +// xoring the resulting stream of data with the input. + +// See NIST SP 800-38A, pp 13-15 + +package block + +import ( + "crypto/block"; + "io"; +) + +type ofbStream struct { + c Cipher; + iv []byte; +} + +func newOFBStream(c Cipher, iv []byte) *ofbStream { + x := new(ofbStream); + x.c = c; + n := len(iv); + if n != c.BlockSize() { + panicln("crypto/block: newOFBStream: invalid iv size", n, "!=", c.BlockSize()); + } + x.iv = copy(iv); + return x; +} + +func (x *ofbStream) Next() []byte { + x.c.Encrypt(x.iv, x.iv); + return x.iv; +} + +// NewOFBReader returns a reader that reads data from r, decrypts (or encrypts) +// it using c in output feedback (OFB) mode with the initialization vector iv. +// The returned Reader does not buffer and has no block size. +// In OFB mode, encryption and decryption are the same operation: +// an OFB reader applied to an encrypted stream produces a decrypted +// stream and vice versa. +func NewOFBReader(c Cipher, iv []byte, r io.Reader) io.Reader { + return newXorReader(newOFBStream(c, iv), r); +} + +// NewOFBWriter returns a writer that encrypts (or decrypts) data using c +// in cipher feedback (OFB) mode with the initialization vector iv +// and writes the encrypted data to w. +// The returned Writer does not buffer and has no block size. +// In OFB mode, encryption and decryption are the same operation: +// an OFB writer applied to an decrypted stream produces an encrypted +// stream and vice versa. +func NewOFBWriter(c Cipher, iv []byte, w io.Writer) io.Writer { + return newXorWriter(newOFBStream(c, iv), w); +} + diff --git a/src/pkg/crypto/block/ofb_aes_test.go b/src/pkg/crypto/block/ofb_aes_test.go new file mode 100644 index 000000000..3f5f9f482 --- /dev/null +++ b/src/pkg/crypto/block/ofb_aes_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. + +// OFB AES test vectors. + +// See U.S. National Institute of Standards and Technology (NIST) +// Special Publication 800-38A, ``Recommendation for Block Cipher +// Modes of Operation,'' 2001 Edition, pp. 52-55. + +package block + +// gotest: $GC ecb_aes_test.go + +import ( + "crypto/aes"; + "crypto/block"; + "io"; + "os"; + "testing"; + + "./ecb_aes_test"; +) + +type ofbTest struct { + name string; + key []byte; + iv []byte; + in []byte; + out []byte; +} + +var ofbAESTests = []ofbTest { + // NIST SP 800-38A pp 52-55 + ofbTest { + "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, + }, + }, + ofbTest { + "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, + }, + }, + ofbTest { + "OFB-AES256", + commonKey256, + commonIV, + commonInput, + []byte { + 0xdc, 0x7e, 0x84, 0xbf, 0xda, 0x79, 0x16, 0x4b, 0x7e, 0xcd, 0x84, 0x86, 0x98, 0x5d, 0x38, 0x60, + 0x4f, 0xeb, 0xdc, 0x67, 0x40, 0xd2, 0x0b, 0x3a, 0xc8, 0x8f, 0x6a, 0xd8, 0x2a, 0x4f, 0xb0, 0x8d, + 0x71, 0xab, 0x47, 0xa0, 0x86, 0xe8, 0x6e, 0xed, 0xf3, 0x9d, 0x1c, 0x5b, 0xba, 0x97, 0xc4, 0x08, + 0x01, 0x26, 0x14, 0x1d, 0x67, 0xf3, 0x7b, 0xe8, 0x53, 0x8f, 0x5a, 0x8b, 0xe7, 0x40, 0xe4, 0x84, + } + }, +} + +func TestOFB_AES(t *testing.T) { + for i, tt := range ofbAESTests { + test := tt.name; + + c, err := aes.NewCipher(tt.key); + if err != nil { + t.Errorf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err); + continue; + } + + for j := 0; j <= 5; j += 5 { + var crypt io.ByteBuffer; + in := tt.in[0:len(tt.in) - j]; + w := NewOFBWriter(c, tt.iv, &crypt); + var r io.Reader = io.NewByteReader(in); + n, err := io.Copy(r, w); + if n != int64(len(in)) || err != nil { + t.Errorf("%s/%d: OFBWriter io.Copy = %d, %v want %d, nil", test, len(in), n, err, len(in)); + } else if d, out := crypt.Data(), tt.out[0:len(in)]; !same(out, d) { + t.Errorf("%s/%d: OFBWriter\ninpt %x\nhave %x\nwant %x", test, len(in), in, d, out); + } + } + + for j := 0; j <= 7; j += 7 { + var plain io.ByteBuffer; + out := tt.out[0:len(tt.out) - j]; + r := NewOFBReader(c, tt.iv, io.NewByteReader(out)); + w := &plain; + n, err := io.Copy(r, w); + if n != int64(len(out)) || err != nil { + t.Errorf("%s/%d: OFBReader io.Copy = %d, %v want %d, nil", test, len(out), n, err, len(out)); + } else if d, in := plain.Data(), tt.in[0:len(out)]; !same(in, d) { + t.Errorf("%s/%d: OFBReader\nhave %x\nwant %x", test, len(out), d, in); + } + } + + if t.Failed() { + break; + } + } +} diff --git a/src/pkg/crypto/block/xor.go b/src/pkg/crypto/block/xor.go new file mode 100644 index 000000000..63229dbb4 --- /dev/null +++ b/src/pkg/crypto/block/xor.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. + +// Encrypt/decrypt data by xor with a pseudo-random data stream. + +package block + +import ( + "crypto/block"; + "io"; + "os"; +) + +// A dataStream is an interface to an unending stream of data, +// used by XorReader and XorWriter to model a pseudo-random generator. +// Calls to Next() return sequential blocks of data from the stream. +// Each call must return at least one byte: there is no EOF. +type dataStream interface { + Next() []byte +} + +type xorReader struct { + r io.Reader; + rand dataStream; // pseudo-random + buf []byte; // data available from last call to rand +} + +func newXorReader(rand dataStream, r io.Reader) io.Reader { + x := new(xorReader); + x.r = r; + x.rand = rand; + return x; +} + +func (x *xorReader) Read(p []byte) (n int, err os.Error) { + n, err = x.r.Read(p); + + // xor input with stream. + bp := 0; + buf := x.buf; + for i := 0; i < n; i++ { + if bp >= len(buf) { + buf = x.rand.Next(); + bp = 0; + } + p[i] ^= buf[bp]; + bp++; + } + x.buf = buf[bp:len(buf)]; + return n, err; +} + +type xorWriter struct { + w io.Writer; + rand dataStream; // pseudo-random + buf []byte; // last buffer returned by rand + extra []byte; // extra random data (use before buf) + work []byte; // work space +} + +func newXorWriter(rand dataStream, w io.Writer) io.Writer { + x := new(xorWriter); + x.w = w; + x.rand = rand; + x.work = make([]byte, 4096); + return x; +} + +func (x *xorWriter) Write(p []byte) (n int, err os.Error) { + for len(p) > 0 { + // Determine next chunk of random data + // and xor with p into x.work. + var chunk []byte; + m := len(p); + if nn := len(x.extra); nn > 0 { + // extra points into work, so edit directly + if m > nn { + m = nn; + } + for i := 0; i < m; i++ { + x.extra[i] ^= p[i]; + } + chunk = x.extra[0:m]; + } else { + // xor p ^ buf into work, refreshing buf as needed + if nn := len(x.work); m > nn { + m = nn; + } + bp := 0; + buf := x.buf; + for i := 0; i < m; i++ { + if bp >= len(buf) { + buf = x.rand.Next(); + bp = 0; + } + x.work[i] = buf[bp] ^ p[i]; + bp++; + } + x.buf = buf[bp:len(buf)]; + chunk = x.work[0:m]; + } + + // Write chunk. + var nn int; + nn, err = x.w.Write(chunk); + if nn != len(chunk) && err == nil { + err = io.ErrShortWrite; + } + if nn < len(chunk) { + // Reconstruct the random bits from the unwritten + // data and save them for next time. + for i := nn; i < m; i++ { + chunk[i] ^= p[i]; + } + x.extra = chunk[nn:len(chunk)]; + } + n += nn; + if err != nil { + return; + } + p = p[m:len(p)]; + } + return; +} + diff --git a/src/pkg/crypto/block/xor_test.go b/src/pkg/crypto/block/xor_test.go new file mode 100644 index 000000000..6e6d1a3ce --- /dev/null +++ b/src/pkg/crypto/block/xor_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 block + +import ( + "crypto/block"; + "fmt"; + "io"; + "testing"; + "testing/iotest"; +) + +// Simple "pseudo-random" stream for testing. +type incStream struct { + buf []byte; + n byte; +} + +func newIncStream(blockSize int) *incStream { + x := new(incStream); + x.buf = make([]byte, blockSize); + return x; +} + +func (x *incStream) Next() []byte { + x.n++; + for i := range x.buf { + x.buf[i] = x.n; + x.n++; + } + return x.buf; +} + +func testXorWriter(t *testing.T, maxio int) { + var plain, crypt [256]byte; + for i := 0; i < len(plain); i++ { + plain[i] = byte(i); + } + b := new(io.ByteBuffer); + for block := 1; block <= 64 && block <= maxio; block *= 2 { + // compute encrypted version + n := byte(0); + for i := 0; i < len(crypt); i++ { + if i % block == 0 { + n++; + } + crypt[i] = plain[i] ^ n; + n++; + } + + for frag := 0; frag < 2; frag++ { + test := fmt.Sprintf("block=%d frag=%d maxio=%d", block, frag, maxio); + b.Reset(); + r := io.NewByteReader(&plain); + s := newIncStream(block); + w := newXorWriter(s, b); + + // copy plain into w in increasingly large chunks: 1, 1, 2, 4, 8, ... + // if frag != 0, move the 1 to the end to cause fragmentation. + if frag == 0 { + nn, err := io.Copyn(r, w, 1); + if err != nil { + t.Errorf("%s: first Copyn: %s", test, err); + continue; + } + } + for n := 1; n <= len(plain)/2; n *= 2 { + nn, err := io.Copyn(r, w, int64(n)); + if err != nil { + t.Errorf("%s: Copyn %d: %s", test, n, err); + } + } + + // check output + crypt := crypt[0:len(crypt) - frag]; + data := b.Data(); + if len(data) != len(crypt) { + t.Errorf("%s: want %d bytes, got %d", test, len(crypt), len(data)); + continue; + } + + if string(data) != string(crypt) { + t.Errorf("%s: want %x got %x", test, data, crypt); + } + } + } +} + + +func TestXorWriter(t *testing.T) { + // Do shorter I/O sizes first; they're easier to debug. + for n := 1; n <= 256 && !t.Failed(); n *= 2 { + testXorWriter(t, n); + } +} + +func testXorReader(t *testing.T, maxio int) { + var readers = []func(io.Reader) io.Reader { + func (r io.Reader) io.Reader { return r }, + iotest.OneByteReader, + iotest.HalfReader, + }; + var plain, crypt [256]byte; + for i := 0; i < len(plain); i++ { + plain[i] = byte(255 - i); + } + b := new(io.ByteBuffer); + for block := 1; block <= 64 && block <= maxio; block *= 2 { + // compute encrypted version + n := byte(0); + for i := 0; i < len(crypt); i++ { + if i % block == 0 { + n++; + } + crypt[i] = plain[i] ^ n; + n++; + } + + for mode := 0; mode < len(readers); mode++ { + for frag := 0; frag < 2; frag++ { + test := fmt.Sprintf("block=%d mode=%d frag=%d maxio=%d", block, mode, frag, maxio); + s := newIncStream(block); + b.Reset(); + r := newXorReader(s, readers[mode](io.NewByteReader(crypt[0:maxio]))); + + // read from crypt in increasingly large chunks: 1, 1, 2, 4, 8, ... + // if frag == 1, move the 1 to the end to cause fragmentation. + if frag == 0 { + nn, err := io.Copyn(r, b, 1); + if err != nil { + t.Errorf("%s: first Copyn: %s", test, err); + continue; + } + } + for n := 1; n <= maxio/2; n *= 2 { + nn, err := io.Copyn(r, b, int64(n)); + if err != nil { + t.Errorf("%s: Copyn %d: %s", test, n, err); + } + } + + // check output + data := b.Data(); + crypt := crypt[0:maxio - frag]; + plain := plain[0:maxio - frag]; + if len(data) != len(plain) { + t.Errorf("%s: want %d bytes, got %d", test, len(plain), len(data)); + continue; + } + + if string(data) != string(plain) { + t.Errorf("%s: input=%x want %x got %x", test, crypt, plain, data); + } + } + } + } +} + +func TestXorReader(t *testing.T) { + // Do shorter I/O sizes first; they're easier to debug. + for n := 1; n <= 256 && !t.Failed(); n *= 2 { + testXorReader(t, n); + } +} + +// TODO(rsc): Test handling of writes after write errors. + diff --git a/src/pkg/crypto/hmac/Makefile b/src/pkg/crypto/hmac/Makefile new file mode 100644 index 000000000..1da3f58dd --- /dev/null +++ b/src/pkg/crypto/hmac/Makefile @@ -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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D=/crypto/ + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + hmac.$O\ + + +phases: a1 +_obj$D/hmac.a: phases + +a1: $(O1) + $(AR) grc _obj$D/hmac.a hmac.$O + rm -f $(O1) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/hmac.a + +$(O1): newpkg +$(O2): a1 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/hmac.a + +packages: _obj$D/hmac.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/hmac.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/hmac.a diff --git a/src/pkg/crypto/hmac/hmac.go b/src/pkg/crypto/hmac/hmac.go new file mode 100644 index 000000000..a3f47ccc9 --- /dev/null +++ b/src/pkg/crypto/hmac/hmac.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. + +// The hmac package implements the Keyed-Hash Message Authentication Code (HMAC) +// as defined in U.S. Federal Information Processing Standards Publication 198. +// An HMAC is a cryptographic hash that uses a key to sign a message. +// The receiver verifies the hash by recomputing it using the same key. +package hmac + +import ( + "crypto/md5"; + "crypto/sha1"; + "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 []byte; + tmp []byte; + 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 { + h.tmpPad(0x5c); + sum := h.inner.Sum(); + for i, b := range sum { + h.tmp[padSize + i] = b; + } + h.inner.Reset(); + h.inner.Write(h.tmp); + return h.inner.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 and key. +func New(h hash.Hash, key []byte) hash.Hash { + if len(key) > padSize { + // If key is too big, hash it. + h.Write(key); + key = h.Sum(); + } + hm := new(hmac); + hm.inner = h; + hm.size = h.Size(); + hm.key = make([]byte, len(key)); + for i, k := range key { + hm.key[i] = k; + } + hm.tmp = make([]byte, padSize + hm.size); + 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); +} diff --git a/src/pkg/crypto/hmac/hmac_test.go b/src/pkg/crypto/hmac/hmac_test.go new file mode 100644 index 000000000..01e532d9f --- /dev/null +++ b/src/pkg/crypto/hmac/hmac_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 hmac + +// TODO(rsc): better test + +import ( + "hash"; + "crypto/hmac"; + "io"; + "fmt"; + "testing"; +) + +type hmacTest struct { + hash func([]byte) hash.Hash; + key []byte; + in []byte; + out string; +} + +// Tests from US FIPS 198 +// http://csrc.nist.gov/publications/fips/fips198/fips-198a.pdf +var hmacTests = []hmacTest { + hmacTest { + 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, + }, + io.StringBytes("Sample #1"), + "4f4ca3d5d68ba7cc0a1208c9c61e9c5da0403c0a", + }, + hmacTest { + NewSHA1, + []byte { + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, + }, + io.StringBytes("Sample #2"), + "0922d3405faa3d194f82a45830737d5cc6c75d24", + }, + hmacTest { + 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, + }, + io.StringBytes("Sample #3"), + "bcf41eab8bb2d802f3d05caf7cb092ecf8d1a3aa", + }, + + // Test from Plan 9. + hmacTest { + NewMD5, + io.StringBytes("Jefe"), + io.StringBytes("what do ya want for nothing?"), + "750c783e6ab0b503eaa86e310a5db738", + } +} + +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; + } + sum := fmt.Sprintf("%x", h.Sum()); + if sum != tt.out { + t.Errorf("test %d.%d: have %s want %s\n", i, j, sum, tt.out); + } + + // Second iteration: make sure reset works. + h.Reset(); + } + } +} diff --git a/src/pkg/crypto/md5/Makefile b/src/pkg/crypto/md5/Makefile new file mode 100644 index 000000000..b6c88d45a --- /dev/null +++ b/src/pkg/crypto/md5/Makefile @@ -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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D=/crypto/ + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + md5.$O\ + +O2=\ + md5block.$O\ + + +phases: a1 a2 +_obj$D/md5.a: phases + +a1: $(O1) + $(AR) grc _obj$D/md5.a md5.$O + rm -f $(O1) + +a2: $(O2) + $(AR) grc _obj$D/md5.a md5block.$O + rm -f $(O2) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/md5.a + +$(O1): newpkg +$(O2): a1 +$(O3): a2 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/md5.a + +packages: _obj$D/md5.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/md5.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/md5.a diff --git a/src/pkg/crypto/md5/md5.go b/src/pkg/crypto/md5/md5.go new file mode 100644 index 000000000..cbc007f01 --- /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. + +// This package implements the MD5 hash algorithm as defined in RFC 1321. +package md5 + +import ( + "hash"; + "os"; +) + +// The size of an MD5 checksum in bytes. +const Size = 16; + +const ( + _Chunk = 64; + + _Init0 = 0x67452301; + _Init1 = 0xEFCDAB89; + _Init2 = 0x98BADCFE; + _Init3 = 0x10325476; +) + +// digest represents the partial evaluation of a checksum. +type digest struct { + s [4]uint32; + x [_Chunk]byte; + nx int; + len uint64; +} + +func (d *digest) Reset() { + d.s[0] = _Init0; + d.s[1] = _Init1; + d.s[2] = _Init2; + d.s[3] = _Init3; + d.nx = 0; + d.len = 0; +} + +// New returns a Hash computing the SHA1 checksum. +func New() hash.Hash { + d := new(digest); + d.Reset(); + return d; +} + +func (d *digest) Size() int { + return Size; +} + +func _Block(dig *digest, p []byte) int + +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); + d.nx = 0; + } + p = p[n:len(p)]; + } + n := _Block(d, p); + p = p[n:len(p)]; + if len(p) > 0 { + for i := 0; i < len(p); i++ { + d.x[i] = p[i]; + } + d.nx = len(p); + } + return; +} + +func (d *digest) Sum() []byte { + // 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 { + panicln("oops"); + } + + p := make([]byte, 16); + j := 0; + for i := 0; i < 4; i++ { + s := d.s[i]; + p[j] = byte(s); j++; + p[j] = byte(s>>8); j++; + p[j] = byte(s>>16); j++; + p[j] = byte(s>>24); j++; + } + 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..f610f1143 --- /dev/null +++ b/src/pkg/crypto/md5/md5_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 md5 + +import ( + "fmt"; + "crypto/md5"; + "io"; + "testing"; +) + +type md5Test struct { + out string; + in string; +} + +var golden = []md5Test { + md5Test{ "d41d8cd98f00b204e9800998ecf8427e", "" }, + md5Test{ "0cc175b9c0f1b6a831c399e269772661", "a" }, + md5Test{ "187ef4436122d1cc2f40dc2b92f0eba0", "ab" }, + md5Test{ "900150983cd24fb0d6963f7d28e17f72", "abc" }, + md5Test{ "e2fc714c4727ee9395f324cd2e7f331f", "abcd" }, + md5Test{ "ab56b4d92b40713acc5af89985d4b786", "abcde" }, + md5Test{ "e80b5017098950fc58aad83c8c14978e", "abcdef" }, + md5Test{ "7ac66c0f148de9519b8bd264312c4d64", "abcdefg" }, + md5Test{ "e8dc4081b13434b45189a720b77b6818", "abcdefgh" }, + md5Test{ "8aa99b1f439ff71293e95357bac6fd94", "abcdefghi" }, + md5Test{ "a925576942e94b2ef57a066101b48876", "abcdefghij" }, + md5Test{ "d747fc1719c7eacb84058196cfe56d57", "Discard medicine more than two years old." }, + md5Test{ "bff2dcb37ef3a44ba43ab144768ca837", "He who has a shady past knows that nice guys finish last." }, + md5Test{ "0441015ecb54a7342d017ed1bcfdbea5", "I wouldn't marry him with a ten foot pole." }, + md5Test{ "9e3cac8e9e9757a60c3ea391130d3689", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave" }, + md5Test{ "a0f04459b031f916a59a35cc482dc039", "The days of the digital watch are numbered. -Tom Stoppard" }, + md5Test{ "e7a48e0fe884faf31475d2a04b1362cc", "Nepal premier won't resign." }, + md5Test{ "637d2fe925c07c113800509964fb0e06", "For every action there is an equal and opposite government program." }, + md5Test{ "834a8d18d5c6562119cf4c7f5086cb71", "His money is twice tainted: 'taint yours and 'taint mine." }, + md5Test{ "de3a4d2fd6c73ec2db2abad23b444281", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977" }, + md5Test{ "acf203f997e2cf74ea3aff86985aefaf", "It's a tiny change to the code and not completely disgusting. - Bob Manchek" }, + md5Test{ "e1c1384cb4d2221dfdd7c795a4222c9a", "size: a.out: bad magic" }, + md5Test{ "c90f3ddecc54f34228c063d7525bf644", "The major problem is with sendmail. -Mark Horton" }, + md5Test{ "cdf7ab6c1fd49bd9933c43f3ea5af185", "Give me a rock, paper and scissors and I will move the world. CCFestoon" }, + md5Test{ "83bc85234942fc883c063cbd7f0ad5d0", "If the enemy is within range, then so are you." }, + md5Test{ "277cbe255686b48dd7e8f389394d9299", "It's well we cannot hear the screams/That we create in others' dreams." }, + md5Test{ "fd3fb0a7ffb8af16603f3d3af98f8e1f", "You remind me of a TV show, but that's all right: I watch it anyway." }, + md5Test{ "469b13a78ebf297ecda64d4723655154", "C is as portable as Stonehedge!!" }, + md5Test{ "63eb3a2f466410104731c4b037600110", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley" }, + md5Test{ "72c2ed7592debca1c90fc0100f931a2f", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule" }, + md5Test{ "132f7619d33b523b1d9e5bd8e0928355", "How can you write a big system without C++? -Paul Glick" }, +} + +func TestGolden(t *testing.T) { + for i := 0; i < len(golden); i++ { + g := golden[i]; + c := New(); + for j := 0; j < 2; j++ { + io.WriteString(c, g.in); + s := fmt.Sprintf("%x", c.Sum()); + if s != g.out { + t.Errorf("md5[%d](%s) = %s want %s", j, g.in, s, g.out); + t.FailNow(); + } + c.Reset(); + } + } +} + diff --git a/src/pkg/crypto/md5/md5block.go b/src/pkg/crypto/md5/md5block.go new file mode 100644 index 000000000..2776c8795 --- /dev/null +++ b/src/pkg/crypto/md5/md5block.go @@ -0,0 +1,178 @@ +// Copyright 2009 The Go 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 + +import "crypto/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; + + for i := 0; i < 16; i++ { + j := i*4; + X[i] = uint32(p[j]) | uint32(p[j+1])<<8 | uint32(p[j+2])<<16 | uint32(p[j+3])<<24; + } + + // 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). + + // Round 1. + for i := 0; i < 16; i++ { + x := i; + t := i; + s := shift1[i%4]; + f := ((c ^ d) & b) ^ d; + a += f + X[x] + table[t]; + a = a<>(32-s); + a += b; + a, b, c, d = d, a, b, c; + } + + // Round 2. + for i := 0; i < 16; i++ { + 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<>(32-s); + a += b; + a, b, c, d = d, a, b, c; + } + + // Round 3. + for i := 0; i < 16; i++ { + x := (5+3*i)%16; + t := 32+i; + s := shift3[i%4]; + h := b ^ c ^ d; + a += h + X[x] + table[t]; + a = a<>(32-s); + a += b; + a, b, c, d = d, a, b, c; + } + + // Round 4. + for i := 0; i < 16; i++ { + x := (7*i)%16; + s := shift4[i%4]; + t := 48+i; + ii := c ^ (b | ^d); + a += ii + X[x] + table[t]; + a = a<>(32-s); + a += b; + a, b, c, d = d, a, b, c; + } + + a += aa; + b += bb; + c += cc; + d += dd; + + p = p[_Chunk:len(p)]; + 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/sha1/Makefile b/src/pkg/crypto/sha1/Makefile new file mode 100644 index 000000000..03ffe4fd7 --- /dev/null +++ b/src/pkg/crypto/sha1/Makefile @@ -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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D=/crypto/ + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + sha1.$O\ + +O2=\ + sha1block.$O\ + + +phases: a1 a2 +_obj$D/sha1.a: phases + +a1: $(O1) + $(AR) grc _obj$D/sha1.a sha1.$O + rm -f $(O1) + +a2: $(O2) + $(AR) grc _obj$D/sha1.a sha1block.$O + rm -f $(O2) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/sha1.a + +$(O1): newpkg +$(O2): a1 +$(O3): a2 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/sha1.a + +packages: _obj$D/sha1.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/sha1.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/sha1.a diff --git a/src/pkg/crypto/sha1/sha1.go b/src/pkg/crypto/sha1/sha1.go new file mode 100644 index 000000000..a4cccd7a3 --- /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. + +// This package implements the SHA1 hash algorithm as defined in RFC 3174. +package sha1 + +import ( + "hash"; + "os"; +) + +// The size of a SHA1 checksum in bytes. +const Size = 20; + +const ( + _Chunk = 64; + + _Init0 = 0x67452301; + _Init1 = 0xEFCDAB89; + _Init2 = 0x98BADCFE; + _Init3 = 0x10325476; + _Init4 = 0xC3D2E1F0; +) + +// digest represents the partial evaluation of a checksum. +type digest struct { + h [5]uint32; + x [_Chunk]byte; + nx int; + len uint64; +} + +func (d *digest) Reset() { + d.h[0] = _Init0; + d.h[1] = _Init1; + d.h[2] = _Init2; + d.h[3] = _Init3; + d.h[4] = _Init4; + d.nx = 0; + d.len = 0; +} + +// New returns a Hash computing the SHA1 checksum. +func New() hash.Hash { + d := new(digest); + d.Reset(); + return d; +} + +func (d *digest) Size() int { + return Size; +} + +func _Block(dig *digest, p []byte) int + +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); + d.nx = 0; + } + p = p[n:len(p)]; + } + n := _Block(d, p); + p = p[n:len(p)]; + if len(p) > 0 { + for i := 0; i < len(p); i++ { + d.x[i] = p[i]; + } + d.nx = len(p); + } + return; +} + +func (d *digest) Sum() []byte { + // 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 { + panicln("oops"); + } + + p := make([]byte, 20); + j := 0; + for i := 0; i < 5; i++ { + s := d.h[i]; + p[j] = byte(s>>24); j++; + p[j] = byte(s>>16); j++; + p[j] = byte(s>>8); j++; + p[j] = byte(s); j++; + } + 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..381cc76ee --- /dev/null +++ b/src/pkg/crypto/sha1/sha1_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. + +// SHA1 hash algorithm. See RFC 3174. + +package sha1 + +import ( + "fmt"; + "crypto/sha1"; + "io"; + "testing"; +) + +type sha1Test struct { + out string; + in string; +} + +var golden = []sha1Test { + sha1Test{ "da39a3ee5e6b4b0d3255bfef95601890afd80709", "" }, + sha1Test{ "86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", "a" }, + sha1Test{ "da23614e02469a0d7c7bd1bdab5c9c474b1904dc", "ab" }, + sha1Test{ "a9993e364706816aba3e25717850c26c9cd0d89d", "abc" }, + sha1Test{ "81fe8bfe87576c3ecb22426f8e57847382917acf", "abcd" }, + sha1Test{ "03de6c570bfe24bfc328ccd7ca46b76eadaf4334", "abcde" }, + sha1Test{ "1f8ac10f23c5b5bc1167bda84b833e5c057a77d2", "abcdef" }, + sha1Test{ "2fb5e13419fc89246865e7a324f476ec624e8740", "abcdefg" }, + sha1Test{ "425af12a0743502b322e93a015bcf868e324d56a", "abcdefgh" }, + sha1Test{ "c63b19f1e4c8b5f76b25c49b8b87f57d8e4872a1", "abcdefghi" }, + sha1Test{ "d68c19a0a345b7eab78d5e11e991c026ec60db63", "abcdefghij" }, + sha1Test{ "ebf81ddcbe5bf13aaabdc4d65354fdf2044f38a7", "Discard medicine more than two years old." }, + sha1Test{ "e5dea09392dd886ca63531aaa00571dc07554bb6", "He who has a shady past knows that nice guys finish last." }, + sha1Test{ "45988f7234467b94e3e9494434c96ee3609d8f8f", "I wouldn't marry him with a ten foot pole." }, + sha1Test{ "55dee037eb7460d5a692d1ce11330b260e40c988", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave" }, + sha1Test{ "b7bc5fb91080c7de6b582ea281f8a396d7c0aee8", "The days of the digital watch are numbered. -Tom Stoppard" }, + sha1Test{ "c3aed9358f7c77f523afe86135f06b95b3999797", "Nepal premier won't resign." }, + sha1Test{ "6e29d302bf6e3a5e4305ff318d983197d6906bb9", "For every action there is an equal and opposite government program." }, + sha1Test{ "597f6a540010f94c15d71806a99a2c8710e747bd", "His money is twice tainted: 'taint yours and 'taint mine." }, + sha1Test{ "6859733b2590a8a091cecf50086febc5ceef1e80", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977" }, + sha1Test{ "514b2630ec089b8aee18795fc0cf1f4860cdacad", "It's a tiny change to the code and not completely disgusting. - Bob Manchek" }, + sha1Test{ "c5ca0d4a7b6676fc7aa72caa41cc3d5df567ed69", "size: a.out: bad magic" }, + sha1Test{ "74c51fa9a04eadc8c1bbeaa7fc442f834b90a00a", "The major problem is with sendmail. -Mark Horton" }, + sha1Test{ "0b4c4ce5f52c3ad2821852a8dc00217fa18b8b66", "Give me a rock, paper and scissors and I will move the world. CCFestoon" }, + sha1Test{ "3ae7937dd790315beb0f48330e8642237c61550a", "If the enemy is within range, then so are you." }, + sha1Test{ "410a2b296df92b9a47412b13281df8f830a9f44b", "It's well we cannot hear the screams/That we create in others' dreams." }, + sha1Test{ "841e7c85ca1adcddbdd0187f1289acb5c642f7f5", "You remind me of a TV show, but that's all right: I watch it anyway." }, + sha1Test{ "163173b825d03b952601376b25212df66763e1db", "C is as portable as Stonehedge!!" }, + sha1Test{ "32b0377f2687eb88e22106f133c586ab314d5279", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley" }, + sha1Test{ "0885aaf99b569542fd165fa44e322718f4a984e0", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule" }, + sha1Test{ "6627d6904d71420b0bf3886ab629623538689f45", "How can you write a big system without C++? -Paul Glick" }, +} + +func TestGolden(t *testing.T) { + for i := 0; i < len(golden); i++ { + g := golden[i]; + c := New(); + for j := 0; j < 2; j++ { + io.WriteString(c, g.in); + s := fmt.Sprintf("%x", c.Sum()); + if s != g.out { + t.Errorf("sha1[%d](%s) = %s want %s", j, g.in, s, g.out); + t.FailNow(); + } + c.Reset(); + } + } +} + diff --git a/src/pkg/crypto/sha1/sha1block.go b/src/pkg/crypto/sha1/sha1block.go new file mode 100644 index 000000000..01ddd9506 --- /dev/null +++ b/src/pkg/crypto/sha1/sha1block.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. + +// SHA1 block step. +// In its own file so that a faster assembly or C version +// can be substituted easily. + +package sha1 + +import "crypto/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:len(p)]; + 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/datafmt/Makefile b/src/pkg/datafmt/Makefile new file mode 100644 index 000000000..1546faf7e --- /dev/null +++ b/src/pkg/datafmt/Makefile @@ -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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D= + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + datafmt.$O\ + +O2=\ + parser.$O\ + + +phases: a1 a2 +_obj$D/datafmt.a: phases + +a1: $(O1) + $(AR) grc _obj$D/datafmt.a datafmt.$O + rm -f $(O1) + +a2: $(O2) + $(AR) grc _obj$D/datafmt.a parser.$O + rm -f $(O2) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/datafmt.a + +$(O1): newpkg +$(O2): a1 +$(O3): a2 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/datafmt.a + +packages: _obj$D/datafmt.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/datafmt.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/datafmt.a diff --git a/src/pkg/datafmt/datafmt.go b/src/pkg/datafmt/datafmt.go new file mode 100644 index 000000000..0aedbbbb0 --- /dev/null +++ b/src/pkg/datafmt/datafmt.go @@ -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. + +/* 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 ( + "container/vector"; + "fmt"; + "go/token"; + "io"; + "os"; + "reflect"; + "runtime"; + "strconv"; + "strings"; +) + + +// ---------------------------------------------------------------------------- +// Format representation + +type State struct + +// 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 io.ByteBuffer; // current indentation + output io.ByteBuffer; // 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.Data()); + n += n1 + n2; + i0 = i + 1; + s.linePos.Offset = s.output.Len(); + s.linePos.Line++; + } + } + n3, _ := s.output.Write(data[i0 : len(data)]); + 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(); +} + + +// getField searches in val, which must be a struct, for a field +// with the given name. It returns the value and the embedded depth +// where it was found. +// +func getField(val reflect.Value, fieldname string) (reflect.Value, int) { + // do we have a struct in the first place? + if val.Kind() != reflect.StructKind { + return nil, 0; + } + + sval, styp := val.(reflect.StructValue), val.Type().(reflect.StructType); + + // look for field at the top level + for i := 0; i < styp.Len(); i++ { + name, typ, tag, offset := styp.Field(i); + if name == fieldname || name == "" && strings.HasSuffix(typ.Name(), "." + fieldname) /* anonymous field */ { + return sval.Field(i), 0; + } + } + + // look for field in anonymous fields + var field reflect.Value; + level := 1000; // infinity (no struct has that many levels) + for i := 0; i < styp.Len(); i++ { + name, typ, tag, offset := styp.Field(i); + if name == "" { + f, l := getField(sval.Field(i), fieldname); + // keep the most shallow field + if f != nil { + switch { + case l < level: + field, level = f, l; + case l == level: + // more than one field at the same level, + // possibly an error unless there is a more + // shallow field found later + field = nil; + } + } + } + } + + return field, level + 1; +} + + +// 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. +// +var defaultNames = map[int]string { + reflect.ArrayKind: "array", + reflect.BoolKind: "bool", + reflect.ChanKind: "chan", + reflect.DotDotDotKind: "ellipsis", + reflect.FloatKind: "float", + reflect.Float32Kind: "float32", + reflect.Float64Kind: "float64", + reflect.FuncKind: "func", + reflect.IntKind: "int", + reflect.Int16Kind: "int16", + reflect.Int32Kind: "int32", + reflect.Int64Kind: "int64", + reflect.Int8Kind: "int8", + reflect.InterfaceKind: "interface", + reflect.MapKind: "map", + reflect.PtrKind: "ptr", + reflect.StringKind: "string", + reflect.StructKind: "struct", + reflect.UintKind: "uint", + reflect.Uint16Kind: "uint16", + reflect.Uint32Kind: "uint32", + reflect.Uint64Kind: "uint64", + reflect.Uint8Kind: "uint8", + reflect.UintptrKind: "uintptr", +} + + +func typename(value reflect.Value) string { + name := value.Type().Name(); + if name == "" { + if defaultName, found := defaultNames[value.Kind()]; found { + name = defaultName; + } + } + return name; +} + + +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 : len(lit)]); + } 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.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.Sub(); + + case reflect.InterfaceValue: + if v.IsNil() { + return false; + } + value = v.Value(); + + 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().Name())); + } + + default: + // value is value of named field + field, _ := getField(value, 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().Name())); + } + value = field; + } + + // determine rule + ruleName := t.ruleName; + if ruleName == "" { + // no alternate rule name, value type determines rule + ruleName = typename(value) + } + 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.Data()[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 occured, 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 ...) ([]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() { + value := reflect.NewValue(args).(reflect.StructValue); + for i := 0; i < value.Len(); i++ { + fld := value.Field(i); + mark := s.save(); + if !s.eval(s.getFormat(typename(fld)), fld, 0) { // TODO is 0 index correct? + s.restore(mark); + } + } + errors <- nil; // no errors + }(); + + return s.output.Data(), <- errors; +} + + +// ---------------------------------------------------------------------------- +// 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 ...) (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 ...) (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 ...) string { + var buf io.ByteBuffer; + n, err := f.Fprint(&buf, nil, args); + if err != nil { + fmt.Fprintf(&buf, "--- Sprint(%s) failed: %v", fmt.Sprint(args), err); + } + return string(buf.Data()); +} diff --git a/src/pkg/datafmt/datafmt_test.go b/src/pkg/datafmt/datafmt_test.go new file mode 100644 index 000000000..788c013c6 --- /dev/null +++ b/src/pkg/datafmt/datafmt_test.go @@ -0,0 +1,375 @@ +// Copyright 2009 The Go Authors. 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"; + "datafmt"; + "io"; + "os"; + "testing"; +) + + +func parse(t *testing.T, form string, fmap FormatterMap) Format { + f, err := Parse(io.StringBytes(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 ...) { + 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(io.StringBytes("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; float="#"`, fmap1); + verify(t, f, `# # #`, 0.0, 1.0, 2.0); + + f = parse(t, `float=@: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 ...) { + 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, `float ="%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 TestInterfaceTypes(t *testing.T) { + var i0 interface{}; + check(t, `interface="interface"`, `interface`, i0); + + i0 = "foo"; + check(t, `interface="interface"`, `interface`, i0); + check(t, `interface=*; string="%s"`, `foo`, i0); +} + + +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/datafmt/parser.go b/src/pkg/datafmt/parser.go new file mode 100644 index 000000000..0d597dcb5 --- /dev/null +++ b/src/pkg/datafmt/parser.go @@ -0,0 +1,447 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package datafmt + +import ( + "container/vector"; + "datafmt"; + "fmt"; + "go/scanner"; + "go/token"; + "io"; + "os"; + "strconv"; + "strings"; +) + +// ---------------------------------------------------------------------------- +// Error handling + +// Error describes an individual error. The position Pos, if valid, +// indicates the format source position the error relates to. The +// error is specified with the Msg string. +// +type Error struct { + Pos token.Position; + Msg string; +} + + +func (e *Error) String() string { + pos := ""; + if e.Pos.IsValid() { + pos = fmt.Sprintf("%d:%d: ", e.Pos.Line, e.Pos.Column); + } + return pos + e.Msg; +} + + +// An ErrorList is a list of errors encountered during parsing. +type ErrorList []*Error + + +// ErrorList implements SortInterface and the os.Error 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 { return p[i].Pos.Offset < p[j].Pos.Offset; } + + +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); +} + + +// ---------------------------------------------------------------------------- +// Parsing + +type parser struct { + errors vector.Vector; + scanner scanner.Scanner; + pos token.Position; // token position + tok token.Token; // one token look-ahead + lit []byte; // token literal + + packs map [string] string; // PackageName -> ImportPath + rules map [string] expr; // RuleName -> Expression +} + + +func (p *parser) next() { + p.pos, p.tok, p.lit = p.scanner.Scan(); + switch p.tok { + case token.CHAN, token.FUNC, token.INTERFACE, token.MAP, token.STRUCT: + // Go keywords for composite types are type names + // returned by reflect. Accept them as identifiers. + p.tok = token.IDENT; // p.lit is already set correctly + } +} + + +func (p *parser) init(src []byte) { + p.errors.Init(0); + p.scanner.Init(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); +} + + +// The parser implements scanner.Error. +func (p *parser) Error(pos token.Position, msg string) { + // Don't collect errors that are on the same line as the previous error + // in the hope to reduce the number of spurious errors due to incorrect + // parser synchronization. + if p.errors.Len() == 0 || p.errors.Last().(*Error).Pos.Line != pos.Line { + p.errors.Push(&Error{pos, msg}); + } +} + + +func (p *parser) errorExpected(pos token.Position, msg string) { + msg = "expected " + msg; + if pos.Offset == p.pos.Offset { + // the error happened at the current position; + // make the error message more specific + msg += ", found '" + p.tok.String() + "'"; + if p.tok.IsLiteral() { + msg += " " + string(p.lit); + } + } + p.Error(pos, msg); +} + + +func (p *parser) expect(tok token.Token) token.Position { + pos := p.pos; + if p.tok != tok { + p.errorExpected(pos, "'" + tok.String() + "'"); + } + p.next(); // make progress in any case + return pos; +} + + +func (p *parser) parseIdentifier() string { + name := string(p.lit); + p.expect(token.IDENT); + return name; +} + + +func (p *parser) parseTypeName() (string, bool) { + pos := p.pos; + name, isIdent := p.parseIdentifier(), true; + if p.tok == token.PERIOD { + // got a package name, lookup package + if importPath, found := p.packs[name]; found { + name = importPath; + } else { + p.Error(pos, "package not declared: " + name); + } + p.next(); + name, isIdent = name + "." + p.parseIdentifier(), false; + } + return name, isIdent; +} + + +// Parses a rule name and returns it. If the rule name is +// a package-qualified type name, the package name is resolved. +// The 2nd result value is true iff the rule name consists of a +// single identifier only (and thus could be a package name). +// +func (p *parser) parseRuleName() (string, bool) { + name, isIdent := "", false; + switch p.tok { + case token.IDENT: + name, isIdent = p.parseTypeName(); + case token.DEFAULT: + name = "default"; + p.next(); + case token.QUO: + name = "/"; + p.next(); + default: + p.errorExpected(p.pos, "rule name"); + p.next(); // make progress in any case + } + return name, isIdent; +} + + +func (p *parser) parseString() string { + s := ""; + if p.tok == token.STRING { + var err os.Error; + s, err = strconv.Unquote(string(p.lit)); + // Unquote may fail with an error, but only if the scanner found + // an illegal string in the first place. In this case the error + // has already been reported. + p.next(); + return s; + } else { + p.expect(token.STRING); + } + return s; +} + + +func (p *parser) parseLiteral() literal { + s := io.StringBytes(p.parseString()); + + // A string literal may contain %-format specifiers. To simplify + // and speed up printing of the literal, split it into segments + // that start with "%" possibly followed by a last segment that + // starts with some other character. + var list vector.Vector; + list.Init(0); + i0 := 0; + for i := 0; i < len(s); i++ { + if s[i] == '%' && i+1 < len(s) { + // the next segment starts with a % format + if i0 < i { + // the current segment is not empty, split it off + list.Push(s[i0 : i]); + i0 = i; + } + i++; // skip %; let loop skip over char after % + } + } + // the final segment may start with any character + // (it is empty iff the string is empty) + list.Push(s[i0 : len(s)]); + + // convert list into a literal + lit := make(literal, list.Len()); + for i := 0; i < list.Len(); i++ { + lit[i] = list.At(i).([]byte); + } + + return lit; +} + + +func (p *parser) parseField() expr { + var fname string; + switch p.tok { + case token.ILLEGAL: + if string(p.lit) != "@" { + return nil; + } + fname = "@"; + p.next(); + case token.MUL: + fname = "*"; + p.next(); + case token.IDENT: + fname = p.parseIdentifier(); + default: + return nil; + } + + var ruleName string; + if p.tok == token.COLON { + p.next(); + var _ bool; + ruleName, _ = p.parseRuleName(); + } + + return &field{fname, ruleName}; +} + + +func (p *parser) parseExpression() expr + +func (p *parser) parseOperand() (x expr) { + switch p.tok { + case token.STRING: + x = p.parseLiteral(); + + case token.LPAREN: + p.next(); + x = p.parseExpression(); + if p.tok == token.SHR { + p.next(); + x = &group{x, p.parseExpression()}; + } + p.expect(token.RPAREN); + + case token.LBRACK: + p.next(); + x = &option{p.parseExpression()}; + p.expect(token.RBRACK); + + case token.LBRACE: + p.next(); + x = p.parseExpression(); + var div expr; + if p.tok == token.QUO { + p.next(); + div = p.parseExpression(); + } + x = &repetition{x, div}; + p.expect(token.RBRACE); + + default: + x = p.parseField(); // may be nil + } + + return x; +} + + +func (p *parser) parseSequence() expr { + var list vector.Vector; + list.Init(0); + + for x := p.parseOperand(); x != nil; x = p.parseOperand() { + list.Push(x); + } + + // no need for a sequence if list.Len() < 2 + switch list.Len() { + case 0: return nil; + case 1: return list.At(0).(expr); + } + + // convert list into a sequence + seq := make(sequence, list.Len()); + for i := 0; i < list.Len(); i++ { + seq[i] = list.At(i).(expr); + } + return seq; +} + + +func (p *parser) parseExpression() expr { + var list vector.Vector; + list.Init(0); + + for { + x := p.parseSequence(); + if x != nil { + list.Push(x); + } + if p.tok != token.OR { + break; + } + p.next(); + } + + // no need for an alternatives if list.Len() < 2 + switch list.Len() { + case 0: return nil; + case 1: return list.At(0).(expr); + } + + // convert list into a alternatives + alt := make(alternatives, list.Len()); + for i := 0; i < list.Len(); i++ { + alt[i] = list.At(i).(expr); + } + return alt; +} + + +func (p *parser) parseFormat() { + for p.tok != token.EOF { + pos := p.pos; + + name, isIdent := p.parseRuleName(); + switch p.tok { + case token.STRING: + // package declaration + importPath := p.parseString(); + + // add package declaration + if !isIdent { + p.Error(pos, "illegal package name: " + name); + } else if _, found := p.packs[name]; !found { + p.packs[name] = importPath; + } else { + p.Error(pos, "package already declared: " + name); + } + + case token.ASSIGN: + // format rule + p.next(); + x := p.parseExpression(); + + // add rule + if _, found := p.rules[name]; !found { + p.rules[name] = x; + } else { + p.Error(pos, "format rule already declared: " + name); + } + + default: + p.errorExpected(p.pos, "package declaration or format rule"); + p.next(); // make progress in any case + } + + if p.tok == token.SEMICOLON { + p.next(); + } else { + break; + } + } + p.expect(token.EOF); +} + + +func remap(p *parser, name string) string { + i := strings.Index(name, "."); + if i >= 0 { + packageName, suffix := name[0 : i], name[i : len(name)]; + // 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(src []byte, fmap FormatterMap) (Format, os.Error) { + // parse source + var p parser; + p.init(src); + p.parseFormat(); + + // add custom formatters, if any + for name, form := range fmap { + name = remap(&p, name); + if t, found := p.rules[name]; !found { + p.rules[name] = &custom{name, form}; + } else { + var invalidPos token.Position; + p.Error(invalidPos, "formatter already declared: " + name); + } + } + + // convert errors list, if any + if p.errors.Len() > 0 { + errors := make(ErrorList, p.errors.Len()); + for i := 0; i < p.errors.Len(); i++ { + errors[i] = p.errors.At(i).(*Error); + } + return nil, errors; + } + + return p.rules, nil; +} diff --git a/src/pkg/exec/Makefile b/src/pkg/exec/Makefile new file mode 100644 index 000000000..679cc39c0 --- /dev/null +++ b/src/pkg/exec/Makefile @@ -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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D= + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + exec.$O\ + + +phases: a1 +_obj$D/exec.a: phases + +a1: $(O1) + $(AR) grc _obj$D/exec.a exec.$O + rm -f $(O1) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/exec.a + +$(O1): newpkg +$(O2): a1 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/exec.a + +packages: _obj$D/exec.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/exec.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/exec.a diff --git a/src/pkg/exec/exec.go b/src/pkg/exec/exec.go new file mode 100644 index 000000000..c2b7bdd59 --- /dev/null +++ b/src/pkg/exec/exec.go @@ -0,0 +1,228 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// The exec package runs external commands. +package exec + +import ( + "os"; + "strings"; +) + +// Arguments to Run. +const ( + DevNull = iota; + PassThrough; + Pipe; + MergeWithStdout; +) + +// A Cmd represents a running command. +// Stdin, Stdout, and Stderr are Files representing pipes +// connected to the running command's standard input, output, and error, +// or else nil, depending on the arguments to Run. +// Pid is the running command's operating system process ID. +type Cmd struct { + Stdin *os.File; + Stdout *os.File; + Stderr *os.File; + Pid int; +} + +// Given mode (DevNull, etc), return file for child +// and file to record in Cmd structure. +func modeToFiles(mode, fd int) (*os.File, *os.File, os.Error) { + switch mode { + case DevNull: + rw := os.O_WRONLY; + if fd == 0 { + rw = os.O_RDONLY; + } + f, err := os.Open("/dev/null", rw, 0); + return f, nil, err; + case PassThrough: + switch fd { + case 0: + return os.Stdin, nil, nil; + case 1: + return os.Stdout, nil, nil; + case 2: + return os.Stderr, nil, nil; + } + case Pipe: + r, w, err := os.Pipe(); + if err != nil { + return nil, nil, err; + } + if fd == 0 { + return r, w, nil; + } + return w, r, nil; + } + return nil, nil, os.EINVAL; +} + +// Run starts the binary prog running with +// arguments argv and environment envv. +// It returns a pointer to a new Cmd representing +// the command or an error. +// +// The parameters stdin, stdout, and stderr +// specify how to handle standard input, output, and error. +// The choices are DevNull (connect to /dev/null), +// PassThrough (connect to the current process's standard stream), +// Pipe (connect to an operating system pipe), and +// MergeWithStdout (only for standard error; use the same +// file descriptor as was used for standard output). +// If a parameter is Pipe, then the corresponding field (Stdin, Stdout, Stderr) +// of the returned Cmd is the other end of the pipe. +// Otherwise the field in Cmd is nil. +func Run(argv0 string, argv, envv []string, stdin, stdout, stderr int) (p *Cmd, err os.Error) +{ + p = new(Cmd); + var fd [3]*os.File; + + if fd[0], p.Stdin, err = modeToFiles(stdin, 0); err != nil { + goto Error; + } + if fd[1], p.Stdout, err = modeToFiles(stdout, 1); err != nil { + goto Error; + } + if stderr == MergeWithStdout { + p.Stderr = p.Stdout; + } else if fd[2], p.Stderr, err = modeToFiles(stderr, 2); err != nil { + goto Error; + } + + // Run command. + p.Pid, err = os.ForkExec(argv0, argv, envv, "", &fd); + if err != nil { + goto Error; + } + if fd[0] != os.Stdin { + fd[0].Close(); + } + if fd[1] != os.Stdout { + fd[1].Close(); + } + if fd[2] != os.Stderr && fd[2] != fd[1] { + fd[2].Close(); + } + return p, nil; + +Error: + if fd[0] != os.Stdin && fd[0] != nil { + fd[0].Close(); + } + if fd[1] != os.Stdout && fd[1] != nil { + fd[1].Close(); + } + if fd[2] != os.Stderr && fd[2] != nil && fd[2] != fd[1] { + fd[2].Close(); + } + if p.Stdin != nil { + p.Stdin.Close(); + } + if p.Stdout != nil { + p.Stdout.Close(); + } + if p.Stderr != nil { + p.Stderr.Close(); + } + return nil, err; +} + +// Wait waits for the running command p, +// returning the Waitmsg returned by os.Wait and an error. +// The options are passed through to os.Wait. +// Setting options to 0 waits for p to exit; +// other options cause Wait to return for other +// process events; see package os for details. +func (p *Cmd) Wait(options int) (*os.Waitmsg, os.Error) { + if p.Pid < 0 { + return nil, os.EINVAL; + } + w, err := os.Wait(p.Pid, options); + if w != nil && (w.Exited() || w.Signaled()) { + p.Pid = -1; + } + return w, err; +} + +// Close waits for the running command p to exit, +// if it hasn't already, and then closes the non-nil file descriptors +// p.Stdin, p.Stdout, and p.Stderr. +func (p *Cmd) Close() os.Error { + if p.Pid >= 0 { + // Loop on interrupt, but + // ignore other errors -- maybe + // caller has already waited for pid. + w, err := p.Wait(0); + for err == os.EINTR { + w, err = p.Wait(0); + } + } + + // Close the FDs that are still open. + var err os.Error; + if p.Stdin != nil && p.Stdin.Fd() >= 0 { + if err1 := p.Stdin.Close(); err1 != nil { + err = err1; + } + } + if p.Stdout != nil && p.Stdout.Fd() >= 0 { + if err1 := p.Stdout.Close(); err1 != nil && err != nil { + err = err1; + } + } + if p.Stderr != nil && p.Stderr != p.Stdout && p.Stderr.Fd() >= 0 { + if err1 := p.Stderr.Close(); err1 != nil && err != nil { + err = err1; + } + } + return err; +} + +func canExec(file string) bool{ + d, err := os.Stat(file); + if err != nil { + return false; + } + return d.IsRegular() && d.Permission() & 0111 != 0; +} + +// LookPath searches for an executable binary named file +// in the directories named by the PATH environment variable. +// If file contains a slash, it is tried directly and the PATH is not consulted. +// +// TODO(rsc): Does LookPath belong in os instead? +func LookPath(file string) (string, os.Error) { + // NOTE(rsc): I wish we could use the Plan 9 behavior here + // (only bypass the path if file begins with / or ./ or ../) + // but that would not match all the Unix shells. + + if strings.Index(file, "/") >= 0 { + if canExec(file) { + return file, nil; + } + return "", os.ENOENT; + } + pathenv, err := os.Getenv("PATH"); + if err != nil { + // Unix shell semantics: no $PATH means assume PATH="" + // (equivalent to PATH="."). + pathenv = ""; + } + for i, dir := range strings.Split(pathenv, ":") { + if dir == "" { + // Unix shell semantics: path element "" means "." + dir = "."; + } + if canExec(dir+"/"+file) { + return dir+"/"+file, nil; + } + } + return "", os.ENOENT; +} + diff --git a/src/pkg/exec/exec_test.go b/src/pkg/exec/exec_test.go new file mode 100644 index 000000000..a1bb1f50e --- /dev/null +++ b/src/pkg/exec/exec_test.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 exec + +import ( + "exec"; + "io"; + "testing"; +) + +func TestRunCat(t *testing.T) { + cmd, err := exec.Run("/bin/cat", []string{"cat"}, nil, + exec.Pipe, exec.Pipe, exec.DevNull); + if err != nil { + t.Fatalf("opencmd /bin/cat: %v", err); + } + io.WriteString(cmd.Stdin, "hello, world\n"); + cmd.Stdin.Close(); + var buf [64]byte; + n, err1 := io.FullRead(cmd.Stdout, &buf); + if err1 != nil && err1 != io.ErrEOF { + t.Fatalf("reading from /bin/cat: %v", err1); + } + if string(buf[0:n]) != "hello, world\n" { + t.Fatalf("reading from /bin/cat: got %q", buf[0:n]); + } + if err1 = cmd.Close(); err1 != nil { + t.Fatalf("closing /bin/cat: %v", err1); + } +} + +func TestRunEcho(t *testing.T) { + cmd, err := Run("/bin/echo", []string{"echo", "hello", "world"}, nil, + exec.DevNull, exec.Pipe, exec.DevNull); + if err != nil { + t.Fatalf("opencmd /bin/echo: %v", err); + } + var buf [64]byte; + n, err1 := io.FullRead(cmd.Stdout, &buf); + if err1 != nil && err1 != io.ErrEOF { + t.Fatalf("reading from /bin/echo: %v", err1); + } + if string(buf[0:n]) != "hello world\n" { + t.Fatalf("reading from /bin/echo: got %q", buf[0:n]); + } + if err1 = cmd.Close(); err1 != nil { + t.Fatalf("closing /bin/echo: %v", err1); + } +} diff --git a/src/pkg/exvar/Makefile b/src/pkg/exvar/Makefile new file mode 100644 index 000000000..a65a1ee6b --- /dev/null +++ b/src/pkg/exvar/Makefile @@ -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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D= + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + exvar.$O\ + + +phases: a1 +_obj$D/exvar.a: phases + +a1: $(O1) + $(AR) grc _obj$D/exvar.a exvar.$O + rm -f $(O1) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/exvar.a + +$(O1): newpkg +$(O2): a1 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/exvar.a + +packages: _obj$D/exvar.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/exvar.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/exvar.a diff --git a/src/pkg/exvar/exvar.go b/src/pkg/exvar/exvar.go new file mode 100644 index 000000000..6473f7af6 --- /dev/null +++ b/src/pkg/exvar/exvar.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. + +// The exvar package provides a standardized interface to public variables, +// such as operation counters in servers. It exposes these variables via +// HTTP at /debug/vars in JSON format. +package exvar + +import ( + "fmt"; + "http"; + "io"; + "log"; + "strconv"; + "sync"; +) + +// Var is an abstract type for all exported variables. +type Var interface { + String() string; +} + +// Int is a 64-bit integer variable, and 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; +} + +// Map is a string-to-Var map variable, and 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(io.ByteBuffer); + 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 string(b.Data()) +} + +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(); + if av, ok := v.m[key]; ok { + return av + } + return nil +} + +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); + } +} + +// TODO(rsc): Make sure map access in separate thread is safe. +func (v *Map) iterate(c chan<- KeyValue) { + for k, v := range v.m { + c <- KeyValue{ k, v }; + } + close(c); +} + +func (v *Map) Iter() <-chan KeyValue { + c := make(chan KeyValue); + go v.iterate(c); + return c +} + +// String is a string variable, and satisfies the Var interface. +type String struct { + s string; +} + +func (v *String) String() string { + return strconv.Quote(v.s) +} + +func (v *String) Set(value string) { + v.s = value; +} + +// IntFunc wraps a func() int64 to create a value that satisfies the Var interface. +// The function will be called each time the Var is evaluated. +type IntFunc func() int64; + +func (v IntFunc) String() string { + return strconv.Itoa64(v()) +} + + +// 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.Crash. +func Publish(name string, v Var) { + mutex.Lock(); + defer mutex.Unlock(); + if _, existing := vars[name]; existing { + log.Crash("Reuse of exported var name:", name); + } + vars[name] = v; +} + +// Get retrieves a named exported variable. +func Get(name string) Var { + if v, ok := vars[name]; ok { + return v + } + return nil +} + +// Convenience functions for creating new exported variables. + +func NewInt(name string) *Int { + v := new(Int); + 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 exvarHandler(c *http.Conn, req *http.Request) { + c.SetHeader("content-type", "application/json; charset=utf-8"); + fmt.Fprintf(c, "{\n"); + first := true; + for name, value := range vars { + if !first { + fmt.Fprintf(c, ",\n"); + } + first = false; + fmt.Fprintf(c, " %q: %s", name, value); + } + fmt.Fprintf(c, "\n}\n"); +} + +func init() { + http.Handle("/debug/vars", http.HandlerFunc(exvarHandler)); +} diff --git a/src/pkg/exvar/exvar_test.go b/src/pkg/exvar/exvar_test.go new file mode 100644 index 000000000..8b028bccb --- /dev/null +++ b/src/pkg/exvar/exvar_test.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 exvar + +import ( + "exvar"; + "fmt"; + "json"; + "testing"; +) + +func TestInt(t *testing.T) { + reqs := NewInt("requests"); + if reqs.i != 0 { + t.Errorf("reqs.i = %v, want 4", 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); + } +} + +func TestString(t *testing.T) { + name := NewString("my-name"); + if name.s != "" { + t.Errorf("name.s = %q, want \"\"", name.s) + } + + name.Set("Mike"); + if name.s != "Mike" { + t.Errorf("name.s = %q, want \"Mike\"", name.s) + } + + if s := name.String(); s != "\"Mike\"" { + t.Errorf("reqs.String() = %q, want \"\"Mike\"\"", s); + } +} + +func TestMapCounter(t *testing.T) { + colours := NewMap("bike-shed-colours"); + + colours.Add("red", 1); + colours.Add("red", 2); + colours.Add("blue", 4); + if x := colours.m["red"].(*Int).i; x != 3 { + t.Errorf("colours.m[\"red\"] = %v, want 3", x) + } + if x := colours.m["blue"].(*Int).i; x != 4 { + t.Errorf("colours.m[\"blue\"] = %v, want 4", x) + } + + // colours.String() should be '{"red":3, "blue":4}', + // though the order of red and blue could vary. + s := colours.String(); + j, ok, errtok := json.StringToJson(s); + if !ok { + t.Errorf("colours.String() isn't valid JSON: %v", errtok) + } + if j.Kind() != json.MapKind { + t.Error("colours.String() didn't produce a map.") + } + red := j.Get("red"); + if red.Kind() != json.NumberKind { + t.Error("red.Kind() is not a NumberKind.") + } + if x := red.Number(); x != 3 { + t.Error("red = %v, want 3", x) + } +} + +func TestIntFunc(t *testing.T) { + x := int(4); + ix := IntFunc(func() int64 { return int64(x) }); + if s := ix.String(); s != "4" { + t.Errorf("ix.String() = %v, want 4", s); + } + + x++; + if s := ix.String(); s != "5" { + t.Errorf("ix.String() = %v, want 5", s); + } +} diff --git a/src/pkg/flag/Makefile b/src/pkg/flag/Makefile new file mode 100644 index 000000000..466e19564 --- /dev/null +++ b/src/pkg/flag/Makefile @@ -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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D= + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + flag.$O\ + + +phases: a1 +_obj$D/flag.a: phases + +a1: $(O1) + $(AR) grc _obj$D/flag.a flag.$O + rm -f $(O1) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/flag.a + +$(O1): newpkg +$(O2): a1 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/flag.a + +packages: _obj$D/flag.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/flag.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/flag.a diff --git a/src/pkg/flag/flag.go b/src/pkg/flag/flag.go new file mode 100644 index 000000000..63d649a9b --- /dev/null +++ b/src/pkg/flag/flag.go @@ -0,0 +1,486 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* + The flag package implements command-line flag parsing. + + Usage: + + 1) Define flags using flag.String(), Bool(), Int(), etc. Example: + import flag "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") + } + + 2) After all flags are defined, call + flag.Parse() + to parse the command line into the defined flags. + + 3) Flags may then be used directly. If you're using the flags themselves, + they are all pointers; if you bind to variables, they're values. + print("ip has value ", *ip, "\n"); + print("flagvar has value ", flagvar, "\n"); + + 4) After parsing, flag.Arg(i) is the i'th argument after the flags. + Args are indexed from 0 up to flag.NArg(). + + Command line flag syntax: + -flag + -flag=x + -flag x + One or two minus signs may be used; they are equivalent. + + 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. + */ +package flag + +import ( + "fmt"; + "os"; + "strconv" +) + +// BUG: atob belongs elsewhere +func atob(str string) (value bool, ok bool) { + switch str { + case "1", "t", "T", "true", "TRUE", "True": + return true, true; + case "0", "f", "F", "false", "FALSE", "False": + return false, true + } + return false, false +} + +type ( + boolValue struct; + intValue struct; + int64Value struct; + uintValue struct; + uint64Value struct; + stringValue struct; +) + +// -- Bool Value +type boolValue struct { + p *bool; +} + +func newBoolValue(val bool, p *bool) *boolValue { + *p = val; + return &boolValue{p} +} + +func (b *boolValue) set(s string) bool { + v, ok := atob(s); + *b.p = v; + return ok +} + +func (b *boolValue) String() string { + return fmt.Sprintf("%v", *b.p) +} + +// -- Int Value +type intValue struct { + p *int; +} + +func newIntValue(val int, p *int) *intValue { + *p = val; + return &intValue{p} +} + +func (i *intValue) set(s string) bool { + v, err := strconv.Atoi(s); + *i.p = int(v); + return err == nil +} + +func (i *intValue) String() string { + return fmt.Sprintf("%v", *i.p) +} + +// -- Int64 Value +type int64Value struct { + p *int64; +} + +func newInt64Value(val int64, p *int64) *int64Value { + *p = val; + return &int64Value{p} +} + +func (i *int64Value) set(s string) bool { + v, err := strconv.Atoi64(s); + *i.p = v; + return err == nil; +} + +func (i *int64Value) String() string { + return fmt.Sprintf("%v", *i.p) +} + +// -- Uint Value +type uintValue struct { + p *uint; +} + +func newUintValue(val uint, p *uint) *uintValue { + *p = val; + return &uintValue{p} +} + +func (i *uintValue) set(s string) bool { + v, err := strconv.Atoui(s); + *i.p = uint(v); + return err == nil; +} + +func (i *uintValue) String() string { + return fmt.Sprintf("%v", *i.p) +} + +// -- uint64 Value +type uint64Value struct { + p *uint64; +} + +func newUint64Value(val uint64, p *uint64) *uint64Value { + *p = val; + return &uint64Value{p} +} + +func (i *uint64Value) set(s string) bool { + v, err := strconv.Atoui64(s); + *i.p = uint64(v); + return err == nil; +} + +func (i *uint64Value) String() string { + return fmt.Sprintf("%v", *i.p) +} + +// -- string Value +type stringValue struct { + p *string; +} + +func newStringValue(val string, p *string) *stringValue { + *p = val; + return &stringValue{p} +} + +func (s *stringValue) set(val string) bool { + *s.p = val; + return true; +} + +func (s *stringValue) String() string { + return fmt.Sprintf("%s", *s.p) +} + +// FlagValue is the interface to the dynamic value stored in a flag. +// (The default value is represented as a string.) +type FlagValue interface { + String() string; + set(string) bool; +} + +// A Flag represents the state of a flag. +type Flag struct { + Name string; // name as it appears on command line + Usage string; // help message + Value FlagValue; // value as set + DefValue string; // default value (as text); for usage message +} + +type allFlags struct { + actual map[string] *Flag; + formal map[string] *Flag; + first_arg int; // 0 is the program name, 1 is first arg +} + +var flags *allFlags = &allFlags{make(map[string] *Flag), make(map[string] *Flag), 1} + +// VisitAll visits the flags, calling fn for each. It visits all flags, even those not set. +func VisitAll(fn func(*Flag)) { + for k, f := range flags.formal { + fn(f) + } +} + +// Visit visits the flags, calling fn for each. It visits only those flags that have been set. +func Visit(fn func(*Flag)) { + for k, f := range flags.actual { + fn(f) + } +} + +// Lookup returns the Flag structure of the named flag, returning nil if none exists. +func Lookup(name string) *Flag { + f, ok := flags.formal[name]; + if !ok { + return nil + } + return f +} + +// Set sets the value of tne named flag. It returns true if the set succeeded; false if +// there is no such flag defined. +func Set(name, value string) bool { + f, ok := flags.formal[name]; + if !ok { + return false + } + ok = f.Value.set(value); + if !ok { + return false + } + flags.actual[name] = f; + return true; +} + +// PrintDefaults prints to standard error the default values of all defined flags. +func PrintDefaults() { + VisitAll(func(f *Flag) { + format := " -%s=%s: %s\n"; + if s, ok := f.Value.(*stringValue); ok { + // put quotes on the value + format = " -%s=%q: %s\n"; + } + fmt.Fprintf(os.Stderr, format, f.Name, f.DefValue, f.Usage); + }) +} + +// Usage prints to standard error a default usage message documenting all defined flags and +// then calls os.Exit(1). +func Usage() { + if len(os.Args) > 0 { + fmt.Fprintln(os.Stderr, "Usage of", os.Args[0] + ":"); + } else { + fmt.Fprintln(os.Stderr, "Usage:"); + } + PrintDefaults(); + os.Exit(1); +} + +func NFlag() int { + return len(flags.actual) +} + +// Arg returns the i'th command-line argument. Arg(0) is the first remaining argument +// after flags have been processed. +func Arg(i int) string { + i += flags.first_arg; + if i < 0 || i >= len(os.Args) { + return ""; + } + return os.Args[i] +} + +// NArg is the number of arguments remaining after flags have been processed. +func NArg() int { + return len(os.Args) - flags.first_arg +} + +// Args returns the non-flag command-line arguments. +func Args() []string { + return os.Args[flags.first_arg:len(os.Args)]; +} + +func add(name string, value FlagValue, usage string) { + // Remember the default value as a string; it won't change. + f := &Flag{name, usage, value, value.String()}; + dummy, alreadythere := flags.formal[name]; + if alreadythere { + print("flag redefined: ", name, "\n"); + panic("flag redefinition"); // Happens only if flags are declared with identical names + } + flags.formal[name] = f; +} + +// 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) { + add(name, newBoolValue(value, p), usage); +} + +// Bool defines a bool flag with specified name, default value, and usage string. +// The return value is the address of a bool variable that stores the value of the flag. +func Bool(name string, value bool, usage string) *bool { + p := new(bool); + BoolVar(p, name, value, usage); + return p; +} + +// IntVar defines an int flag with specified name, default value, and usage string. +// The argument p points to an int variable in which to store the value of the flag. +func IntVar(p *int, name string, value int, usage string) { + add(name, newIntValue(value, p), usage); +} + +// Int defines an int flag with specified name, default value, and usage string. +// The return value is the address of an int variable that stores the value of the flag. +func Int(name string, value int, usage string) *int { + p := new(int); + IntVar(p, name, value, usage); + return p; +} + +// Int64Var defines an int64 flag with specified name, default value, and usage string. +// The argument p points to an int64 variable in which to store the value of the flag. +func Int64Var(p *int64, name string, value int64, usage string) { + add(name, newInt64Value(value, p), usage); +} + +// Int64 defines an int64 flag with specified name, default value, and usage string. +// The return value is the address of an int64 variable that stores the value of the flag. +func Int64(name string, value int64, usage string) *int64 { + p := new(int64); + Int64Var(p, name, value, usage); + return p; +} + +// UintVar defines a uint flag with specified name, default value, and usage string. +// The argument p points to a uint variable in which to store the value of the flag. +func UintVar(p *uint, name string, value uint, usage string) { + add(name, newUintValue(value, p), usage); +} + +// Uint defines a uint flag with specified name, default value, and usage string. +// The return value is the address of a uint variable that stores the value of the flag. +func Uint(name string, value uint, usage string) *uint { + p := new(uint); + UintVar(p, name, value, usage); + return p; +} + +// Uint64Var defines a uint64 flag with specified name, default value, and usage string. +// The argument p points to a uint64 variable in which to store the value of the flag. +func Uint64Var(p *uint64, name string, value uint64, usage string) { + add(name, newUint64Value(value, p), usage); +} + +// Uint64 defines a uint64 flag with specified name, default value, and usage string. +// The return value is the address of a uint64 variable that stores the value of the flag. +func Uint64(name string, value uint64, usage string) *uint64 { + p := new(uint64); + Uint64Var(p, name, value, usage); + return p; +} + +// StringVar defines a string flag with specified name, default value, and usage string. +// The argument p points to a string variable in which to store the value of the flag. +func StringVar(p *string, name, value string, usage string) { + add(name, newStringValue(value, p), usage); +} + +// String defines a string flag with specified name, default value, and usage string. +// The return value is the address of a string variable that stores the value of the flag. +func String(name, value string, usage string) *string { + p := new(string); + StringVar(p, name, value, usage); + return p; +} + +func (f *allFlags) parseOne(index int) (ok bool, next int) +{ + s := os.Args[index]; + f.first_arg = index; // until proven otherwise + if len(s) == 0 { + return false, -1 + } + if s[0] != '-' { + return false, -1 + } + num_minuses := 1; + if len(s) == 1 { + return false, index + } + if s[1] == '-' { + num_minuses++; + if len(s) == 2 { // "--" terminates the flags + return false, index + 1 + } + } + name := s[num_minuses : len(s)]; + if len(name) == 0 || name[0] == '-' || name[0] == '=' { + print("bad flag syntax: ", s, "\n"); + Usage(); + } + + // it's a flag. does it have an argument? + has_value := false; + value := ""; + for i := 1; i < len(name); i++ { // equals cannot be first + if name[i] == '=' { + value = name[i+1 : len(name)]; + has_value = true; + name = name[0 : i]; + break; + } + } + flag, alreadythere := flags.actual[name]; + if alreadythere { + print("flag specified twice: -", name, "\n"); + Usage(); + } + m := flags.formal; + flag, alreadythere = m[name]; // BUG + if !alreadythere { + print("flag provided but not defined: -", name, "\n"); + Usage(); + } + if f, ok := flag.Value.(*boolValue); ok { // special case: doesn't need an arg + if has_value { + if !f.set(value) { + print("invalid boolean value ", value, " for flag: -", name, "\n"); + Usage(); + } + } else { + f.set("true") + } + } else { + // It must have a value, which might be the next argument. + if !has_value && index < len(os.Args)-1 { + // value is the next arg + has_value = true; + index++; + value = os.Args[index]; + } + if !has_value { + print("flag needs an argument: -", name, "\n"); + Usage(); + } + ok = flag.Value.set(value); + if !ok { + print("invalid value ", value, " for flag: -", name, "\n"); + Usage(); + } + } + flags.actual[name] = flag; + return true, index + 1 +} + +// Parse parses the command-line flags. Must be called after all flags are defined +// and before any are accessed by the program. +func Parse() { + for i := 1; i < len(os.Args); { + ok, next := flags.parseOne(i); + if next > 0 { + flags.first_arg = next; + i = next; + } + if !ok { + break + } + } +} diff --git a/src/pkg/flag/flag_test.go b/src/pkg/flag/flag_test.go new file mode 100644 index 000000000..0d83fcf81 --- /dev/null +++ b/src/pkg/flag/flag_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 flag + +import ( + "flag"; + "fmt"; + "testing"; +) + +var ( + test_bool = flag.Bool("test_bool", false, "bool value"); + test_int = flag.Int("test_int", 0, "int value"); + test_int64 = flag.Int64("test_int64", 0, "int64 value"); + test_uint = flag.Uint("test_uint", 0, "uint value"); + test_uint64 = flag.Uint64("test_uint64", 0, "uint64 value"); + test_string = flag.String("test_string", "0", "string value"); +) + +func boolString(s string) string { + if s == "0" { + return "false" + } + return "true" +} + +func TestEverything(t *testing.T) { + m := make(map[string] *flag.Flag); + desired := "0"; + visitor := func(f *flag.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("flag.Visit: bad value", f.Value.String(), "for", f.Name); + } + } + }; + flag.VisitAll(visitor); + if len(m) != 6 { + t.Error("flag.VisitAll misses some flags"); + for k, v := range m { + t.Log(k, *v) + } + } + m = make(map[string] *flag.Flag); + flag.Visit(visitor); + if len(m) != 0 { + t.Errorf("flag.Visit sees unset flags"); + for k, v := range m { + t.Log(k, *v) + } + } + // Now set all flags + flag.Set("test_bool", "true"); + flag.Set("test_int", "1"); + flag.Set("test_int64", "1"); + flag.Set("test_uint", "1"); + flag.Set("test_uint64", "1"); + flag.Set("test_string", "1"); + desired = "1"; + flag.Visit(visitor); + if len(m) != 6 { + t.Error("flag.Visit fails after set"); + for k, v := range m { + t.Log(k, *v) + } + } +} diff --git a/src/pkg/fmt/Makefile b/src/pkg/fmt/Makefile new file mode 100644 index 000000000..5d0281a0c --- /dev/null +++ b/src/pkg/fmt/Makefile @@ -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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D= + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + format.$O\ + +O2=\ + print.$O\ + + +phases: a1 a2 +_obj$D/fmt.a: phases + +a1: $(O1) + $(AR) grc _obj$D/fmt.a format.$O + rm -f $(O1) + +a2: $(O2) + $(AR) grc _obj$D/fmt.a print.$O + rm -f $(O2) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/fmt.a + +$(O1): newpkg +$(O2): a1 +$(O3): a2 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/fmt.a + +packages: _obj$D/fmt.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/fmt.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/fmt.a diff --git a/src/pkg/fmt/fmt_test.go b/src/pkg/fmt/fmt_test.go new file mode 100644 index 000000000..e8abc2f0d --- /dev/null +++ b/src/pkg/fmt/fmt_test.go @@ -0,0 +1,247 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package fmt + +import ( + "fmt"; + "io"; + "math"; + "testing"; +) + +func TestFmtInterface(t *testing.T) { + var i1 interface{}; + i1 = "abc"; + s := fmt.Sprintf("%s", i1); + if s != "abc" { + t.Errorf(`fmt.Sprintf("%%s", empty("abc")) = %q want %q`, s, "abc"); + } +} + +type fmtTest struct { + fmt string; + val interface { }; + out string; +} + +const b32 uint32 = 1<<32 - 1 +const b64 uint64 = 1<<64 - 1 +var array = []int{1, 2, 3, 4, 5} +var iarray = []interface{}{1, "hello", 2.5, nil} + +var fmttests = []fmtTest{ + // basic string + fmtTest{ "%s", "abc", "abc" }, + fmtTest{ "%x", "abc", "616263" }, + fmtTest{ "%x", "xyz", "78797a" }, + fmtTest{ "%X", "xyz", "78797A" }, + fmtTest{ "%q", "abc", `"abc"` }, + + // basic bytes + fmtTest{ "%s", io.StringBytes("abc"), "abc" }, + fmtTest{ "%x", io.StringBytes("abc"), "616263" }, + fmtTest{ "% x", io.StringBytes("abc"), "61 62 63" }, + fmtTest{ "%x", io.StringBytes("xyz"), "78797a" }, + fmtTest{ "%X", io.StringBytes("xyz"), "78797A" }, + fmtTest{ "%q", io.StringBytes("abc"), `"abc"` }, + + // escaped strings + fmtTest{ "%#q", `abc`, "`abc`" }, + fmtTest{ "%#q", `"`, "`\"`" }, + fmtTest{ "1 %#q", `\n`, "1 `\\n`" }, + fmtTest{ "2 %#q", "\n", `2 "\n"` }, + fmtTest{ "%q", `"`, `"\""` }, + fmtTest{ "%q", "\a\b\f\r\n\t\v", `"\a\b\f\r\n\t\v"` }, + fmtTest{ "%q", "abc\xffdef", `"abc\xffdef"` }, + fmtTest{ "%q", "\u263a", `"\u263a"` }, + fmtTest{ "%q", "\U0010ffff", `"\U0010ffff"` }, + + // width + fmtTest{ "%5s", "abc", " abc" }, + fmtTest{ "%-5s", "abc", "abc " }, + fmtTest{ "%05s", "abc", "00abc" }, + + // integers + fmtTest{ "%d", 12345, "12345" }, + fmtTest{ "%d", -12345, "-12345" }, + fmtTest{ "%10d", 12345, " 12345" }, + fmtTest{ "%10d", -12345, " -12345" }, + fmtTest{ "%+10d", 12345, " +12345" }, + fmtTest{ "%010d", 12345, "0000012345" }, + fmtTest{ "%010d", -12345, "-000012345" }, + fmtTest{ "%-10d", 12345, "12345 " }, + fmtTest{ "%010.3d", 1, " 001" }, + fmtTest{ "%010.3d", -1, " -001" }, + fmtTest{ "%+d", 12345, "+12345" }, + fmtTest{ "%+d", -12345, "-12345" }, + fmtTest{ "% d", 12345, " 12345" }, + + // arrays + fmtTest{ "%v", array, "[1 2 3 4 5]" }, + fmtTest{ "%v", iarray, "[1 hello 2.5 ]" }, + fmtTest{ "%v", &array, "&[1 2 3 4 5]" }, + fmtTest{ "%v", &iarray, "&[1 hello 2.5 ]" }, + + // old test/fmt_test.go + fmtTest{ "%d", 1234, "1234" }, + fmtTest{ "%d", -1234, "-1234" }, + fmtTest{ "%d", uint(1234), "1234" }, + fmtTest{ "%d", uint32(b32), "4294967295" }, + fmtTest{ "%d", uint64(b64), "18446744073709551615" }, + fmtTest{ "%o", 01234, "1234" }, + fmtTest{ "%#o", 01234, "01234" }, + fmtTest{ "%o", uint32(b32), "37777777777" }, + fmtTest{ "%o", uint64(b64), "1777777777777777777777" }, + fmtTest{ "%x", 0x1234abcd, "1234abcd" }, + fmtTest{ "%#x", 0x1234abcd, "0x1234abcd" }, + fmtTest{ "%x", b32-0x1234567, "fedcba98" }, + fmtTest{ "%X", 0x1234abcd, "1234ABCD" }, + fmtTest{ "%X", b32-0x1234567, "FEDCBA98" }, + fmtTest{ "%#X", 0, "0X0" }, + fmtTest{ "%x", b64, "ffffffffffffffff" }, + fmtTest{ "%b", 7, "111" }, + fmtTest{ "%b", b64, "1111111111111111111111111111111111111111111111111111111111111111" }, + fmtTest{ "%e", float64(1), "1.000000e+00" }, + fmtTest{ "%e", float64(1234.5678e3), "1.234568e+06" }, + fmtTest{ "%e", float64(1234.5678e-8), "1.234568e-05" }, + fmtTest{ "%e", float64(-7), "-7.000000e+00" }, + fmtTest{ "%e", float64(-1e-9), "-1.000000e-09" }, + fmtTest{ "%f", float64(1234.5678e3), "1234567.800000" }, + fmtTest{ "%f", float64(1234.5678e-8), "0.000012" }, + fmtTest{ "%f", float64(-7), "-7.000000" }, + fmtTest{ "%f", float64(-1e-9), "-0.000000" }, + fmtTest{ "%g", float64(1234.5678e3), "1.2345678e+06" }, + fmtTest{ "%g", float32(1234.5678e3), "1.2345678e+06" }, + fmtTest{ "%g", float64(1234.5678e-8), "1.2345678e-05" }, + fmtTest{ "%g", float64(-7), "-7" }, + fmtTest{ "%g", float64(-1e-9), "-1e-09", }, + fmtTest{ "%g", float32(-1e-9), "-1e-09" }, + fmtTest{ "%c", 'x', "x" }, + fmtTest{ "%c", 0xe4, "ä" }, + fmtTest{ "%c", 0x672c, "本" }, + fmtTest{ "%c", '日', "日" }, + fmtTest{ "%20.8d", 1234, " 00001234" }, + fmtTest{ "%20.8d", -1234, " -00001234" }, + fmtTest{ "%20d", 1234, " 1234" }, + fmtTest{ "%-20.8d", 1234, "00001234 " }, + fmtTest{ "%-20.8d", -1234, "-00001234 " }, + fmtTest{ "%-#20.8x", 0x1234abc, "0x01234abc " }, + fmtTest{ "%-#20.8X", 0x1234abc, "0X01234ABC " }, + fmtTest{ "%-#20.8o", 01234, "00001234 " }, + fmtTest{ "%.20b", 7, "00000000000000000111" }, + fmtTest{ "%20.5s", "qwertyuiop", " qwert" }, + fmtTest{ "%.5s", "qwertyuiop", "qwert" }, + fmtTest{ "%-20.5s", "qwertyuiop", "qwert " }, + fmtTest{ "%20c", 'x', " x" }, + fmtTest{ "%-20c", 'x', "x " }, + fmtTest{ "%20.6e", 1.2345e3, " 1.234500e+03" }, + fmtTest{ "%20.6e", 1.2345e-3, " 1.234500e-03" }, + fmtTest{ "%20e", 1.2345e3, " 1.234500e+03" }, + fmtTest{ "%20e", 1.2345e-3, " 1.234500e-03" }, + fmtTest{ "%20.8e", 1.2345e3, " 1.23450000e+03" }, + fmtTest{ "%20f", float64(1.23456789e3), " 1234.567890" }, + fmtTest{ "%20f", float64(1.23456789e-3), " 0.001235" }, + fmtTest{ "%20f", float64(12345678901.23456789), " 12345678901.234568" }, + fmtTest{ "%-20f", float64(1.23456789e3), "1234.567890 " }, + fmtTest{ "%20.8f", float64(1.23456789e3), " 1234.56789000" }, + fmtTest{ "%20.8f", float64(1.23456789e-3), " 0.00123457" }, + fmtTest{ "%g", float64(1.23456789e3), "1234.56789" }, + fmtTest{ "%g", float64(1.23456789e-3), "0.00123456789" }, + fmtTest{ "%g", float64(1.23456789e20), "1.23456789e+20" }, + fmtTest{ "%20e", math.Inf(1), " +Inf" }, + fmtTest{ "%-20f", math.Inf(-1), "-Inf " }, + fmtTest{ "%20g", math.NaN(), " NaN" }, +} + +func TestSprintf(t *testing.T) { + for i := 0; i < len(fmttests); i++ { + tt := fmttests[i]; + s := fmt.Sprintf(tt.fmt, tt.val); + if s != tt.out { + if ss, ok := tt.val.(string); ok { + // Don't requote the already-quoted strings. + // It's too confusing to read the errors. + t.Errorf("fmt.Sprintf(%q, %q) = %s want %s", tt.fmt, tt.val, s, tt.out); + } else { + t.Errorf("fmt.Sprintf(%q, %v) = %q want %q", tt.fmt, tt.val, s, tt.out); + } + } + } +} + +type flagPrinter struct { } +func (*flagPrinter) Format(f fmt.Formatter, c int) { + s := "%"; + for i := 0; i < 128; i++ { + if f.Flag(i) { + s += string(i); + } + } + if w, ok := f.Width(); ok { + s += fmt.Sprintf("%d", w); + } + if p, ok := f.Precision(); ok { + s += fmt.Sprintf(".%d", p); + } + s += string(c); + io.WriteString(f, "["+s+"]"); +} + +type flagTest struct { + in string; + out string; +} + +var flagtests = []flagTest { + flagTest{ "%a", "[%a]" }, + flagTest{ "%-a", "[%-a]" }, + flagTest{ "%+a", "[%+a]" }, + flagTest{ "%#a", "[%#a]" }, + flagTest{ "% a", "[% a]" }, + flagTest{ "%0a", "[%0a]" }, + flagTest{ "%1.2a", "[%1.2a]" }, + flagTest{ "%-1.2a", "[%-1.2a]" }, + flagTest{ "%+1.2a", "[%+1.2a]" }, + flagTest{ "%-+1.2a", "[%+-1.2a]" }, + flagTest{ "%-+1.2abc", "[%+-1.2a]bc" }, + flagTest{ "%-1.2abc", "[%-1.2a]bc" }, +} + +func TestFlagParser(t *testing.T) { + var flagprinter flagPrinter; + for i := 0; i < len(flagtests); i++ { + tt := flagtests[i]; + s := fmt.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; + type Test struct { + fmt string; + out string; + } + var tests = []Test { + Test{ "%v", "{abc def 123}" }, + Test{ "%+v", "{a=abc b=def c=123}" }, + }; + for i := 0; i < len(tests); i++ { + tt := tests[i]; + out := fmt.Sprintf(tt.fmt, s); + if out != tt.out { + t.Errorf("Sprintf(%q, &s) = %q, want %q", tt.fmt, out, tt.out); + } + } +} diff --git a/src/pkg/fmt/format.go b/src/pkg/fmt/format.go new file mode 100644 index 000000000..3cd492980 --- /dev/null +++ b/src/pkg/fmt/format.go @@ -0,0 +1,533 @@ +// Copyright 2009 The Go Authors. 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 ( + "strconv"; +) + + +const nByte = 64; +const nPows10 = 160; + +var ldigits string = "0123456789abcdef" // var not const because we take its address +var udigits string = "0123456789ABCDEF" + +/* + Fmt is the raw formatter used by Printf etc. Not meant for normal use. + See print.go for a more palatable interface. + + The model is to accumulate operands into an internal buffer and then + retrieve the buffer in one hit using Str(), Putnl(), etc. The formatting + methods return ``self'' so the operations can be chained. + + f := fmt.New(); + print(f.Fmt_d(1234).Fmt_s("\n").Str()); // create string, print it + f.Fmt_d(-1234).Fmt_s("\n").Put(); // print string + f.Fmt_ud(1<<63).Putnl(); // print string with automatic newline +*/ +type Fmt struct { + buf string; + wid int; + wid_present bool; + prec int; + prec_present bool; + // flags + minus bool; + plus bool; + sharp bool; + space bool; + zero bool; +} + +func (f *Fmt) clearflags() { + f.wid = 0; + f.wid_present = false; + f.prec = 0; + f.prec_present = false; + f.minus = false; + f.plus = false; + f.sharp = false; + f.space = false; + f.zero = false; +} + +func (f *Fmt) clearbuf() { + f.buf = ""; +} + +func (f *Fmt) init() { + f.clearbuf(); + f.clearflags(); +} + +// New returns a new initialized Fmt +func New() *Fmt { + f := new(Fmt); + f.init(); + return f; +} + +// Str returns the buffered contents as a string and resets the Fmt. +func (f *Fmt) Str() string { + s := f.buf; + f.clearbuf(); + f.clearflags(); + f.buf = ""; + return s; +} + +// Put writes the buffered contents to stdout and resets the Fmt. +func (f *Fmt) Put() { + print(f.buf); + f.clearbuf(); + f.clearflags(); +} + +// Putnl writes the buffered contents to stdout, followed by a newline, and resets the Fmt. +func (f *Fmt) Putnl() { + print(f.buf, "\n"); + f.clearbuf(); + f.clearflags(); +} + +// Wp sets the width and precision for formatting the next item. +func (f *Fmt) Wp(w, p int) *Fmt { + f.wid_present = true; + f.wid = w; + f.prec_present = true; + f.prec = p; + return f; +} + +// P sets the precision for formatting the next item. +func (f *Fmt) P(p int) *Fmt { + f.prec_present = true; + f.prec = p; + return f; +} + +// W sets the width for formatting the next item. +func (f *Fmt) W(x int) *Fmt { + f.wid_present = true; + f.wid = x; + return f; +} + +// append s to buf, padded on left (w > 0) or right (w < 0 or f.minus) +// padding is in bytes, not characters (agrees with ANSIC C, not Plan 9 C) +func (f *Fmt) pad(s string) { + if f.wid_present && f.wid != 0 { + left := !f.minus; + w := f.wid; + if w < 0 { + left = false; + w = -w; + } + w -= len(s); + padchar := byte(' '); + if left && f.zero { + padchar = '0'; + } + if w > 0 { + if w > nByte { + w = nByte; + } + buf := make([]byte, w); + for i := 0; i < w; i++ { + buf[i] = padchar; + } + if left { + s = string(buf) + s; + } else { + s = s + string(buf); + } + } + } + f.buf += s; +} + +// format val into buf, ending at buf[i]. (printing is easier right-to-left; +// that's why the bidi languages are right-to-left except for numbers. wait, +// never mind.) val is known to be unsigned. we could make things maybe +// marginally faster by splitting the 32-bit case out into a separate function +// but it's not worth the duplication, so val has 64 bits. +func putint(buf *[nByte]byte, i int, base, val uint64, digits *string) int { + 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) *Fmt { + if v { + f.pad("true"); + } else { + f.pad("false"); + } + f.clearflags(); + return f; +} + +// integer; interprets prec but not wid. +func (f *Fmt) integer(a int64, base uint, is_signed bool, digits *string) string { + var buf [nByte]byte; + negative := is_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.prec_present { + prec = f.prec; + f.zero = false; + } else if f.zero && f.wid_present && !f.minus && f.wid > 0{ + prec = f.wid; + if negative || f.plus || f.space { + prec--; // leave room for sign + } + } + + i := putint(&buf, nByte-1, uint64(base), uint64(a), digits); + for i > 0 && prec > (nByte-1-i) { + buf[i] = '0'; + i--; + } + + if f.sharp { + switch base { + case 8: + if buf[i+1] != '0' { + buf[i] = '0'; + i--; + } + case 16: + buf[i] = 'x' + digits[10]-'a'; + i--; + buf[i] = '0'; + i--; + } + } + + if negative { + buf[i] = '-'; + i--; + } else if f.plus { + buf[i] = '+'; + i--; + } else if f.space { + buf[i] = ' '; + i--; + } + return string(buf[i+1:nByte]); +} + +// Fmt_d64 formats an int64 in decimal. +func (f *Fmt) Fmt_d64(v int64) *Fmt { + f.pad(f.integer(v, 10, true, &ldigits)); + f.clearflags(); + return f; +} + +// Fmt_d32 formats an int32 in decimal. +func (f *Fmt) Fmt_d32(v int32) *Fmt { + return f.Fmt_d64(int64(v)); +} + +// Fmt_d formats an int in decimal. +func (f *Fmt) Fmt_d(v int) *Fmt { + return f.Fmt_d64(int64(v)); +} + +// Fmt_ud64 formats a uint64 in decimal. +func (f *Fmt) Fmt_ud64(v uint64) *Fmt { + f.pad(f.integer(int64(v), 10, false, &ldigits)); + f.clearflags(); + return f; +} + +// Fmt_ud32 formats a uint32 in decimal. +func (f *Fmt) Fmt_ud32(v uint32) *Fmt { + return f.Fmt_ud64(uint64(v)); +} + +// Fmt_ud formats a uint in decimal. +func (f *Fmt) Fmt_ud(v uint) *Fmt { + return f.Fmt_ud64(uint64(v)); +} + +// Fmt_x64 formats an int64 in hexadecimal. +func (f *Fmt) Fmt_x64(v int64) *Fmt { + f.pad(f.integer(v, 16, true, &ldigits)); + f.clearflags(); + return f; +} + +// Fmt_x32 formats an int32 in hexadecimal. +func (f *Fmt) Fmt_x32(v int32) *Fmt { + return f.Fmt_x64(int64(v)); +} + +// Fmt_x formats an int in hexadecimal. +func (f *Fmt) Fmt_x(v int) *Fmt { + return f.Fmt_x64(int64(v)); +} + +// Fmt_ux64 formats a uint64 in hexadecimal. +func (f *Fmt) Fmt_ux64(v uint64) *Fmt { + f.pad(f.integer(int64(v), 16, false, &ldigits)); + f.clearflags(); + return f; +} + +// Fmt_ux32 formats a uint32 in hexadecimal. +func (f *Fmt) Fmt_ux32(v uint32) *Fmt { + return f.Fmt_ux64(uint64(v)); +} + +// Fmt_ux formats a uint in hexadecimal. +func (f *Fmt) Fmt_ux(v uint) *Fmt { + return f.Fmt_ux64(uint64(v)); +} + +// Fmt_X64 formats an int64 in upper case hexadecimal. +func (f *Fmt) Fmt_X64(v int64) *Fmt { + f.pad(f.integer(v, 16, true, &udigits)); + f.clearflags(); + return f; +} + +// Fmt_X32 formats an int32 in upper case hexadecimal. +func (f *Fmt) Fmt_X32(v int32) *Fmt { + return f.Fmt_X64(int64(v)); +} + +// Fmt_X formats an int in upper case hexadecimal. +func (f *Fmt) Fmt_X(v int) *Fmt { + return f.Fmt_X64(int64(v)); +} + +// Fmt_uX64 formats a uint64 in upper case hexadecimal. +func (f *Fmt) Fmt_uX64(v uint64) *Fmt { + f.pad(f.integer(int64(v), 16, false, &udigits)); + f.clearflags(); + return f; +} + +// Fmt_uX32 formats a uint32 in upper case hexadecimal. +func (f *Fmt) Fmt_uX32(v uint32) *Fmt { + return f.Fmt_uX64(uint64(v)); +} + +// Fmt_uX formats a uint in upper case hexadecimal. +func (f *Fmt) Fmt_uX(v uint) *Fmt { + return f.Fmt_uX64(uint64(v)); +} + +// Fmt_o64 formats an int64 in octal. +func (f *Fmt) Fmt_o64(v int64) *Fmt { + f.pad(f.integer(v, 8, true, &ldigits)); + f.clearflags(); + return f; +} + +// Fmt_o32 formats an int32 in octal. +func (f *Fmt) Fmt_o32(v int32) *Fmt { + return f.Fmt_o64(int64(v)); +} + +// Fmt_o formats an int in octal. +func (f *Fmt) Fmt_o(v int) *Fmt { + return f.Fmt_o64(int64(v)); +} + +// Fmt_uo64 formats a uint64 in octal. +func (f *Fmt) Fmt_uo64(v uint64) *Fmt { + f.pad(f.integer(int64(v), 8, false, &ldigits)); + f.clearflags(); + return f; +} + +// Fmt_uo32 formats a uint32 in octal. +func (f *Fmt) Fmt_uo32(v uint32) *Fmt { + return f.Fmt_uo64(uint64(v)); +} + +// Fmt_uo formats a uint in octal. +func (f *Fmt) Fmt_uo(v uint) *Fmt { + return f.Fmt_uo64(uint64(v)); +} + +// Fmt_b64 formats a uint64 in binary. +func (f *Fmt) Fmt_b64(v uint64) *Fmt { + f.pad(f.integer(int64(v), 2, false, &ldigits)); + f.clearflags(); + return f; +} + +// Fmt_b32 formats a uint32 in binary. +func (f *Fmt) Fmt_b32(v uint32) *Fmt { + return f.Fmt_b64(uint64(v)); +} + +// Fmt_b formats a uint in binary. +func (f *Fmt) Fmt_b(v uint) *Fmt { + return f.Fmt_b64(uint64(v)); +} + +// Fmt_c formats a Unicode character. +func (f *Fmt) Fmt_c(v int) *Fmt { + f.pad(string(v)); + f.clearflags(); + return f; +} + +// Fmt_s formats a string. +func (f *Fmt) Fmt_s(s string) *Fmt { + if f.prec_present { + if f.prec < len(s) { + s = s[0:f.prec]; + } + } + f.pad(s); + f.clearflags(); + return f; +} + +// Fmt_sx formats a string as a hexadecimal encoding of its bytes. +func (f *Fmt) Fmt_sx(s string) *Fmt { + 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.pad(t); + f.clearflags(); + return f; +} + +// Fmt_sX formats a string as an uppercase hexadecimal encoding of its bytes. +func (f *Fmt) Fmt_sX(s string) *Fmt { + t := ""; + for i := 0; i < len(s); i++ { + v := s[i]; + t += string(udigits[v>>4]); + t += string(udigits[v&0xF]); + } + f.pad(t); + f.clearflags(); + return f; +} + +// Fmt_q formats a string as a double-quoted, escaped Go string constant. +func (f *Fmt) Fmt_q(s string) *Fmt { + var quoted string; + if f.sharp && strconv.CanBackquote(s) { + quoted = "`"+s+"`"; + } else { + quoted = strconv.Quote(s); + } + f.pad(quoted); + f.clearflags(); + return f; +} + +// floating-point + +func doPrec(f *Fmt, def int) int { + if f.prec_present { + return f.prec; + } + return def; +} + +func fmtString(f *Fmt, s string) *Fmt { + f.pad(s); + f.clearflags(); + return f; +} + +// Fmt_e64 formats a float64 in the form -1.23e+12. +func (f *Fmt) Fmt_e64(v float64) *Fmt { + return fmtString(f, strconv.Ftoa64(v, 'e', doPrec(f, 6))); +} + +// Fmt_f64 formats a float64 in the form -1.23. +func (f *Fmt) Fmt_f64(v float64) *Fmt { + return fmtString(f, 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) *Fmt { + return fmtString(f, 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) *Fmt { + return fmtString(f, 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) *Fmt { + return fmtString(f, strconv.Ftoa32(v, 'e', doPrec(f, 6))); +} + +// Fmt_f32 formats a float32 in the form -1.23. +func (f *Fmt) Fmt_f32(v float32) *Fmt { + return fmtString(f, 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) *Fmt { + return fmtString(f, 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) *Fmt { + return fmtString(f, strconv.Ftoa32(v, 'b', 0)); +} + +// float +func (x *Fmt) f(a float) *Fmt { + if strconv.FloatSize == 32 { + return x.Fmt_f32(float32(a)) + } + return x.Fmt_f64(float64(a)) +} + +func (x *Fmt) e(a float) *Fmt { + if strconv.FloatSize == 32 { + return x.Fmt_e32(float32(a)) + } + return x.Fmt_e64(float64(a)) +} + +func (x *Fmt) g(a float) *Fmt { + if strconv.FloatSize == 32 { + return x.Fmt_g32(float32(a)) + } + return x.Fmt_g64(float64(a)) +} + +func (x *Fmt) fb(a float) *Fmt { + if strconv.FloatSize == 32 { + return x.Fmt_fb32(float32(a)) + } + return x.Fmt_fb64(float64(a)) +} diff --git a/src/pkg/fmt/print.go b/src/pkg/fmt/print.go new file mode 100644 index 000000000..66174c74b --- /dev/null +++ b/src/pkg/fmt/print.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 fmt implements formatted I/O with functions analogous +// to C's printf. Because of reflection knowledge it does not need +// to be told about sizes and signedness (no %llud etc. - just %d). +// Still to do: document the formats properly. For now, like C but: +// - don't need l or u flags - type of integer tells that. +// - %v prints any value using its native format. +// - for each Printf-like fn, there is also a Print fn that takes no format +// and is equivalent to saying %v for every operand. +// - another variant Println inserts blanks and appends a newline. +// - if an operand implements method String() that method will +// be used for %v, %s, or Print etc. +// - if an operand implements interface Formatter, that interface can +// be used for fine control of formatting. +package fmt + + +import ( + "fmt"; + "io"; + "os"; + "reflect"; + "utf8"; +) + +// Formatter 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 Formatter 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; +} + +// Format is the interface implemented by objects with a custom formatter. +// The implementation of Format may call Sprintf or Fprintf(f) etc. +// to generate its output. +type Format interface { + Format(f Formatter, c int); +} + +// String represents any object being printed that has a String() method that +// returns a string, which defines the ``native'' format for that object. +// Any such object will be printed using that method if passed +// as operand to a %s or %v format or to an unformatted printer such as Print. +type Stringer interface { + String() string +} + +const runeSelf = utf8.RuneSelf +const allocSize = 32 + +type pp struct { + n int; + buf []byte; + fmt *Fmt; +} + +func newPrinter() *pp { + p := new(pp); + p.fmt = fmt.New(); + return p; +} + +func (p *pp) Width() (wid int, ok bool) { + return p.fmt.wid, p.fmt.wid_present +} + +func (p *pp) Precision() (prec int, ok bool) { + return p.fmt.prec, p.fmt.prec_present +} + +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) ensure(n int) { + if len(p.buf) < n { + newn := allocSize + len(p.buf); + if newn < n { + newn = n + allocSize + } + b := make([]byte, newn); + for i := 0; i < p.n; i++ { + b[i] = p.buf[i]; + } + p.buf = b; + } +} + +func (p *pp) addstr(s string) { + n := len(s); + p.ensure(p.n + n); + for i := 0; i < n; i++ { + p.buf[p.n] = s[i]; + p.n++; + } +} + +func (p *pp) addbytes(b []byte, start, end int) { + p.ensure(p.n + end-start); + for i := start; i < end; i++ { + p.buf[p.n] = b[i]; + p.n++; + } +} + +func (p *pp) add(c int) { + p.ensure(p.n + 1); + if c < runeSelf { + p.buf[p.n] = byte(c); + p.n++; + } else { + p.addstr(string(c)); + } +} + +// Implement Write so we can call fprintf on a P, for +// recursive use in custom verbs. +func (p *pp) Write(b []byte) (ret int, err os.Error) { + p.addbytes(b, 0, len(b)); + return len(b), nil; +} + +func (p *pp) doprintf(format string, v reflect.StructValue); +func (p *pp) doprint(v reflect.StructValue, addspace, addnewline bool); + +// These routines end in 'f' and take a format string. + +// Fprintf formats according to a format specifier and writes to w. +func Fprintf(w io.Writer, format string, a ...) (n int, error os.Error) { + v := reflect.NewValue(a).(reflect.StructValue); + p := newPrinter(); + p.doprintf(format, v); + n, error = w.Write(p.buf[0:p.n]); + return n, error; +} + +// Printf formats according to a format specifier and writes to standard output. +func Printf(format string, v ...) (n int, errno os.Error) { + n, errno = Fprintf(os.Stdout, format, v); + return n, errno; +} + +// Sprintf formats according to a format specifier and returns the resulting string. +func Sprintf(format string, a ...) string { + v := reflect.NewValue(a).(reflect.StructValue); + p := newPrinter(); + p.doprintf(format, v); + s := string(p.buf)[0 : p.n]; + return s; +} + +// 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. +func Fprint(w io.Writer, a ...) (n int, error os.Error) { + v := reflect.NewValue(a).(reflect.StructValue); + p := newPrinter(); + p.doprint(v, false, false); + n, error = w.Write(p.buf[0:p.n]); + return n, 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. +func Print(v ...) (n int, errno os.Error) { + n, errno = Fprint(os.Stdout, v); + 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 ...) string { + v := reflect.NewValue(a).(reflect.StructValue); + p := newPrinter(); + p.doprint(v, false, false); + s := string(p.buf)[0 : p.n]; + 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. +func Fprintln(w io.Writer, a ...) (n int, error os.Error) { + v := reflect.NewValue(a).(reflect.StructValue); + p := newPrinter(); + p.doprint(v, true, true); + n, error = w.Write(p.buf[0:p.n]); + return n, 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. +func Println(v ...) (n int, errno os.Error) { + n, errno = Fprintln(os.Stdout, v); + 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 ...) string { + v := reflect.NewValue(a).(reflect.StructValue); + p := newPrinter(); + p.doprint(v, true, true); + s := string(p.buf)[0 : p.n]; + 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 val.Kind() == reflect.InterfaceKind { + inter := val.(reflect.InterfaceValue).Get(); + return reflect.NewValue(inter); + } + return val; +} + +// Getters for the fields of the argument structure. + +func getBool(v reflect.Value) (val bool, ok bool) { + switch v.Kind() { + case reflect.BoolKind: + return v.(reflect.BoolValue).Get(), true; + } + return false, false +} + +func getInt(v reflect.Value) (val int64, signed, ok bool) { + switch v.Kind() { + case reflect.IntKind: + return int64(v.(reflect.IntValue).Get()), true, true; + case reflect.Int8Kind: + return int64(v.(reflect.Int8Value).Get()), true, true; + case reflect.Int16Kind: + return int64(v.(reflect.Int16Value).Get()), true, true; + case reflect.Int32Kind: + return int64(v.(reflect.Int32Value).Get()), true, true; + case reflect.Int64Kind: + return int64(v.(reflect.Int64Value).Get()), true, true; + case reflect.UintKind: + return int64(v.(reflect.UintValue).Get()), false, true; + case reflect.Uint8Kind: + return int64(v.(reflect.Uint8Value).Get()), false, true; + case reflect.Uint16Kind: + return int64(v.(reflect.Uint16Value).Get()), false, true; + case reflect.Uint32Kind: + return int64(v.(reflect.Uint32Value).Get()), false, true; + case reflect.Uint64Kind: + return int64(v.(reflect.Uint64Value).Get()), false, true; + case reflect.UintptrKind: + return int64(v.(reflect.UintptrValue).Get()), false, true; + } + return 0, false, false; +} + +func getString(v reflect.Value) (val string, ok bool) { + switch v.Kind() { + case reflect.StringKind: + return v.(reflect.StringValue).Get(), true; + case reflect.ArrayKind: + if val, ok := v.Interface().([]byte); ok { + return string(val), true; + } + } + return "", false; +} + +func getFloat32(v reflect.Value) (val float32, ok bool) { + switch v.Kind() { + case reflect.Float32Kind: + return float32(v.(reflect.Float32Value).Get()), true; + case reflect.FloatKind: + if v.Type().Size()*8 == 32 { + return float32(v.(reflect.FloatValue).Get()), true; + } + } + return 0.0, false; +} + +func getFloat64(v reflect.Value) (val float64, ok bool) { + switch v.Kind() { + case reflect.FloatKind: + if v.Type().Size()*8 == 64 { + return float64(v.(reflect.FloatValue).Get()), true; + } + case reflect.Float64Kind: + return float64(v.(reflect.Float64Value).Get()), true; + } + return 0.0, false; +} + +func getPtr(v reflect.Value) (val uintptr, ok bool) { + switch v.Kind() { + case reflect.PtrKind: + return uintptr(v.(reflect.PtrValue).Get()), true; + } + return 0, false; +} + +func getArrayPtr(v reflect.Value) (val reflect.ArrayValue, ok bool) { + if v.Kind() == reflect.PtrKind { + v = v.(reflect.PtrValue).Sub(); + if v.Kind() == reflect.ArrayKind { + return v.(reflect.ArrayValue), true; + } + } + return nil, false; +} + +func getArray(v reflect.Value) (val reflect.ArrayValue, ok bool) { + switch v.Kind() { + case reflect.ArrayKind: + return v.(reflect.ArrayValue), true; + } + return nil, false; +} + +// Convert ASCII to integer. n is 0 (and got is false) if no number present. + +func parsenum(s string, start, end int) (n int, got bool, newi int) { + if start >= end { + return 0, false, end + } + isnum := false; + num := 0; + for '0' <= s[start] && s[start] <= '9' { + num = num*10 + int(s[start] - '0'); + start++; + isnum = true; + } + return num, isnum, start; +} + +func (p *pp) printField(field reflect.Value) (was_string bool) { + inter := field.Interface(); + if inter != nil { + if stringer, ok := inter.(Stringer); ok { + p.addstr(stringer.String()); + return false; // this value is not a string + } + } + s := ""; + switch field.Kind() { + case reflect.BoolKind: + s = p.fmt.Fmt_boolean(field.(reflect.BoolValue).Get()).Str(); + case reflect.IntKind, reflect.Int8Kind, reflect.Int16Kind, reflect.Int32Kind, reflect.Int64Kind: + v, signed, ok := getInt(field); + s = p.fmt.Fmt_d64(v).Str(); + case reflect.UintKind, reflect.Uint8Kind, reflect.Uint16Kind, reflect.Uint32Kind, reflect.Uint64Kind: + v, signed, ok := getInt(field); + s = p.fmt.Fmt_ud64(uint64(v)).Str(); + case reflect.UintptrKind: + v, signed, ok := getInt(field); + p.fmt.sharp = !p.fmt.sharp; // turn 0x on by default + s = p.fmt.Fmt_ux64(uint64(v)).Str(); + case reflect.Float32Kind: + v, ok := getFloat32(field); + s = p.fmt.Fmt_g32(v).Str(); + case reflect.Float64Kind: + v, ok := getFloat64(field); + s = p.fmt.Fmt_g64(v).Str(); + case reflect.FloatKind: + if field.Type().Size()*8 == 32 { + v, ok := getFloat32(field); + s = p.fmt.Fmt_g32(v).Str(); + } else { + v, ok := getFloat64(field); + s = p.fmt.Fmt_g64(v).Str(); + } + case reflect.StringKind: + v, ok := getString(field); + s = p.fmt.Fmt_s(v).Str(); + was_string = true; + case reflect.PtrKind: + if v, ok := getPtr(field); v == 0 { + s = "" + } else { + // pointer to array? (TODO(r): holdover; delete?) + if a, ok := getArrayPtr(field); ok { + p.addstr("&["); + for i := 0; i < a.Len(); i++ { + if i > 0 { + p.addstr(" "); + } + p.printField(a.Elem(i)); + } + p.addstr("]"); + } else { + p.fmt.sharp = !p.fmt.sharp; // turn 0x on by default + s = p.fmt.Fmt_uX64(uint64(v)).Str(); + } + } + case reflect.ArrayKind: + if a, ok := getArray(field); ok { + p.addstr("["); + for i := 0; i < a.Len(); i++ { + if i > 0 { + p.addstr(" "); + } + p.printField(a.Elem(i)); + } + p.addstr("]"); + } + case reflect.StructKind: + p.add('{'); + v := field.(reflect.StructValue); + t := v.Type().(reflect.StructType); + donames := p.fmt.plus; + p.fmt.clearflags(); // clear flags for p.printField + for i := 0; i < v.Len(); i++ { + if i > 0 { + p.add(' ') + } + if donames { + if name, typ, tag, off := t.Field(i); name != "" { + p.addstr(name); + p.add('='); + } + } + p.printField(getField(v, i)); + } + p.add('}'); + case reflect.InterfaceKind: + value := field.(reflect.InterfaceValue).Value(); + if value == nil { + s = "" + } else { + return p.printField(value); + } + default: + s = "?" + field.Type().String() + "?"; + } + p.addstr(s); + return was_string; +} + +func (p *pp) doprintf(format string, v reflect.StructValue) { + p.ensure(len(format)); // a good starting size + end := len(format) - 1; + fieldnum := 0; // we process one field per non-trivial format + for i := 0; i <= end; { + c, w := utf8.DecodeRuneInString(format[i:len(format)]); + if c != '%' || i == end { + p.add(c); + i += w; + continue; + } + 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 20 (width)? + p.fmt.wid, p.fmt.wid_present, i = parsenum(format, i, end); + // do we have .20 (precision)? + if i < end && format[i] == '.' { + p.fmt.prec, p.fmt.prec_present, i = parsenum(format, i+1, end); + } + c, w = utf8.DecodeRuneInString(format[i:len(format)]); + i += w; + // percent is special - absorbs no operand + if c == '%' { + p.add('%'); // TODO: should we bother with width & prec? + continue; + } + if fieldnum >= v.Len() { // out of operands + p.add('%'); + p.add(c); + p.addstr("(missing)"); + continue; + } + field := getField(v, fieldnum); + fieldnum++; + inter := field.Interface(); + if inter != nil && c != 'T' { // don't want thing to describe itself if we're asking for its type + if formatter, ok := inter.(Format); ok { + formatter.Format(p, c); + continue; + } + } + s := ""; + switch c { + // bool + case 't': + if v, ok := getBool(field); ok { + if v { + s = "true"; + } else { + s = "false"; + } + } else { + goto badtype; + } + + // int + case 'b': + if v, signed, ok := getInt(field); ok { + s = p.fmt.Fmt_b64(uint64(v)).Str() // always unsigned + } else if v, ok := getFloat32(field); ok { + s = p.fmt.Fmt_fb32(v).Str() + } else if v, ok := getFloat64(field); ok { + s = p.fmt.Fmt_fb64(v).Str() + } else { + goto badtype + } + case 'c': + if v, signed, ok := getInt(field); ok { + s = p.fmt.Fmt_c(int(v)).Str() + } else { + goto badtype + } + case 'd': + if v, signed, ok := getInt(field); ok { + if signed { + s = p.fmt.Fmt_d64(v).Str() + } else { + s = p.fmt.Fmt_ud64(uint64(v)).Str() + } + } else { + goto badtype + } + case 'o': + if v, signed, ok := getInt(field); ok { + if signed { + s = p.fmt.Fmt_o64(v).Str() + } else { + s = p.fmt.Fmt_uo64(uint64(v)).Str() + } + } else { + goto badtype + } + case 'x': + if v, signed, ok := getInt(field); ok { + if signed { + s = p.fmt.Fmt_x64(v).Str() + } else { + s = p.fmt.Fmt_ux64(uint64(v)).Str() + } + } else if v, ok := getString(field); ok { + s = p.fmt.Fmt_sx(v).Str(); + } else { + goto badtype + } + case 'X': + if v, signed, ok := getInt(field); ok { + if signed { + s = p.fmt.Fmt_X64(v).Str() + } else { + s = p.fmt.Fmt_uX64(uint64(v)).Str() + } + } else if v, ok := getString(field); ok { + s = p.fmt.Fmt_sX(v).Str(); + } else { + goto badtype + } + + // float + case 'e': + if v, ok := getFloat32(field); ok { + s = p.fmt.Fmt_e32(v).Str() + } else if v, ok := getFloat64(field); ok { + s = p.fmt.Fmt_e64(v).Str() + } else { + goto badtype + } + case 'f': + if v, ok := getFloat32(field); ok { + s = p.fmt.Fmt_f32(v).Str() + } else if v, ok := getFloat64(field); ok { + s = p.fmt.Fmt_f64(v).Str() + } else { + goto badtype + } + case 'g': + if v, ok := getFloat32(field); ok { + s = p.fmt.Fmt_g32(v).Str() + } else if v, ok := getFloat64(field); ok { + s = p.fmt.Fmt_g64(v).Str() + } else { + goto badtype + } + + // string + case 's': + if inter != nil { + // if object implements String, use the result. + if stringer, ok := inter.(Stringer); ok { + s = p.fmt.Fmt_s(stringer.String()).Str(); + break; + } + } + if v, ok := getString(field); ok { + s = p.fmt.Fmt_s(v).Str() + } else { + goto badtype + } + case 'q': + if v, ok := getString(field); ok { + s = p.fmt.Fmt_q(v).Str() + } else { + goto badtype + } + + // pointer + case 'p': + if v, ok := getPtr(field); ok { + if v == 0 { + s = "" + } else { + s = "0x" + p.fmt.Fmt_uX64(uint64(v)).Str() + } + } else { + goto badtype + } + + // arbitrary value; do your best + case 'v': + p.printField(field); + + // the value's type + case 'T': + s = field.Type().String(); + + default: + badtype: + s = "%" + string(c) + "(" + field.Type().String() + ")%"; + } + p.addstr(s); + } + if fieldnum < v.Len() { + p.addstr("?(extra "); + for ; fieldnum < v.Len(); fieldnum++ { + p.addstr(getField(v, fieldnum).Type().String()); + if fieldnum + 1 < v.Len() { + p.addstr(", "); + } + } + p.addstr(")"); + } +} + +func (p *pp) doprint(v reflect.StructValue, addspace, addnewline bool) { + prev_string := false; + for fieldnum := 0; fieldnum < v.Len(); fieldnum++ { + // always add spaces if we're doing println + field := getField(v, fieldnum); + if fieldnum > 0 { + if addspace { + p.add(' ') + } else if field.Kind() != reflect.StringKind && !prev_string{ + // if not doing println, add spaces if neither side is a string + p.add(' ') + } + } + was_string := p.printField(field); + prev_string = was_string; + } + if addnewline { + p.add('\n') + } +} diff --git a/src/pkg/go/ast/Makefile b/src/pkg/go/ast/Makefile new file mode 100644 index 000000000..1fd22ae71 --- /dev/null +++ b/src/pkg/go/ast/Makefile @@ -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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D=/go/ + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + ast.$O\ + +O2=\ + format.$O\ + + +phases: a1 a2 +_obj$D/ast.a: phases + +a1: $(O1) + $(AR) grc _obj$D/ast.a ast.$O + rm -f $(O1) + +a2: $(O2) + $(AR) grc _obj$D/ast.a format.$O + rm -f $(O2) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/ast.a + +$(O1): newpkg +$(O2): a1 +$(O3): a2 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/ast.a + +packages: _obj$D/ast.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/ast.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/ast.a diff --git a/src/pkg/go/ast/ast.go b/src/pkg/go/ast/ast.go new file mode 100644 index 000000000..6cac8ea1a --- /dev/null +++ b/src/pkg/go/ast/ast.go @@ -0,0 +1,772 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// The AST package declares the types used to represent +// syntax trees for Go source files. +// +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. + +// TODO: For comment positioning only the byte position and not +// a complete token.Position field is needed. May be able to trim +// node sizes a bit. + + +type ( + ExprVisitor interface; + StmtVisitor interface; + DeclVisitor interface; +) + + +// All expression nodes implement the Expr interface. +type Expr interface { + // For a (dynamic) node type X, calling Visit with an expression + // visitor v invokes the node-specific DoX function of the visitor. + // + Visit(v ExprVisitor); + + // Pos returns the (beginning) position of the expression. + Pos() token.Position; +} + + +// All statement nodes implement the Stmt interface. +type Stmt interface { + // For a (dynamic) node type X, calling Visit with a statement + // visitor v invokes the node-specific DoX function of the visitor. + // + Visit(v StmtVisitor); + + // Pos returns the (beginning) position of the statement. + Pos() token.Position; +} + + +// All declaration nodes implement the Decl interface. +type Decl interface { + // For a (dynamic) node type X, calling Visit with a declaration + // visitor v invokes the node-specific DoX function of the visitor. + // + Visit(v DeclVisitor); + + // Pos returns the (beginning) position of the declaration. + Pos() token.Position; +} + + +// ---------------------------------------------------------------------------- +// Comments + +// A Comment node represents a single //-style or /*-style comment. +type Comment struct { + token.Position; // beginning position of the comment + Text []byte; // the comment text (without '\n' for //-style comments) + EndLine int; // the line where the comment ends +} + + +// A Comments node represents a sequence of single comments +// with no other tokens and no empty lines between. +// +type Comments []*Comment + + +// ---------------------------------------------------------------------------- +// Expressions and types + +// Support types. +type ( + Ident struct; + StringLit struct; + FuncType struct; + BlockStmt struct; + + // A Field represents a Field declaration list in a struct type, + // a method in an interface type, or a parameter/result declaration + // in a signature. + Field struct { + Doc Comments; // associated documentation; or nil + Names []*Ident; // field/method/parameter names; nil if anonymous field + Type Expr; // field/method/parameter type + Tag []*StringLit; // field tag; nil if no tag + }; +) + + +// 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 { + token.Position; // beginning position of bad expression + }; + + // An Ident node represents an identifier. + Ident struct { + token.Position; // identifier position + Value string; // identifier string (e.g. foobar) + }; + + // An Ellipsis node stands for the "..." type in a + // parameter list or the "..." length in an array type. + // + Ellipsis struct { + token.Position; // position of "..." + }; + + // An IntLit node represents an integer literal. + IntLit struct { + token.Position; // int literal position + Value []byte; // literal string; e.g. 42 or 0x7f + }; + + // A FloatLit node represents a floating-point literal. + FloatLit struct { + token.Position; // float literal position + Value []byte; // literal string; e.g. 3.14 or 1e-9 + }; + + // A CharLit node represents a character literal. + CharLit struct { + token.Position; // char literal position + Value []byte; // literal string, including quotes; e.g. 'a' or '\x7f' + }; + + // A StringLit node represents a string literal. + StringLit struct { + token.Position; // string literal position + Value []byte; // literal string, including quotes; e.g. "foo" or `\m\n\o` + }; + + // A StringList node represents a sequence of adjacent string literals. + // A single string literal (common case) is represented by a StringLit + // node; StringList nodes are used only if there are two or more string + // literals in a sequence. + // + StringList struct { + Strings []*StringLit; // list of strings, len(Strings) > 1 + }; + + // 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 + Lbrace token.Position; // position of "{" + Elts []Expr; // list of composite elements + Rbrace token.Position; // position of "}" + }; + + // A ParenExpr node represents a parenthesized expression. + ParenExpr struct { + token.Position; // position of "(" + X Expr; // parenthesized expression + Rparen token.Position; // 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 or slice. + IndexExpr struct { + X Expr; // expression + Index Expr; // index expression or beginning of slice range + End Expr; // end of slice range; or nil + }; + + // A TypeAssertExpr node represents an expression followed by a + // type assertion. + // + TypeAssertExpr struct { + X Expr; // expression + Type Expr; // asserted type + }; + + // A CallExpr node represents an expression followed by an argument list. + CallExpr struct { + Fun Expr; // function expression + Lparen token.Position; // position of "(" + Args []Expr; // function arguments + Rparen token.Position; // positions of ")" + }; + + // A StarExpr node represents an expression of the form "*" Expression. + // Semantically it could be a unary "*" expression, or a pointer type. + StarExpr struct { + token.Position; // position of "*" + X Expr; // operand + }; + + // A UnaryExpr node represents a unary expression. + // Unary "*" expressions are represented via StarExpr nodes. + // + UnaryExpr struct { + token.Position; // position of Op + Op token.Token; // operator + X Expr; // operand + }; + + // A BinaryExpr node represents a binary expression. + // + BinaryExpr struct { + X Expr; // left operand + OpPos token.Position; // position of Op + Op token.Token; // operator + Y Expr; // right operand + }; + + // A KeyValueExpr node represents (key : value) pairs + // in composite literals. + // + KeyValueExpr struct { + Key Expr; + Colon token.Position; // 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 { + token.Position; // position of "[" + Len Expr; // Ellipsis node for [...]T array types, nil for slice types + Elt Expr; // element type + }; + + // A StructType node represents a struct type. + StructType struct { + token.Position; // position of "struct" keyword + Lbrace token.Position; // position of "{" + Fields []*Field; // list of field declarations; nil if forward declaration + Rbrace token.Position; // position of "}" + }; + + // Pointer types are represented via StarExpr nodes. + + // A FuncType node represents a function type. + FuncType struct { + token.Position; // position of "func" keyword + Params []*Field; // (incoming) parameters + Results []*Field; // (outgoing) results + }; + + // An InterfaceType node represents an interface type. + InterfaceType struct { + token.Position; // position of "interface" keyword + Lbrace token.Position; // position of "{" + Methods []*Field; // list of methods; nil if forward declaration + Rbrace token.Position; // position of "}" + }; + + // A MapType node represents a map type. + MapType struct { + token.Position; // position of "map" keyword + Key Expr; + Value Expr; + }; + + // A ChanType node represents a channel type. + ChanType struct { + token.Position; // position of "chan" keyword or "<-" (whichever comes first) + Dir ChanDir; // channel direction + Value Expr; // value type + }; +) + + +// Pos() implementations for expression/type where the position +// corresponds to the position of a sub-node. +// +func (x *StringList) Pos() token.Position { return x.Strings[0].Pos(); } +func (x *FuncLit) Pos() token.Position { return x.Type.Pos(); } +func (x *CompositeLit) Pos() token.Position { return x.Type.Pos(); } +func (x *SelectorExpr) Pos() token.Position { return x.X.Pos(); } +func (x *IndexExpr) Pos() token.Position { return x.X.Pos(); } +func (x *TypeAssertExpr) Pos() token.Position { return x.X.Pos(); } +func (x *CallExpr) Pos() token.Position { return x.Fun.Pos(); } +func (x *BinaryExpr) Pos() token.Position { return x.X.Pos(); } +func (x *KeyValueExpr) Pos() token.Position { return x.Key.Pos(); } + + +// All expression/type nodes implement a Visit method which takes +// an ExprVisitor as argument. For a given node x of type X, and +// an implementation v of an ExprVisitor, calling x.Visit(v) will +// result in a call of v.DoX(x) (through a double-dispatch). +// +type ExprVisitor interface { + // Expressions + DoBadExpr(x *BadExpr); + DoIdent(x *Ident); + DoIntLit(x *IntLit); + DoFloatLit(x *FloatLit); + DoCharLit(x *CharLit); + DoStringLit(x *StringLit); + DoStringList(x *StringList); + DoFuncLit(x *FuncLit); + DoCompositeLit(x *CompositeLit); + DoParenExpr(x *ParenExpr); + DoSelectorExpr(x *SelectorExpr); + DoIndexExpr(x *IndexExpr); + DoTypeAssertExpr(x *TypeAssertExpr); + DoCallExpr(x *CallExpr); + DoStarExpr(x *StarExpr); + DoUnaryExpr(x *UnaryExpr); + DoBinaryExpr(x *BinaryExpr); + DoKeyValueExpr(x *KeyValueExpr); + + // Type expressions + DoEllipsis(x *Ellipsis); + DoArrayType(x *ArrayType); + DoStructType(x *StructType); + DoFuncType(x *FuncType); + DoInterfaceType(x *InterfaceType); + DoMapType(x *MapType); + DoChanType(x *ChanType); +} + + +// Visit() implementations for all expression/type nodes. +// +func (x *BadExpr) Visit(v ExprVisitor) { v.DoBadExpr(x); } +func (x *Ident) Visit(v ExprVisitor) { v.DoIdent(x); } +func (x *Ellipsis) Visit(v ExprVisitor) { v.DoEllipsis(x); } +func (x *IntLit) Visit(v ExprVisitor) { v.DoIntLit(x); } +func (x *FloatLit) Visit(v ExprVisitor) { v.DoFloatLit(x); } +func (x *CharLit) Visit(v ExprVisitor) { v.DoCharLit(x); } +func (x *StringLit) Visit(v ExprVisitor) { v.DoStringLit(x); } +func (x *StringList) Visit(v ExprVisitor) { v.DoStringList(x); } +func (x *FuncLit) Visit(v ExprVisitor) { v.DoFuncLit(x); } +func (x *CompositeLit) Visit(v ExprVisitor) { v.DoCompositeLit(x); } +func (x *ParenExpr) Visit(v ExprVisitor) { v.DoParenExpr(x); } +func (x *SelectorExpr) Visit(v ExprVisitor) { v.DoSelectorExpr(x); } +func (x *IndexExpr) Visit(v ExprVisitor) { v.DoIndexExpr(x); } +func (x *TypeAssertExpr) Visit(v ExprVisitor) { v.DoTypeAssertExpr(x); } +func (x *CallExpr) Visit(v ExprVisitor) { v.DoCallExpr(x); } +func (x *StarExpr) Visit(v ExprVisitor) { v.DoStarExpr(x); } +func (x *UnaryExpr) Visit(v ExprVisitor) { v.DoUnaryExpr(x); } +func (x *BinaryExpr) Visit(v ExprVisitor) { v.DoBinaryExpr(x); } +func (x *KeyValueExpr) Visit(v ExprVisitor) { v.DoKeyValueExpr(x); } + +func (x *ArrayType) Visit(v ExprVisitor) { v.DoArrayType(x); } +func (x *StructType) Visit(v ExprVisitor) { v.DoStructType(x); } +func (x *FuncType) Visit(v ExprVisitor) { v.DoFuncType(x); } +func (x *InterfaceType) Visit(v ExprVisitor) { v.DoInterfaceType(x); } +func (x *MapType) Visit(v ExprVisitor) { v.DoMapType(x); } +func (x *ChanType) Visit(v ExprVisitor) { v.DoChanType(x); } + + +// IsExported returns whether name is an exported Go symbol +// (i.e., whether it begins with an uppercase letter). +func IsExported(name string) bool { + ch, len := utf8.DecodeRuneInString(name); + return unicode.IsUpper(ch); +} + +// IsExported returns whether name is an exported Go symbol +// (i.e., whether it begins with an uppercase letter). +func (name *ast.Ident) IsExported() bool { + return IsExported(name.Value); +} + +func (name *ast.Ident) String() string { + return name.Value; +} + + +// ---------------------------------------------------------------------------- +// 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 { + token.Position; // beginning position of bad statement + }; + + // A DeclStmt node represents a declaration in a statement list. + DeclStmt struct { + Decl Decl; + }; + + // An EmptyStmt node represents an empty statement. + // The "position" of the empty statement is the position + // of the immediately preceeding semicolon. + // + EmptyStmt struct { + token.Position; // position of preceeding ";" + }; + + // A LabeledStmt node represents a labeled statement. + LabeledStmt struct { + Label *Ident; + Stmt Stmt; + }; + + // An ExprStmt node represents a (stand-alone) expression + // in a statement list. + // + ExprStmt struct { + X Expr; // expression + }; + + // An IncDecStmt node represents an increment or decrement statement. + IncDecStmt struct { + X Expr; + Tok token.Token; // INC or DEC + }; + + // An AssignStmt node represents an assignment or + // a short variable declaration. + AssignStmt struct { + Lhs []Expr; + TokPos token.Position; // position of Tok + Tok token.Token; // assignment token, DEFINE + Rhs []Expr; + }; + + // A GoStmt node represents a go statement. + GoStmt struct { + token.Position; // position of "go" keyword + Call *CallExpr; + }; + + // A DeferStmt node represents a defer statement. + DeferStmt struct { + token.Position; // position of "defer" keyword + Call *CallExpr; + }; + + // A ReturnStmt node represents a return statement. + ReturnStmt struct { + token.Position; // position of "return" keyword + Results []Expr; + }; + + // A BranchStmt node represents a break, continue, goto, + // or fallthrough statement. + // + BranchStmt struct { + token.Position; // position of Tok + Tok token.Token; // keyword token (BREAK, CONTINUE, GOTO, FALLTHROUGH) + Label *Ident; + }; + + // A BlockStmt node represents a braced statement list. + BlockStmt struct { + token.Position; // position of "{" + List []Stmt; + Rbrace token.Position; // position of "}" + }; + + // An IfStmt node represents an if statement. + IfStmt struct { + token.Position; // position of "if" keyword + Init Stmt; + Cond Expr; + Body *BlockStmt; + Else Stmt; + }; + + // A CaseClause represents a case of an expression switch statement. + CaseClause struct { + token.Position; // position of "case" or "default" keyword + Values []Expr; // nil means default case + Colon token.Position; // position of ":" + Body []Stmt; // statement list; or nil + }; + + // A SwitchStmt node represents an expression switch statement. + SwitchStmt struct { + token.Position; // position of "switch" keyword + Init Stmt; + Tag Expr; + Body *BlockStmt; // CaseClauses only + }; + + // A TypeCaseClause represents a case of a type switch statement. + TypeCaseClause struct { + token.Position; // position of "case" or "default" keyword + Type Expr; // nil means default case + Colon token.Position; // position of ":" + Body []Stmt; // statement list; or nil + }; + + // An TypeSwitchStmt node represents a type switch statement. + TypeSwitchStmt struct { + token.Position; // position of "switch" keyword + Init Stmt; + Assign Stmt; // x := y.(type) + Body *BlockStmt; // TypeCaseClauses only + }; + + // A CommClause node represents a case of a select statement. + CommClause struct { + token.Position; // position of "case" or "default" keyword + Tok token.Token; // ASSIGN or DEFINE (valid only if Lhs != nil) + Lhs, Rhs Expr; // Rhs == nil means default case + Colon token.Position; // position of ":" + Body []Stmt; // statement list; or nil + }; + + // An SelectStmt node represents a select statement. + SelectStmt struct { + token.Position; // position of "select" keyword + Body *BlockStmt; // CommClauses only + }; + + // A ForStmt represents a for statement. + ForStmt struct { + token.Position; // position of "for" keyword + Init Stmt; + Cond Expr; + Post Stmt; + Body *BlockStmt; + }; + + // A RangeStmt represents a for statement with a range clause. + RangeStmt struct { + token.Position; // position of "for" keyword + Key, Value Expr; // Value may be nil + TokPos token.Position; // position of Tok + Tok token.Token; // ASSIGN, DEFINE + X Expr; // value to range over + Body *BlockStmt; + }; +) + + +// Pos() implementations for statement nodes where the position +// corresponds to the position of a sub-node. +// +func (s *DeclStmt) Pos() token.Position { return s.Decl.Pos(); } +func (s *LabeledStmt) Pos() token.Position { return s.Label.Pos(); } +func (s *ExprStmt) Pos() token.Position { return s.X.Pos(); } +func (s *IncDecStmt) Pos() token.Position { return s.X.Pos(); } +func (s *AssignStmt) Pos() token.Position { return s.Lhs[0].Pos(); } + + +// All statement nodes implement a Visit method which takes +// a StmtVisitor as argument. For a given node x of type X, and +// an implementation v of a StmtVisitor, calling x.Visit(v) will +// result in a call of v.DoX(x) (through a double-dispatch). +// +type StmtVisitor interface { + DoBadStmt(s *BadStmt); + DoDeclStmt(s *DeclStmt); + DoEmptyStmt(s *EmptyStmt); + DoLabeledStmt(s *LabeledStmt); + DoExprStmt(s *ExprStmt); + DoIncDecStmt(s *IncDecStmt); + DoAssignStmt(s *AssignStmt); + DoGoStmt(s *GoStmt); + DoDeferStmt(s *DeferStmt); + DoReturnStmt(s *ReturnStmt); + DoBranchStmt(s *BranchStmt); + DoBlockStmt(s *BlockStmt); + DoIfStmt(s *IfStmt); + DoCaseClause(s *CaseClause); + DoSwitchStmt(s *SwitchStmt); + DoTypeCaseClause(s *TypeCaseClause); + DoTypeSwitchStmt(s *TypeSwitchStmt); + DoCommClause(s *CommClause); + DoSelectStmt(s *SelectStmt); + DoForStmt(s *ForStmt); + DoRangeStmt(s *RangeStmt); +} + + +// Visit() implementations for all statement nodes. +// +func (s *BadStmt) Visit(v StmtVisitor) { v.DoBadStmt(s); } +func (s *DeclStmt) Visit(v StmtVisitor) { v.DoDeclStmt(s); } +func (s *EmptyStmt) Visit(v StmtVisitor) { v.DoEmptyStmt(s); } +func (s *LabeledStmt) Visit(v StmtVisitor) { v.DoLabeledStmt(s); } +func (s *ExprStmt) Visit(v StmtVisitor) { v.DoExprStmt(s); } +func (s *IncDecStmt) Visit(v StmtVisitor) { v.DoIncDecStmt(s); } +func (s *AssignStmt) Visit(v StmtVisitor) { v.DoAssignStmt(s); } +func (s *GoStmt) Visit(v StmtVisitor) { v.DoGoStmt(s); } +func (s *DeferStmt) Visit(v StmtVisitor) { v.DoDeferStmt(s); } +func (s *ReturnStmt) Visit(v StmtVisitor) { v.DoReturnStmt(s); } +func (s *BranchStmt) Visit(v StmtVisitor) { v.DoBranchStmt(s); } +func (s *BlockStmt) Visit(v StmtVisitor) { v.DoBlockStmt(s); } +func (s *IfStmt) Visit(v StmtVisitor) { v.DoIfStmt(s); } +func (s *CaseClause) Visit(v StmtVisitor) { v.DoCaseClause(s); } +func (s *SwitchStmt) Visit(v StmtVisitor) { v.DoSwitchStmt(s); } +func (s *TypeCaseClause) Visit(v StmtVisitor) { v.DoTypeCaseClause(s); } +func (s *TypeSwitchStmt) Visit(v StmtVisitor) { v.DoTypeSwitchStmt(s); } +func (s *CommClause) Visit(v StmtVisitor) { v.DoCommClause(s); } +func (s *SelectStmt) Visit(v StmtVisitor) { v.DoSelectStmt(s); } +func (s *ForStmt) Visit(v StmtVisitor) { v.DoForStmt(s); } +func (s *RangeStmt) Visit(v StmtVisitor) { v.DoRangeStmt(s); } + + +// ---------------------------------------------------------------------------- +// 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 {}; + + // An ImportSpec node represents a single package import. + ImportSpec struct { + Doc Comments; // associated documentation; or nil + Name *Ident; // local package name (including "."); or nil + Path []*StringLit; // package path + }; + + // A ValueSpec node represents a constant or variable declaration + // (ConstSpec or VarSpec production). + ValueSpec struct { + Doc Comments; // associated documentation; or nil + Names []*Ident; + Type Expr; // value type; or nil + Values []Expr; + }; + + // A TypeSpec node represents a type declaration (TypeSpec production). + TypeSpec struct { + Doc Comments; // associated documentation; or nil + Name *Ident; // type name + Type Expr; + }; +) + + +// 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 { + token.Position; // beginning position 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 Comments; // associated documentation; or nil + token.Position; // position of Tok + Tok token.Token; // IMPORT, CONST, TYPE, VAR + Lparen token.Position; // position of '(', if any + Specs []Spec; + Rparen token.Position; // position of ')', if any + }; + + // A FuncDecl node represents a function declaration. + FuncDecl struct { + Doc Comments; // associated documentation; or nil + Recv *Field; // 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) + }; +) + + +// The position of a FuncDecl node is the position of its function type. +func (d *FuncDecl) Pos() token.Position { return d.Type.Pos(); } + + +// All declaration nodes implement a Visit method which takes +// a DeclVisitor as argument. For a given node x of type X, and +// an implementation v of a DeclVisitor, calling x.Visit(v) will +// result in a call of v.DoX(x) (through a double-dispatch). +// +type DeclVisitor interface { + DoBadDecl(d *BadDecl); + DoGenDecl(d *GenDecl); + DoFuncDecl(d *FuncDecl); +} + + +// Visit() implementations for all declaration nodes. +// +func (d *BadDecl) Visit(v DeclVisitor) { v.DoBadDecl(d); } +func (d *GenDecl) Visit(v DeclVisitor) { v.DoGenDecl(d); } +func (d *FuncDecl) Visit(v DeclVisitor) { v.DoFuncDecl(d); } + + +// ---------------------------------------------------------------------------- +// Programs + +// A Program node represents the root node of an AST +// for an entire source file. +// +type Program struct { + Doc Comments; // associated documentation; or nil + token.Position; // position of "package" keyword + Name *Ident; // package name + Decls []Decl; // top-level declarations + Comments []*Comment; // list of unassociated comments +} diff --git a/src/pkg/go/ast/format.go b/src/pkg/go/ast/format.go new file mode 100644 index 000000000..caeca19aa --- /dev/null +++ b/src/pkg/go/ast/format.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 ast + +import ( + "datafmt"; + "go/ast"; + "go/token"; + "io"; + "os"; +) + + +// Format is a customized datafmt.Format for printing of ASTs. +type Format datafmt.Format; + + +// ---------------------------------------------------------------------------- +// Custom formatters + +// The AST-specific formatting state is maintained by a state variable. +type state struct { + // for now we have very little state + // TODO maintain list of unassociated comments + optSemi bool +} + + +func (s *state) Copy() datafmt.Environment { + copy := *s; + return © +} + + +func isValidPos(s *datafmt.State, value interface{}, ruleName string) bool { + pos := value.(token.Position); + return pos.IsValid(); +} + + +func isSend(s *datafmt.State, value interface{}, ruleName string) bool { + return value.(ast.ChanDir) & ast.SEND != 0; +} + + +func isRecv(s *datafmt.State, value interface{}, ruleName string) bool { + return value.(ast.ChanDir) & ast.RECV != 0; +} + + +func isMultiLineComment(s *datafmt.State, value interface{}, ruleName string) bool { + return value.([]byte)[1] == '*'; +} + + +func clearOptSemi(s *datafmt.State, value interface{}, ruleName string) bool { + s.Env().(*state).optSemi = false; + return true; +} + + +func setOptSemi(s *datafmt.State, value interface{}, ruleName string) bool { + s.Env().(*state).optSemi = true; + return true; +} + + +func optSemi(s *datafmt.State, value interface{}, ruleName string) bool { + if !s.Env().(*state).optSemi { + s.Write([]byte{';'}); + } + return true; +} + + +var fmap = datafmt.FormatterMap { + "isValidPos": isValidPos, + "isSend": isSend, + "isRecv": isRecv, + "isMultiLineComment": isMultiLineComment, + "/": clearOptSemi, + "clearOptSemi": clearOptSemi, + "setOptSemi": setOptSemi, + "optSemi": optSemi, +} + + +// ---------------------------------------------------------------------------- +// Printing + +// NewFormat parses a datafmt format specification from a file +// and adds AST-specific custom formatter rules. The result is +// the customized format or an os.Error, if any. +// +func NewFormat(filename string) (Format, os.Error) { + src, err := io.ReadFile(filename); + if err != nil { + return nil, err; + } + f, err := datafmt.Parse(src, fmap); + return Format(f), err; +} + + +// Fprint formats each AST node provided as 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) Fprint(w io.Writer, nodes ...) (int, os.Error) { + var s state; + return datafmt.Format(f).Fprint(w, &s, nodes); +} + + +// Fprint formats each AST node provided as 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) Print(nodes ...) (int, os.Error) { + return f.Fprint(os.Stdout, nodes); +} diff --git a/src/pkg/go/doc/Makefile b/src/pkg/go/doc/Makefile new file mode 100644 index 000000000..d7c6acaac --- /dev/null +++ b/src/pkg/go/doc/Makefile @@ -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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D=/go/ + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + comment.$O\ + +O2=\ + doc.$O\ + + +phases: a1 a2 +_obj$D/doc.a: phases + +a1: $(O1) + $(AR) grc _obj$D/doc.a comment.$O + rm -f $(O1) + +a2: $(O2) + $(AR) grc _obj$D/doc.a doc.$O + rm -f $(O2) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/doc.a + +$(O1): newpkg +$(O2): a1 +$(O3): a2 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/doc.a + +packages: _obj$D/doc.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/doc.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/doc.a diff --git a/src/pkg/go/doc/comment.go b/src/pkg/go/doc/comment.go new file mode 100644 index 000000000..19a65a227 --- /dev/null +++ b/src/pkg/go/doc/comment.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. + +// Godoc comment extraction and comment -> HTML formatting. + +package doc + +import ( + "fmt"; + "io"; + "once"; + "regexp"; + "strings"; + "template"; // for htmlEscape +) + +// Comment extraction + +var ( + comment_markers *regexp.Regexp; + trailing_whitespace *regexp.Regexp; + comment_junk *regexp.Regexp; +) + +func makeRex(s string) *regexp.Regexp { + re, err := regexp.Compile(s); + if err != nil { + panic("MakeRegexp ", s, " ", err.String()); + } + return re; +} + +// TODO(rsc): Cannot use var initialization for regexps, +// because Regexp constructor needs threads. +func setupRegexps() { + comment_markers = makeRex("^/(/|\\*) ?"); + trailing_whitespace = makeRex("[ \t\r]+$"); + comment_junk = makeRex("^[ \t]*(/\\*|\\*/)[ \t]*$"); +} + +// Aggregate comment text, without comment markers. +func commentText(comments []string) string { + once.Do(setupRegexps); + lines := make([]string, 0, 20); + for i, c := range comments { + // split on newlines + cl := strings.Split(c, "\n"); + + // walk lines, stripping comment markers + w := 0; + for j, l := range cl { + // remove /* and */ lines + if comment_junk.Match(l) { + continue; + } + + // strip trailing white space + m := trailing_whitespace.Execute(l); + if len(m) > 0 { + l = l[0 : m[1]]; + } + + // strip leading comment markers + m = comment_markers.Execute(l); + if len(m) > 0 { + l = l[m[1] : len(l)]; + } + + // throw away leading blank lines + if w == 0 && l == "" { + continue; + } + + cl[w] = l; + w++; + } + + // throw away trailing blank lines + for w > 0 && cl[w-1] == "" { + w--; + } + cl = cl[0 : w]; + + // add this comment to total list + // TODO: maybe separate with a single blank line + // if there is already a comment and len(cl) > 0? + for j, l := range cl { + n := len(lines); + if n+1 >= cap(lines) { + newlines := make([]string, n, 2*cap(lines)); + for k := range newlines { + newlines[k] = lines[k]; + } + lines = newlines; + } + lines = lines[0 : n+1]; + lines[n] = l; + } + } + + // add final "" entry to get trailing newline. + // loop always leaves room for one more. + n := len(lines); + lines = lines[0 : n+1]; + + 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 : len(text)]; + } + + return out; +} + + +var ( + ldquo = io.StringBytes("“"); + rdquo = io.StringBytes("”"); +) + +// Escape comment text for HTML. +// Also, turn `` into “ and '' into ”. +func commentEscape(w io.Writer, s []byte) { + last := 0; + for i := 0; i < len(s)-1; i++ { + if s[i] == s[i+1] && (s[i] == '`' || s[i] == '\'') { + template.HtmlEscape(w, s[last : i]); + last = i+2; + switch s[i] { + case '`': + w.Write(ldquo); + case '\'': + w.Write(rdquo); + } + i++; // loop will add one more + } + } + template.HtmlEscape(w, s[last : len(s)]); +} + + +var ( + html_p = io.StringBytes("

\n"); + html_endp = io.StringBytes("

\n"); + html_pre = io.StringBytes("
");
+	html_endpre = io.StringBytes("
\n"); +) + + +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 i, 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 : len(line)]; + } + } +} + + +// 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

+// Turn each run of indented lines into

 without indent.
+//
+// TODO(rsc): I'd like to pass in an array of variable names []string
+// and then italicize those strings when they appear as words.
+func ToHtml(w io.Writer, s []byte) {
+	inpara := false;
+
+	/* TODO(rsc): 6g cant generate code for these
+	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
+			if inpara {
+				w.Write(html_endp);
+				inpara = false;
+			}
+			i++;
+			continue;
+		}
+		if indentLen(line) > 0 {
+			// close paragraph
+			if inpara {
+				w.Write(html_endp);
+				inpara = false;
+			}
+
+			// 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.
+			// they don't get the nice text formatting,
+			// just html escaping
+			w.Write(html_pre);
+			for k, line := range block {
+				template.HtmlEscape(w, line);
+			}
+			w.Write(html_endpre);
+			continue;
+		}
+		// open paragraph
+		if !inpara {
+			w.Write(html_p);
+			inpara = true;
+		}
+		commentEscape(w, lines[i]);
+		i++;
+	}
+	if inpara {
+		w.Write(html_endp);
+		inpara = false;
+	}
+}
+
diff --git a/src/pkg/go/doc/doc.go b/src/pkg/go/doc/doc.go
new file mode 100644
index 000000000..03872fd14
--- /dev/null
+++ b/src/pkg/go/doc/doc.go
@@ -0,0 +1,486 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package doc
+
+import (
+	"container/vector";
+	"fmt";
+	"go/ast";
+	"go/doc";
+	"go/token";
+	"io";
+	"regexp";
+	"sort";
+	"strings";
+)
+
+
+// ----------------------------------------------------------------------------
+// Elementary support
+
+func hasExportedNames(names []*ast.Ident) bool {
+	for i, name := range names {
+		if name.IsExported() {
+			return true;
+		}
+	}
+	return false;
+}
+
+
+func hasExportedSpecs(specs []ast.Spec) bool {
+	for i, s := range specs {
+		// only called for []astSpec lists of *ast.ValueSpec
+		return hasExportedNames(s.(*ast.ValueSpec).Names);
+	}
+	return false;
+}
+
+
+// ----------------------------------------------------------------------------
+
+type typeDoc struct {
+	decl *ast.GenDecl;  // len(decl.Specs) == 1, and the element type is *ast.TypeSpec
+	factories map[string] *ast.FuncDecl;
+	methods map[string] *ast.FuncDecl;
+}
+
+
+// DocReader accumulates documentation for a single package.
+//
+type DocReader struct {
+	name string;  // package name
+	path string;  // import path
+	doc ast.Comments;  // package documentation, if any
+	consts *vector.Vector;  // list of *ast.GenDecl
+	types map[string] *typeDoc;
+	vars *vector.Vector;  // list of *ast.GenDecl
+	funcs map[string] *ast.FuncDecl;
+}
+
+
+// Init initializes a DocReader to collect package documentation
+// for the package with the given package name and import path.
+//
+func (doc *DocReader) Init(pkg, imp string) {
+	doc.name = pkg;
+	doc.path = imp;
+	doc.consts = vector.New(0);
+	doc.types = make(map[string] *typeDoc);
+	doc.vars = vector.New(0);
+	doc.funcs = make(map[string] *ast.FuncDecl);
+}
+
+
+func baseTypeName(typ ast.Expr) string {
+	switch t := typ.(type) {
+	case *ast.Ident:
+		return string(t.Value);
+	case *ast.StarExpr:
+		return baseTypeName(t.X);
+	}
+	return "";
+}
+
+
+func (doc *DocReader) lookupTypeDoc(typ ast.Expr) *typeDoc {
+	tdoc, found := doc.types[baseTypeName(typ)];
+	if found {
+		return tdoc;
+	}
+	return nil;
+}
+
+
+func (doc *DocReader) addType(decl *ast.GenDecl) {
+	typ := decl.Specs[0].(*ast.TypeSpec);
+	name := typ.Name.Value;
+	tdoc := &typeDoc{decl, make(map[string] *ast.FuncDecl), make(map[string] *ast.FuncDecl)};
+	doc.types[name] = tdoc;
+}
+
+
+func (doc *DocReader) addFunc(fun *ast.FuncDecl) {
+	name := fun.Name.Value;
+
+	// determine if it should be associated with a type
+	var typ *typeDoc;
+	if fun.Recv != nil {
+		// method
+		// (all receiver types must be declared before they are used)
+		typ = doc.lookupTypeDoc(fun.Recv.Type);
+		if typ != nil {
+			// type found (i.e., exported)
+			typ.methods[name] = fun;
+		}
+		// if the type wasn't found, it wasn't exported
+		// TODO(gri): a non-exported type may still have exported functions
+		//            determine what to do in that case
+		return;
+	}
+
+	// perhaps a factory function
+	// determine result type, if any
+	if len(fun.Type.Results) >= 1 {
+		res := fun.Type.Results[0];
+		if len(res.Names) <= 1 {
+			// exactly one (named or anonymous) result type
+			typ = doc.lookupTypeDoc(res.Type);
+			if typ != nil {
+				typ.factories[name] = fun;
+				return;
+			}
+		}
+	}
+
+	// ordinary function
+	doc.funcs[name] = 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.IMPORT:
+				// ignore
+			case token.CONST:
+				// constants are always handled as a group
+				if hasExportedSpecs(d.Specs) {
+					doc.consts.Push(d);
+				}
+			case token.TYPE:
+				// types are handled individually
+				for i, spec := range d.Specs {
+					s := spec.(*ast.TypeSpec);
+					if s.Name.IsExported() {
+						// make a (fake) GenDecl node for this TypeSpec
+						// (we need to do this here - as opposed to just
+						// for printing - so we don't loose the GenDecl
+						// documentation)
+						var noPos token.Position;
+						doc.addType(&ast.GenDecl{d.Doc, d.Pos(), token.TYPE, noPos, []ast.Spec{s}, noPos});
+					}
+				}
+			case token.VAR:
+				// variables are always handled as a group
+				if hasExportedSpecs(d.Specs) {
+					doc.vars.Push(d);
+				}
+			}
+		}
+	case *ast.FuncDecl:
+		if d.Name.IsExported() {
+			doc.addFunc(d);
+		}
+	}
+}
+
+
+// AddProgram adds the AST for a source file to the DocReader.
+// Adding the same AST multiple times is a no-op.
+//
+func (doc *DocReader) AddProgram(prog *ast.Program) {
+	if doc.name != prog.Name.Value {
+		panic("package names don't match");
+	}
+
+	// add package documentation
+	// TODO(gri) what to do if there are multiple files?
+	if prog.Doc != nil {
+		doc.doc = prog.Doc
+	}
+
+	// add all exported declarations
+	for i, decl := range prog.Decls {
+		doc.addDecl(decl);
+	}
+}
+
+// ----------------------------------------------------------------------------
+// Conversion to external representation
+
+func astComment(comments ast.Comments) string {
+	text := make([]string, len(comments));
+	for i, c := range comments {
+		text[i] = string(c.Text);
+	}
+	return commentText(text);
+}
+
+// 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].Value;
+	case *ast.TypeSpec:
+		return v.Name.Value;
+	}
+
+	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(v *vector.Vector) []*ValueDoc {
+	d := make([]*ValueDoc, v.Len());
+	for i := range d {
+		decl := v.At(i).(*ast.GenDecl);
+		d[i] = &ValueDoc{astComment(decl.Doc), decl, i};
+	}
+	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 name, f := range m {
+		doc := new(FuncDoc);
+		doc.Doc = astComment(f.Doc);
+		if f.Recv != nil {
+			doc.Recv = f.Recv.Type;
+		}
+		doc.Name = f.Name.Value;
+		doc.Decl = f;
+		d[i] = doc;
+		i++;
+	}
+	sort.Sort(sortFuncDoc(d));
+	return d;
+}
+
+
+// TypeDoc is the documentation for a declared 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;
+	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.Value, p[j].Type.Name.Value; 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 statements.
+func makeTypeDocs(m map[string] *typeDoc) []*TypeDoc {
+	d := make([]*TypeDoc, len(m));
+	i := 0;
+	for name, old := range m {
+		typespec := old.decl.Specs[0].(*ast.TypeSpec);
+		t := new(TypeDoc);
+		t.Doc = astComment(typespec.Doc);
+		t.Type = typespec;
+		t.Factories = makeFuncDocs(old.factories);
+		t.Methods = makeFuncDocs(old.methods);
+		t.Decl = old.decl;
+		t.order = i;
+		d[i] = t;
+		i++;
+	}
+	sort.Sort(sortTypeDoc(d));
+	return d;
+}
+
+
+// PackageDoc is the documentation for an entire package.
+//
+type PackageDoc struct {
+	PackageName string;
+	ImportPath string;
+	Doc string;
+	Consts []*ValueDoc;
+	Types []*TypeDoc;
+	Vars []*ValueDoc;
+	Funcs []*FuncDoc;
+}
+
+
+// Doc returns the accumulated documentation for the package.
+//
+func (doc *DocReader) Doc() *PackageDoc {
+	p := new(PackageDoc);
+	p.PackageName = doc.name;
+	p.ImportPath = doc.path;
+	p.Doc = astComment(doc.doc);
+	p.Consts = makeValueDocs(doc.consts);
+	p.Vars = makeValueDocs(doc.vars);
+	p.Types = makeTypeDocs(doc.types);
+	p.Funcs = makeFuncDocs(doc.funcs);
+	return p;
+}
+
+
+// ----------------------------------------------------------------------------
+// Filtering by name
+
+// Does s look like a regular expression?
+func isRegexp(s string) bool {
+	metachars := ".(|)*+?^$[]";
+	for i, c := range s {
+		for j, m := range metachars {
+			if c == m {
+				return true
+			}
+		}
+	}
+	return false
+}
+
+
+func match(s string, a []string) bool {
+	for i, t := range a {
+		if isRegexp(t) {
+			if matched, err := regexp.Match(t, s); matched {
+				return true;
+			}
+		}
+		if s == t {
+			return true;
+		}
+	}
+	return false;
+}
+
+
+func matchDecl(d *ast.GenDecl, names []string) bool {
+	for i, d := range d.Specs {
+		switch v := d.(type) {
+		case *ast.ValueSpec:
+			for j, name := range v.Names {
+				if match(name.Value, names) {
+					return true;
+				}
+			}
+		case *ast.TypeSpec:
+			if match(v.Name.Value, names) {
+				return true;
+			}
+		}
+	}
+	return false;
+}
+
+
+func filterValueDocs(a []*ValueDoc, names []string) []*ValueDoc {
+	w := 0;
+	for i, vd := range a {
+		if matchDecl(vd.Decl, names) {
+			a[w] = vd;
+			w++;
+		}
+	}
+	return a[0 : w];
+}
+
+
+func filterFuncDocs(a []*FuncDoc, names []string) []*FuncDoc {
+	w := 0;
+	for i, fd := range a {
+		if match(fd.Name, names) {
+			a[w] = fd;
+			w++;
+		}
+	}
+	return a[0 : w];
+}
+
+
+func filterTypeDocs(a []*TypeDoc, names []string) []*TypeDoc {
+	w := 0;
+	for i, td := range a {
+		match := false;
+		if matchDecl(td.Decl, names) {
+			match = true;
+		} else {
+			// type name doesn't match, but we may have matching factories or methods
+			td.Factories = filterFuncDocs(td.Factories, names);
+			td.Methods = filterFuncDocs(td.Methods, names);
+			match = len(td.Factories) > 0 || len(td.Methods) > 0;
+		}
+		if match {
+			a[w] = td;
+			w++;
+		}
+	}
+	return a[0 : w];
+}
+
+
+// Filter eliminates information from d that is not
+// about one of the given names.
+// TODO: Recognize "Type.Method" as a name.
+// TODO(r): maybe precompile the regexps.
+//
+func (p *PackageDoc) Filter(names []string) {
+	p.Consts = filterValueDocs(p.Consts, names);
+	p.Vars = filterValueDocs(p.Vars, names);
+	p.Types = filterTypeDocs(p.Types, names);
+	p.Funcs = filterFuncDocs(p.Funcs, names);
+	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..08d83646f
--- /dev/null
+++ b/src/pkg/go/parser/Makefile
@@ -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.
+
+# DO NOT EDIT.  Automatically generated by gobuild.
+# gobuild -m >Makefile
+
+D=/go/
+
+include $(GOROOT)/src/Make.$(GOARCH)
+AR=gopack
+
+default: packages
+
+clean:
+	rm -rf *.[$(OS)] *.a [$(OS)].out _obj
+
+test: packages
+	gotest
+
+coverage: packages
+	gotest
+	6cov -g `pwd` | grep -v '_test\.go:'
+
+%.$O: %.go
+	$(GC) -I_obj $*.go
+
+%.$O: %.c
+	$(CC) $*.c
+
+%.$O: %.s
+	$(AS) $*.s
+
+O1=\
+	parser.$O\
+
+
+phases: a1
+_obj$D/parser.a: phases
+
+a1: $(O1)
+	$(AR) grc _obj$D/parser.a parser.$O
+	rm -f $(O1)
+
+
+newpkg: clean
+	mkdir -p _obj$D
+	$(AR) grc _obj$D/parser.a
+
+$(O1): newpkg
+$(O2): a1
+
+nuke: clean
+	rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/parser.a
+
+packages: _obj$D/parser.a
+
+install: packages
+	test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D
+	cp _obj$D/parser.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/parser.a
diff --git a/src/pkg/go/parser/parser.go b/src/pkg/go/parser/parser.go
new file mode 100644
index 000000000..056868695
--- /dev/null
+++ b/src/pkg/go/parser/parser.go
@@ -0,0 +1,1975 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// A parser for Go source text. The input is a stream of lexical tokens
+// provided via the Scanner interface. The output is an abstract syntax
+// tree (AST) representing the Go source. The parser is invoked by calling
+// Parse.
+//
+package parser
+
+import (
+	"container/vector";
+	"fmt";
+	"go/ast";
+	"go/scanner";
+	"go/token";
+	"io";
+	"os";
+)
+
+
+// A parser 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 {
+	pos := "";
+	if e.Pos.IsValid() {
+		pos = fmt.Sprintf("%d:%d: ", e.Pos.Line, e.Pos.Column);
+	}
+	return pos + e.Msg;
+}
+
+
+// Parser errors are returned as an ErrorList.
+type ErrorList []*Error
+
+
+// ErrorList implements the SortInterface.
+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  { return p[i].Pos.Offset < p[j].Pos.Offset; }
+
+
+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);
+}
+
+
+type interval struct {
+	beg, end int;
+}
+
+
+// The parser structure holds the parser's internal state.
+type parser struct {
+	errors vector.Vector;
+	scanner scanner.Scanner;
+
+	// Tracing/debugging
+	mode uint;  // parsing mode
+	trace bool;  // == (mode & Trace != 0)
+	indent uint;  // indentation used for tracing output
+
+	// Comments
+	comments vector.Vector;  // list of collected, unassociated comments
+	last_doc interval;  // last comments interval of consecutive comments
+
+	// The next token
+	pos token.Position;  // token position
+	tok token.Token;  // one token look-ahead
+	lit []byte;  // token literal
+
+	// Non-syntactic parser control
+	opt_semi bool;  // true if semicolon separator is optional in statement list
+	expr_lev int;  // < 0: in control clause, >= 0: in expression
+};
+
+
+// noPos is used when there is no corresponding source position for a token
+var noPos token.Position;
+
+
+// ----------------------------------------------------------------------------
+// Parsing support
+
+func (p *parser) printTrace(a ...) {
+	const dots =
+		". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . "
+		". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ";
+	const n = uint(len(dots));
+	fmt.Printf("%5d:%3d: ", p.pos.Line, p.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;
+}
+
+
+func un/*trace*/(p *parser) {
+	p.indent--;
+	p.printTrace(")");
+}
+
+
+func (p *parser) next0() {
+	// Because of one-token look-ahead, print the previous token
+	// when tracing as it provides a more readable output. The
+	// very first token (p.pos.Line == 0) is not initialized (it
+	// is token.ILLEGAL), so don't print it .
+	if p.trace && p.pos.Line > 0 {
+		s := p.tok.String();
+		switch {
+		case p.tok.IsLiteral():
+			p.printTrace(s, string(p.lit));
+		case p.tok.IsOperator(), p.tok.IsKeyword():
+			p.printTrace("\"" + s + "\"");
+		default:
+			p.printTrace(s);
+		}
+	}
+
+	p.pos, p.tok, p.lit = p.scanner.Scan();
+	p.opt_semi = false;
+}
+
+
+// Collect a comment in the parser's comment list and return the line
+// on which the comment ends.
+//
+func (p *parser) collectComment() int {
+	// For /*-style comments, the comment may end on a different line.
+	// Scan the comment for '\n' chars and adjust the end line accordingly.
+	// (Note that the position of the next token may be even further down
+	// as there may be more whitespace lines after the comment.)
+	endline := p.pos.Line;
+	if p.lit[1] == '*' {
+		for _, b := range p.lit {
+			if b == '\n' {
+				endline++;
+			}
+		}
+	}
+	p.comments.Push(&ast.Comment{p.pos, p.lit, endline});
+	p.next0();
+
+	return endline;
+}
+
+
+func (p *parser) getComments() interval {
+	// group adjacent comments, an empty line terminates a group
+	beg := p.comments.Len();
+	endline := p.pos.Line;
+	for p.tok == token.COMMENT && endline+1 >= p.pos.Line {
+		endline = p.collectComment();
+	}
+	end := p.comments.Len();
+	return interval {beg, end};
+}
+
+
+func (p *parser) getDoc() ast.Comments {
+	doc := p.last_doc;
+	n := doc.end - doc.beg;
+
+	if n <= 0 || p.comments.At(doc.end - 1).(*ast.Comment).EndLine + 1 < p.pos.Line {
+		// no comments or empty line between last comment and current token;
+		// do not use as documentation
+		return nil;
+	}
+
+	// found immediately adjacent comment interval;
+	// use as documentation
+	c := make(ast.Comments, n);
+	for i := 0; i < n; i++ {
+		c[i] = p.comments.At(doc.beg + i).(*ast.Comment);
+	}
+
+	// remove comments from the general list
+	p.comments.Cut(doc.beg, doc.end);
+
+	return c;
+}
+
+
+func (p *parser) next() {
+	p.next0();
+	p.last_doc = interval{0, 0};
+	for p.tok == token.COMMENT {
+		p.last_doc = p.getComments();
+	}
+}
+
+
+// The parser implements scanner.Error.
+func (p *parser) Error(pos token.Position, msg string) {
+	// Don't collect errors that are on the same line as the previous error
+	// in the hope to reduce the number of spurious errors due to incorrect
+	// parser synchronization.
+	if p.errors.Len() == 0 || p.errors.Last().(*Error).Pos.Line != pos.Line {
+		p.errors.Push(&Error{pos, msg});
+	}
+}
+
+
+func (p *parser) error_expected(pos token.Position, msg string) {
+	msg = "expected " + msg;
+	if pos.Offset == p.pos.Offset {
+		// the error happened at the current position;
+		// make the error message more specific
+		msg += ", found '" + p.tok.String() + "'";
+		if p.tok.IsLiteral() {
+			msg += " " + string(p.lit);
+		}
+	}
+	p.Error(pos, msg);
+}
+
+
+func (p *parser) expect(tok token.Token) token.Position {
+	pos := p.pos;
+	if p.tok != tok {
+		p.error_expected(pos, "'" + tok.String() + "'");
+	}
+	p.next();  // make progress in any case
+	return pos;
+}
+
+
+// ----------------------------------------------------------------------------
+// Common productions
+
+func (p *parser) tryType() ast.Expr;
+func (p *parser) parseStringList(x *ast.StringLit) []*ast.StringLit
+func (p *parser) parseExpression() ast.Expr;
+func (p *parser) parseStatement() ast.Stmt;
+func (p *parser) parseDeclaration() ast.Decl;
+
+
+func (p *parser) parseIdent() *ast.Ident {
+	if p.tok == token.IDENT {
+		x := &ast.Ident{p.pos, string(p.lit)};
+		p.next();
+		return x;
+	}
+	p.expect(token.IDENT);  // use expect() error handling
+	return &ast.Ident{p.pos, ""};
+}
+
+
+func (p *parser) parseIdentList(x ast.Expr) []*ast.Ident {
+	if p.trace {
+		defer un(trace(p, "IdentList"));
+	}
+
+	list := vector.New(0);
+	if x == nil {
+		x = p.parseIdent();
+	}
+	list.Push(x);
+	for p.tok == token.COMMA {
+		p.next();
+		list.Push(p.parseIdent());
+	}
+
+	// convert vector
+	idents := make([]*ast.Ident, list.Len());
+	for i := 0; i < list.Len(); i++ {
+		idents[i] = list.At(i).(*ast.Ident);
+	}
+
+	return idents;
+}
+
+
+func (p *parser) parseExpressionList() []ast.Expr {
+	if p.trace {
+		defer un(trace(p, "ExpressionList"));
+	}
+
+	list := vector.New(0);
+	list.Push(p.parseExpression());
+	for p.tok == token.COMMA {
+		p.next();
+		list.Push(p.parseExpression());
+	}
+
+	// convert list
+	exprs := make([]ast.Expr, list.Len());
+	for i := 0; i < list.Len(); i++ {
+		exprs[i] = list.At(i).(ast.Expr);
+	}
+
+	return exprs;
+}
+
+
+// ----------------------------------------------------------------------------
+// Types
+
+func (p *parser) parseType() ast.Expr {
+	if p.trace {
+		defer un(trace(p, "Type"));
+	}
+
+	typ := p.tryType();
+
+	if typ == nil {
+		p.error_expected(p.pos, "type");
+		p.next();  // make progress
+		return &ast.BadExpr{p.pos};
+	}
+
+	return typ;
+}
+
+
+func (p *parser) parseQualifiedIdent() ast.Expr {
+	if p.trace {
+		defer un(trace(p, "QualifiedIdent"));
+	}
+
+	var x ast.Expr = p.parseIdent();
+	if p.tok == token.PERIOD {
+		// first identifier is a package identifier
+		p.next();
+		sel := p.parseIdent();
+		x = &ast.SelectorExpr{x, sel};
+	}
+	return x;
+}
+
+
+func (p *parser) parseTypeName() ast.Expr {
+	if p.trace {
+		defer un(trace(p, "TypeName"));
+	}
+
+	return p.parseQualifiedIdent();
+}
+
+
+func (p *parser) parseArrayType(ellipsis_ok bool) ast.Expr {
+	if p.trace {
+		defer un(trace(p, "ArrayType"));
+	}
+
+	lbrack := p.expect(token.LBRACK);
+	var len ast.Expr;
+	if ellipsis_ok && p.tok == token.ELLIPSIS {
+		len = &ast.Ellipsis{p.pos};
+		p.next();
+	} else if p.tok != token.RBRACK {
+		len = p.parseExpression();
+	}
+	p.expect(token.RBRACK);
+	elt := p.parseType();
+
+	return &ast.ArrayType{lbrack, len, elt};
+}
+
+
+func (p *parser) makeIdentList(list *vector.Vector) []*ast.Ident {
+	idents := make([]*ast.Ident, list.Len());
+	for i := 0; i < list.Len(); i++ {
+		ident, is_ident := list.At(i).(*ast.Ident);
+		if !is_ident {
+			pos := list.At(i).(ast.Expr).Pos();
+			p.error_expected(pos, "identifier");
+			idents[i] = &ast.Ident{pos, ""};
+		}
+		idents[i] = ident;
+	}
+	return idents;
+}
+
+
+func (p *parser) parseFieldDecl() *ast.Field {
+	if p.trace {
+		defer un(trace(p, "FieldDecl"));
+	}
+
+	doc := p.getDoc();
+
+	// a list of identifiers looks like a list of type names
+	list := vector.New(0);
+	for {
+		// TODO do not allow ()'s here
+		list.Push(p.parseType());
+		if p.tok == token.COMMA {
+			p.next();
+		} else {
+			break;
+		}
+	}
+
+	// if we had a list of identifiers, it must be followed by a type
+	typ := p.tryType();
+
+	// optional tag
+	var tag []*ast.StringLit;
+	if p.tok == token.STRING {
+		tag = p.parseStringList(nil);
+	}
+
+	// analyze case
+	var idents []*ast.Ident;
+	if typ != nil {
+		// IdentifierList Type
+		idents = p.makeIdentList(list);
+	} else {
+		// Type (anonymous field)
+		if list.Len() == 1 {
+			// TODO check that this looks like a type
+			typ = list.At(0).(ast.Expr);
+		} else {
+			p.error_expected(p.pos, "anonymous field");
+			typ = &ast.BadExpr{p.pos};
+		}
+	}
+
+	return &ast.Field{doc, idents, typ, tag};
+}
+
+
+func (p *parser) parseStructType() *ast.StructType {
+	if p.trace {
+		defer un(trace(p, "StructType"));
+	}
+
+	pos := p.expect(token.STRUCT);
+	var lbrace, rbrace token.Position;
+	var fields []*ast.Field;
+	if p.tok == token.LBRACE {
+		lbrace = p.pos;
+		p.next();
+
+		list := vector.New(0);
+		for p.tok != token.RBRACE && p.tok != token.EOF {
+			list.Push(p.parseFieldDecl());
+			if p.tok == token.SEMICOLON {
+				p.next();
+			} else {
+				break;
+			}
+		}
+		if p.tok == token.SEMICOLON {
+			p.next();
+		}
+
+		rbrace = p.expect(token.RBRACE);
+		p.opt_semi = true;
+
+		// convert vector
+		fields = make([]*ast.Field, list.Len());
+		for i := list.Len() - 1; i >= 0; i-- {
+			fields[i] = list.At(i).(*ast.Field);
+		}
+	}
+
+	return &ast.StructType{pos, lbrace, fields, rbrace};
+}
+
+
+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) tryParameterType(ellipsis_ok bool) ast.Expr {
+	if ellipsis_ok && p.tok == token.ELLIPSIS {
+		pos := p.pos;
+		p.next();
+		if p.tok != token.RPAREN {
+			// "..." always must be at the very end of a parameter list
+			p.Error(pos, "expected type, found '...'");
+		}
+		return &ast.Ellipsis{pos};
+	}
+	return p.tryType();
+}
+
+
+func (p *parser) parseParameterType(ellipsis_ok bool) ast.Expr {
+	typ := p.tryParameterType(ellipsis_ok);
+	if typ == nil {
+		p.error_expected(p.pos, "type");
+		p.next();  // make progress
+		typ = &ast.BadExpr{p.pos};
+	}
+	return typ;
+}
+
+
+func (p *parser) parseParameterDecl(ellipsis_ok bool) (*vector.Vector, ast.Expr) {
+	if p.trace {
+		defer un(trace(p, "ParameterDecl"));
+	}
+
+	// a list of identifiers looks like a list of type names
+	list := vector.New(0);
+	for {
+		// TODO do not allow ()'s here
+		list.Push(p.parseParameterType(ellipsis_ok));
+		if p.tok == token.COMMA {
+			p.next();
+		} else {
+			break;
+		}
+	}
+
+	// if we had a list of identifiers, it must be followed by a type
+	typ := p.tryParameterType(ellipsis_ok);
+
+	return list, typ;
+}
+
+
+func (p *parser) parseParameterList(ellipsis_ok bool) []*ast.Field {
+	if p.trace {
+		defer un(trace(p, "ParameterList"));
+	}
+
+	list, typ := p.parseParameterDecl(ellipsis_ok);
+	if typ != nil {
+		// IdentifierList Type
+		idents := p.makeIdentList(list);
+		list.Init(0);
+		list.Push(&ast.Field{nil, idents, typ, nil});
+
+		for p.tok == token.COMMA {
+			p.next();
+			idents := p.parseIdentList(nil);
+			typ := p.parseParameterType(ellipsis_ok);
+			list.Push(&ast.Field{nil, idents, typ, nil});
+		}
+
+	} else {
+		// Type { "," Type } (anonymous parameters)
+		// convert list of types into list of *Param
+		for i := 0; i < list.Len(); i++ {
+			list.Set(i, &ast.Field{nil, nil, list.At(i).(ast.Expr), nil});
+		}
+	}
+
+	// convert list
+	params := make([]*ast.Field, list.Len());
+	for i := 0; i < list.Len(); i++ {
+		params[i] = list.At(i).(*ast.Field);
+	}
+
+	return params;
+}
+
+
+func (p *parser) parseParameters(ellipsis_ok bool) []*ast.Field {
+	if p.trace {
+		defer un(trace(p, "Parameters"));
+	}
+
+	var params []*ast.Field;
+	p.expect(token.LPAREN);
+	if p.tok != token.RPAREN {
+		params = p.parseParameterList(ellipsis_ok);
+	}
+	p.expect(token.RPAREN);
+
+	return params;
+}
+
+
+func (p *parser) parseResult() []*ast.Field {
+	if p.trace {
+		defer un(trace(p, "Result"));
+	}
+
+	var results []*ast.Field;
+	if p.tok == token.LPAREN {
+		results = p.parseParameters(false);
+	} else if p.tok != token.FUNC {
+		typ := p.tryType();
+		if typ != nil {
+			results = make([]*ast.Field, 1);
+			results[0] = &ast.Field{nil, nil, typ, nil};
+		}
+	}
+
+	return results;
+}
+
+
+func (p *parser) parseSignature() (params []*ast.Field, results []*ast.Field) {
+	if p.trace {
+		defer un(trace(p, "Signature"));
+	}
+
+	params = p.parseParameters(true);
+	results = p.parseResult();
+
+	return params, results;
+}
+
+
+func (p *parser) parseFuncType() *ast.FuncType {
+	if p.trace {
+		defer un(trace(p, "FuncType"));
+	}
+
+	pos := p.expect(token.FUNC);
+	params, results := p.parseSignature();
+
+	return &ast.FuncType{pos, params, results};
+}
+
+
+func (p *parser) parseMethodSpec() *ast.Field {
+	if p.trace {
+		defer un(trace(p, "MethodSpec"));
+	}
+
+	doc := p.getDoc();
+	var idents []*ast.Ident;
+	var typ ast.Expr;
+	x := p.parseQualifiedIdent();
+	if tmp, is_ident := x.(*ast.Ident); is_ident && (p.tok == token.COMMA || p.tok == token.LPAREN) {
+		// methods
+		idents = p.parseIdentList(x);
+		params, results := p.parseSignature();
+		typ = &ast.FuncType{noPos, params, results};
+	} else {
+		// embedded interface
+		typ = x;
+	}
+
+	return &ast.Field{doc, idents, typ, nil};
+}
+
+
+func (p *parser) parseInterfaceType() *ast.InterfaceType {
+	if p.trace {
+		defer un(trace(p, "InterfaceType"));
+	}
+
+	pos := p.expect(token.INTERFACE);
+	var lbrace, rbrace token.Position;
+	var methods []*ast.Field;
+	if p.tok == token.LBRACE {
+		lbrace = p.pos;
+		p.next();
+
+		list := vector.New(0);
+		for p.tok == token.IDENT {
+			list.Push(p.parseMethodSpec());
+			if p.tok != token.RBRACE {
+				p.expect(token.SEMICOLON);
+			}
+		}
+
+		rbrace = p.expect(token.RBRACE);
+		p.opt_semi = true;
+
+		// convert vector
+		methods = make([]*ast.Field, list.Len());
+		for i := list.Len() - 1; i >= 0; i-- {
+			methods[i] = list.At(i).(*ast.Field);
+		}
+	}
+
+	return &ast.InterfaceType{pos, lbrace, methods, rbrace};
+}
+
+
+func (p *parser) parseMapType() *ast.MapType {
+	if p.trace {
+		defer un(trace(p, "MapType"));
+	}
+
+	pos := p.expect(token.MAP);
+	p.expect(token.LBRACK);
+	key := p.parseType();
+	p.expect(token.RBRACK);
+	value := p.parseType();
+
+	return &ast.MapType{pos, key, value};
+}
+
+
+func (p *parser) parseChanType() *ast.ChanType {
+	if p.trace {
+		defer un(trace(p, "ChanType"));
+	}
+
+	pos := p.pos;
+	dir := ast.SEND | ast.RECV;
+	if p.tok == token.CHAN {
+		p.next();
+		if p.tok == token.ARROW {
+			p.next();
+			dir = ast.SEND;
+		}
+	} else {
+		p.expect(token.ARROW);
+		p.expect(token.CHAN);
+		dir = ast.RECV;
+	}
+	value := p.parseType();
+
+	return &ast.ChanType{pos, dir, value};
+}
+
+
+func (p *parser) tryRawType(ellipsis_ok bool) ast.Expr {
+	switch p.tok {
+	case token.IDENT: return p.parseTypeName();
+	case token.LBRACK: return p.parseArrayType(ellipsis_ok);
+	case token.STRUCT: return p.parseStructType();
+	case token.MUL: return p.parsePointerType();
+	case token.FUNC: return p.parseFuncType();
+	case token.INTERFACE: return p.parseInterfaceType();
+	case token.MAP: return p.parseMapType();
+	case token.CHAN, token.ARROW: return p.parseChanType();
+	case token.LPAREN:
+		lparen := p.pos;
+		p.next();
+		typ := p.parseType();
+		rparen := p.expect(token.RPAREN);
+		return &ast.ParenExpr{lparen, typ, rparen};
+	}
+
+	// no type found
+	return nil;
+}
+
+
+func (p *parser) tryType() ast.Expr {
+	return p.tryRawType(false);
+}
+
+
+// ----------------------------------------------------------------------------
+// Blocks
+
+func makeStmtList(list *vector.Vector) []ast.Stmt {
+	stats := make([]ast.Stmt, list.Len());
+	for i := 0; i < list.Len(); i++ {
+		stats[i] = list.At(i).(ast.Stmt);
+	}
+	return stats;
+}
+
+
+func (p *parser) parseStatementList() []ast.Stmt {
+	if p.trace {
+		defer un(trace(p, "StatementList"));
+	}
+
+	list := vector.New(0);
+	expect_semi := false;
+	for p.tok != token.CASE && p.tok != token.DEFAULT && p.tok != token.RBRACE && p.tok != token.EOF {
+		if expect_semi {
+			p.expect(token.SEMICOLON);
+			expect_semi = false;
+		}
+		list.Push(p.parseStatement());
+		if p.tok == token.SEMICOLON {
+			p.next();
+		} else if p.opt_semi {
+			p.opt_semi = false;  // "consume" optional semicolon
+		} else {
+			expect_semi = true;
+		}
+	}
+
+	return makeStmtList(list);
+}
+
+
+func (p *parser) parseBlockStmt() *ast.BlockStmt {
+	if p.trace {
+		defer un(trace(p, "BlockStmt"));
+	}
+
+	lbrace := p.expect(token.LBRACE);
+	list := p.parseStatementList();
+	rbrace := p.expect(token.RBRACE);
+	p.opt_semi = true;
+
+	return &ast.BlockStmt{lbrace, list, rbrace};
+}
+
+
+// ----------------------------------------------------------------------------
+// Expressions
+
+func (p *parser) parseStringList(x *ast.StringLit) []*ast.StringLit {
+	if p.trace {
+		defer un(trace(p, "StringList"));
+	}
+
+	list := vector.New(0);
+	if x != nil {
+		list.Push(x);
+	}
+
+	for p.tok == token.STRING {
+		list.Push(&ast.StringLit{p.pos, p.lit});
+		p.next();
+	}
+
+	// convert list
+	strings := make([]*ast.StringLit, list.Len());
+	for i := 0; i < list.Len(); i++ {
+		strings[i] = list.At(i).(*ast.StringLit);
+	}
+
+	return strings;
+}
+
+
+func (p *parser) parseFuncLit() ast.Expr {
+	if p.trace {
+		defer un(trace(p, "FuncLit"));
+	}
+
+	typ := p.parseFuncType();
+	p.expr_lev++;
+	body := p.parseBlockStmt();
+	p.opt_semi = false;  // function body requires separating ";"
+	p.expr_lev--;
+
+	return &ast.FuncLit{typ, body};
+}
+
+
+// parseOperand may return an expression or a raw type (incl. array
+// types of the form [...]T. Callers must verify the result.
+//
+func (p *parser) parseOperand() ast.Expr {
+	if p.trace {
+		defer un(trace(p, "Operand"));
+	}
+
+	switch p.tok {
+	case token.IDENT:
+		return p.parseIdent();
+
+	case token.INT:
+		x := &ast.IntLit{p.pos, p.lit};
+		p.next();
+		return x;
+
+	case token.FLOAT:
+		x := &ast.FloatLit{p.pos, p.lit};
+		p.next();
+		return x;
+
+	case token.CHAR:
+		x := &ast.CharLit{p.pos, p.lit};
+		p.next();
+		return x;
+
+	case token.STRING:
+		x := &ast.StringLit{p.pos, p.lit};
+		p.next();
+		if p.tok == token.STRING {
+			return &ast.StringList{p.parseStringList(x)};
+		}
+		return x;
+
+	case token.LPAREN:
+		lparen := p.pos;
+		p.next();
+		p.expr_lev++;
+		x := p.parseExpression();
+		p.expr_lev--;
+		rparen := p.expect(token.RPAREN);
+		return &ast.ParenExpr{lparen, x, rparen};
+
+	case token.FUNC:
+		return p.parseFuncLit();
+
+	default:
+		t := p.tryRawType(true);  // could be type for composite literal
+		if t != nil {
+			return t;
+		}
+	}
+
+	p.error_expected(p.pos, "operand");
+	p.next();  // make progress
+	return &ast.BadExpr{p.pos};
+}
+
+
+func (p *parser) parseSelectorOrTypeAssertion(x ast.Expr) ast.Expr {
+	if p.trace {
+		defer un(trace(p, "SelectorOrTypeAssertion"));
+	}
+
+	p.expect(token.PERIOD);
+	if p.tok == token.IDENT {
+		// selector
+		sel := p.parseIdent();
+		return &ast.SelectorExpr{x, sel};
+	}
+
+	// type assertion
+	p.expect(token.LPAREN);
+	var typ ast.Expr;
+	if p.tok == token.TYPE {
+		// special case for type switch
+		typ = &ast.Ident{p.pos, "type"};
+		p.next();
+	} else {
+		typ = p.parseType();
+	}
+	p.expect(token.RPAREN);
+
+	return &ast.TypeAssertExpr{x, typ};
+}
+
+
+func (p *parser) parseIndex(x ast.Expr) ast.Expr {
+	if p.trace {
+		defer un(trace(p, "Index"));
+	}
+
+	p.expect(token.LBRACK);
+	p.expr_lev++;
+	begin := p.parseExpression();
+	var end ast.Expr;
+	if p.tok == token.COLON {
+		p.next();
+		end = p.parseExpression();
+	}
+	p.expr_lev--;
+	p.expect(token.RBRACK);
+
+	return &ast.IndexExpr{x, begin, end};
+}
+
+
+func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
+	if p.trace {
+		defer un(trace(p, "CallOrConversion"));
+	}
+
+	lparen := p.expect(token.LPAREN);
+	var args []ast.Expr;
+	if p.tok != token.RPAREN {
+		args = p.parseExpressionList();
+	}
+	rparen := p.expect(token.RPAREN);
+
+	return &ast.CallExpr{fun, lparen, args, rparen};
+}
+
+
+func (p *parser) parseElement() ast.Expr {
+	if p.trace {
+		defer un(trace(p, "Element"));
+	}
+
+	x := p.parseExpression();
+	if p.tok == token.COLON {
+		colon := p.pos;
+		p.next();
+		x = &ast.KeyValueExpr{x, colon, p.parseExpression()};
+	}
+
+	return x;
+}
+
+
+func (p *parser) parseElementList() []ast.Expr {
+	if p.trace {
+		defer un(trace(p, "ElementList"));
+	}
+
+	list := vector.New(0);
+	for p.tok != token.RBRACE && p.tok != token.EOF {
+		list.Push(p.parseElement());
+		if p.tok == token.COMMA {
+			p.next();
+		} else {
+			break;
+		}
+	}
+
+	// convert list
+	elts := make([]ast.Expr, list.Len());
+	for i := 0; i < list.Len(); i++ {
+		elts[i] = list.At(i).(ast.Expr);
+	}
+
+	return elts;
+}
+
+
+func (p *parser) parseCompositeLit(typ ast.Expr) ast.Expr {
+	if p.trace {
+		defer un(trace(p, "CompositeLit"));
+	}
+
+	lbrace := p.expect(token.LBRACE);
+	var elts []ast.Expr;
+	if p.tok != token.RBRACE {
+		elts = p.parseElementList();
+	}
+	rbrace := p.expect(token.RBRACE);
+	return &ast.CompositeLit{typ, lbrace, elts, rbrace};
+}
+
+
+// TODO Consider different approach to checking syntax after parsing:
+//      Provide a arguments (set of flags) to parsing functions
+//      restricting what they are syupposed to accept depending
+//      on context.
+
+// checkExpr checks that x is an expression (and not a type).
+func (p *parser) checkExpr(x ast.Expr) ast.Expr {
+	// TODO should provide predicate in AST nodes
+	switch t := x.(type) {
+	case *ast.BadExpr:
+	case *ast.Ident:
+	case *ast.IntLit:
+	case *ast.FloatLit:
+	case *ast.CharLit:
+	case *ast.StringLit:
+	case *ast.StringList:
+	case *ast.FuncLit:
+	case *ast.CompositeLit:
+	case *ast.ParenExpr:
+	case *ast.SelectorExpr:
+	case *ast.IndexExpr:
+	case *ast.TypeAssertExpr:
+	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.error_expected(x.Pos(), "expression");
+			x = &ast.BadExpr{x.Pos()};
+		}
+	case *ast.BinaryExpr:
+	default:
+		// all other nodes are not proper expressions
+		p.error_expected(x.Pos(), "expression");
+		x = &ast.BadExpr{x.Pos()};
+	}
+	return x;
+}
+
+
+// isTypeName returns true iff x is type name.
+func isTypeName(x ast.Expr) bool {
+	// TODO should provide predicate in AST nodes
+	switch t := x.(type) {
+	case *ast.BadExpr:
+	case *ast.Ident:
+	case *ast.ParenExpr: return isTypeName(t.X);  // TODO should (TypeName) be illegal?
+	case *ast.SelectorExpr: return isTypeName(t.X);
+	default: return false;  // all other nodes are not type names
+	}
+	return true;
+}
+
+
+// isCompositeLitType returns true iff x is a legal composite literal type.
+func isCompositeLitType(x ast.Expr) bool {
+	// TODO should provide predicate in AST nodes
+	switch t := x.(type) {
+	case *ast.BadExpr:
+	case *ast.Ident:
+	case *ast.ParenExpr: return isCompositeLitType(t.X);
+	case *ast.SelectorExpr: return isTypeName(t.X);
+	case *ast.ArrayType:
+	case *ast.StructType:
+	case *ast.MapType:
+	default: return false;  // all other nodes are not legal composite literal types
+	}
+	return true;
+}
+
+
+// checkExprOrType checks that x is an expression or a type
+// (and not a raw type such as [...]T).
+//
+func (p *parser) checkExprOrType(x ast.Expr) ast.Expr {
+	// TODO should provide predicate in AST nodes
+	switch t := x.(type) {
+	case *ast.UnaryExpr:
+		if t.Op == token.RANGE {
+			// the range operator is only allowed at the top of a for statement
+			p.error_expected(x.Pos(), "expression");
+			x = &ast.BadExpr{x.Pos()};
+		}
+	case *ast.ArrayType:
+		if len, is_ellipsis := t.Len.(*ast.Ellipsis); is_ellipsis {
+			p.Error(len.Pos(), "expected array length, found '...'");
+			x = &ast.BadExpr{x.Pos()};
+		}
+	}
+
+	// all other nodes are expressions or types
+	return x;
+}
+
+
+func (p *parser) parsePrimaryExpr() ast.Expr {
+	if p.trace {
+		defer un(trace(p, "PrimaryExpr"));
+	}
+
+	x := p.parseOperand();
+L:	for {
+		switch p.tok {
+		case token.PERIOD: x = p.parseSelectorOrTypeAssertion(p.checkExpr(x));
+		case token.LBRACK: x = p.parseIndex(p.checkExpr(x));
+		case token.LPAREN: x = p.parseCallOrConversion(p.checkExprOrType(x));
+		case token.LBRACE:
+			if isCompositeLitType(x) && (p.expr_lev >= 0 || !isTypeName(x)) {
+				x = p.parseCompositeLit(x);
+			} else {
+				break L;
+			}
+		default:
+			break L;
+		}
+	}
+
+	return p.checkExprOrType(x);
+}
+
+
+func (p *parser) parseUnaryExpr() ast.Expr {
+	if p.trace {
+		defer un(trace(p, "UnaryExpr"));
+	}
+
+	switch p.tok {
+	case token.ADD, token.SUB, token.NOT, token.XOR, token.ARROW, token.AND, token.RANGE:
+		pos, op := p.pos, p.tok;
+		p.next();
+		x := p.parseUnaryExpr();
+		return &ast.UnaryExpr{pos, op, p.checkExpr(x)};
+
+	case token.MUL:
+		// unary "*" expression or pointer type
+		pos := p.pos;
+		p.next();
+		x := p.parseUnaryExpr();
+		return &ast.StarExpr{pos, p.checkExprOrType(x)};
+	}
+
+	return p.parsePrimaryExpr();
+}
+
+
+func (p *parser) parseBinaryExpr(prec1 int) ast.Expr {
+	if p.trace {
+		defer un(trace(p, "BinaryExpr"));
+	}
+
+	x := p.parseUnaryExpr();
+	for prec := p.tok.Precedence(); prec >= prec1; prec-- {
+		for p.tok.Precedence() == prec {
+			pos, op := p.pos, p.tok;
+			p.next();
+			y := p.parseBinaryExpr(prec + 1);
+			x = &ast.BinaryExpr{p.checkExpr(x), pos, op, p.checkExpr(y)};
+		}
+	}
+
+	return x;
+}
+
+
+func (p *parser) parseExpression() ast.Expr {
+	if p.trace {
+		defer un(trace(p, "Expression"));
+	}
+
+	return p.parseBinaryExpr(token.LowestPrec + 1);
+}
+
+
+// ----------------------------------------------------------------------------
+// Statements
+
+
+func (p *parser) parseSimpleStmt(label_ok bool) ast.Stmt {
+	if p.trace {
+		defer un(trace(p, "SimpleStmt"));
+	}
+
+	x := p.parseExpressionList();
+
+	switch p.tok {
+	case token.COLON:
+		// labeled statement
+		p.next();
+		if label_ok && len(x) == 1 {
+			if label, is_ident := x[0].(*ast.Ident); is_ident {
+				return &ast.LabeledStmt{label, p.parseStatement()};
+			}
+		}
+		p.Error(x[0].Pos(), "illegal label declaration");
+		return &ast.BadStmt{x[0].Pos()};
+
+	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.parseExpressionList();
+		if len(x) > 1 && len(y) > 1 && len(x) != len(y) {
+			p.Error(x[0].Pos(), "arity of lhs doesn't match rhs");
+		}
+		return &ast.AssignStmt{x, pos, tok, y};
+	}
+
+	if len(x) > 1 {
+		p.Error(x[0].Pos(), "only one expression allowed");
+		// continue with first expression
+	}
+
+	if p.tok == token.INC || p.tok == token.DEC {
+		// increment or decrement
+		s := &ast.IncDecStmt{x[0], p.tok};
+		p.next();  // consume "++" or "--"
+		return s;
+	}
+
+	// expression
+	return &ast.ExprStmt{x[0]};
+}
+
+
+func (p *parser) parseCallExpr() *ast.CallExpr {
+	x := p.parseExpression();
+	if call, is_call := x.(*ast.CallExpr); is_call {
+		return call;
+	}
+	p.error_expected(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();
+	if call != nil {
+		return &ast.GoStmt{pos, call};
+	}
+	return &ast.BadStmt{pos};
+}
+
+
+func (p *parser) parseDeferStmt() ast.Stmt {
+	if p.trace {
+		defer un(trace(p, "DeferStmt"));
+	}
+
+	pos := p.expect(token.DEFER);
+	call := p.parseCallExpr();
+	if call != nil {
+		return &ast.DeferStmt{pos, call};
+	}
+	return &ast.BadStmt{pos};
+}
+
+
+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.parseExpressionList();
+	}
+
+	return &ast.ReturnStmt{pos, x};
+}
+
+
+func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt {
+	if p.trace {
+		defer un(trace(p, "BranchStmt"));
+	}
+
+	s := &ast.BranchStmt{p.pos, tok, nil};
+	p.expect(tok);
+	if tok != token.FALLTHROUGH && p.tok == token.IDENT {
+		s.Label = p.parseIdent();
+	}
+
+	return s;
+}
+
+
+func (p *parser) isExpr(s ast.Stmt) bool {
+	if s == nil {
+		return true;
+	}
+	dummy, is_expr := s.(*ast.ExprStmt);
+	return is_expr;
+}
+
+
+func (p *parser) makeExpr(s ast.Stmt) ast.Expr {
+	if s == nil {
+		return nil;
+	}
+	if es, is_expr := s.(*ast.ExprStmt); is_expr {
+		return p.checkExpr(es.X);
+	}
+	p.Error(s.Pos(), "expected condition, found simple statement");
+	return &ast.BadExpr{s.Pos()};
+}
+
+
+func (p *parser) parseControlClause(isForStmt bool) (s1, s2, s3 ast.Stmt) {
+	if p.tok != token.LBRACE {
+		prev_lev := p.expr_lev;
+		p.expr_lev = -1;
+
+		if p.tok != token.SEMICOLON {
+			s1 = p.parseSimpleStmt(false);
+		}
+		if p.tok == token.SEMICOLON {
+			p.next();
+			if p.tok != token.LBRACE && p.tok != token.SEMICOLON {
+				s2 = p.parseSimpleStmt(false);
+			}
+			if isForStmt {
+				// for statements have a 3rd section
+				p.expect(token.SEMICOLON);
+				if p.tok != token.LBRACE {
+					s3 = p.parseSimpleStmt(false);
+				}
+			}
+		} else {
+			s1, s2 = nil, s1;
+		}
+
+		p.expr_lev = prev_lev;
+	}
+
+	return s1, s2, s3;
+}
+
+
+func (p *parser) parseIfStmt() *ast.IfStmt {
+	if p.trace {
+		defer un(trace(p, "IfStmt"));
+	}
+
+	pos := p.expect(token.IF);
+	s1, s2, dummy := p.parseControlClause(false);
+	body := p.parseBlockStmt();
+	var else_ ast.Stmt;
+	if p.tok == token.ELSE {
+		p.next();
+		else_ = p.parseStatement();
+	}
+
+	return &ast.IfStmt{pos, s1, p.makeExpr(s2), body, else_};
+}
+
+
+func (p *parser) parseCaseClause() *ast.CaseClause {
+	if p.trace {
+		defer un(trace(p, "CaseClause"));
+	}
+
+	// SwitchCase
+	pos := p.pos;
+	var x []ast.Expr;
+	if p.tok == token.CASE {
+		p.next();
+		x = p.parseExpressionList();
+	} else {
+		p.expect(token.DEFAULT);
+	}
+
+	colon := p.expect(token.COLON);
+	body := p.parseStatementList();
+
+	return &ast.CaseClause{pos, x, colon, body};
+}
+
+
+func (p *parser) parseTypeCaseClause() *ast.TypeCaseClause {
+	if p.trace {
+		defer un(trace(p, "CaseClause"));
+	}
+
+	// TypeSwitchCase
+	pos := p.pos;
+	var typ ast.Expr;
+	if p.tok == token.CASE {
+		p.next();
+		typ = p.parseType();
+	} else {
+		p.expect(token.DEFAULT);
+	}
+
+	colon := p.expect(token.COLON);
+	body := p.parseStatementList();
+
+	return &ast.TypeCaseClause{pos, typ, colon, body};
+}
+
+
+func (p *parser) parseSwitchStmt() ast.Stmt {
+	if p.trace {
+		defer un(trace(p, "SwitchStmt"));
+	}
+
+	pos := p.expect(token.SWITCH);
+	s1, s2, dummy := p.parseControlClause(false);
+
+	if p.isExpr(s2) {
+		// expression switch
+		lbrace := p.expect(token.LBRACE);
+		cases := vector.New(0);
+		for p.tok == token.CASE || p.tok == token.DEFAULT {
+			cases.Push(p.parseCaseClause());
+		}
+		rbrace := p.expect(token.RBRACE);
+		p.opt_semi = true;
+		body := &ast.BlockStmt{lbrace, makeStmtList(cases), rbrace};
+		return &ast.SwitchStmt{pos, s1, p.makeExpr(s2), body};
+	}
+
+	// type switch
+	// TODO do all the checks!
+	lbrace := p.expect(token.LBRACE);
+	cases := vector.New(0);
+	for p.tok == token.CASE || p.tok == token.DEFAULT {
+		cases.Push(p.parseTypeCaseClause());
+	}
+	rbrace := p.expect(token.RBRACE);
+	p.opt_semi = true;
+	body := &ast.BlockStmt{lbrace, makeStmtList(cases), rbrace};
+	return &ast.TypeSwitchStmt{pos, s1, s2, body};
+}
+
+
+func (p *parser) parseCommClause() *ast.CommClause {
+	if p.trace {
+		defer un(trace(p, "CommClause"));
+	}
+
+	// CommCase
+	pos := p.pos;
+	var tok token.Token;
+	var lhs, rhs ast.Expr;
+	if p.tok == token.CASE {
+		p.next();
+		if p.tok == token.ARROW {
+			// RecvExpr without assignment
+			rhs = p.parseExpression();
+		} else {
+			// SendExpr or RecvExpr
+			rhs = p.parseExpression();
+			if p.tok == token.ASSIGN || p.tok == token.DEFINE {
+				// RecvExpr with assignment
+				tok = p.tok;
+				p.next();
+				lhs = rhs;
+				if p.tok == token.ARROW {
+					rhs = p.parseExpression();
+				} else {
+					p.expect(token.ARROW);  // use expect() error handling
+				}
+			}
+			// else SendExpr
+		}
+	} else {
+		p.expect(token.DEFAULT);
+	}
+
+	colon := p.expect(token.COLON);
+	body := p.parseStatementList();
+
+	return &ast.CommClause{pos, tok, lhs, rhs, colon, body};
+}
+
+
+func (p *parser) parseSelectStmt() *ast.SelectStmt {
+	if p.trace {
+		defer un(trace(p, "SelectStmt"));
+	}
+
+	pos := p.expect(token.SELECT);
+	lbrace := p.expect(token.LBRACE);
+	cases := vector.New(0);
+	for p.tok == token.CASE || p.tok == token.DEFAULT {
+		cases.Push(p.parseCommClause());
+	}
+	rbrace := p.expect(token.RBRACE);
+	p.opt_semi = true;
+	body := &ast.BlockStmt{lbrace, makeStmtList(cases), rbrace};
+
+	return &ast.SelectStmt{pos, body};
+}
+
+
+func (p *parser) parseForStmt() ast.Stmt {
+	if p.trace {
+		defer un(trace(p, "ForStmt"));
+	}
+
+	pos := p.expect(token.FOR);
+	s1, s2, s3 := p.parseControlClause(true);
+	body := p.parseBlockStmt();
+
+	if as, is_as := s2.(*ast.AssignStmt); is_as {
+		// possibly a for statement with a range clause; check assignment operator
+		if as.Tok != token.ASSIGN && as.Tok != token.DEFINE {
+			p.error_expected(as.TokPos, "'=' or ':='");
+			return &ast.BadStmt{pos};
+		}
+		// check lhs
+		var key, value ast.Expr;
+		switch len(as.Lhs) {
+		case 2:
+			value = as.Lhs[1];
+			fallthrough;
+		case 1:
+			key = as.Lhs[0];
+		default:
+			p.error_expected(as.Lhs[0].Pos(), "1 or 2 expressions");
+			return &ast.BadStmt{pos};
+		}
+		// check rhs
+		if len(as.Rhs) != 1 {
+			p.error_expected(as.Rhs[0].Pos(), "1 expressions");
+			return &ast.BadStmt{pos};
+		}
+		if rhs, is_unary := as.Rhs[0].(*ast.UnaryExpr); is_unary && rhs.Op == token.RANGE {
+			// rhs is range expression; check lhs
+			return &ast.RangeStmt{pos, key, value, as.TokPos, as.Tok, rhs.X, body}
+		} else {
+			p.error_expected(s2.Pos(), "range clause");
+			return &ast.BadStmt{pos};
+		}
+	} else {
+		// regular for statement
+		return &ast.ForStmt{pos, s1, p.makeExpr(s2), s3, body};
+	}
+
+	panic();  // unreachable
+	return nil;
+}
+
+
+func (p *parser) parseStatement() ast.Stmt {
+	if p.trace {
+		defer un(trace(p, "Statement"));
+	}
+
+	switch p.tok {
+	case token.CONST, token.TYPE, token.VAR:
+		return &ast.DeclStmt{p.parseDeclaration()};
+	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:  // unary operators
+		return p.parseSimpleStmt(true);
+	case token.GO:
+		return p.parseGoStmt();
+	case token.DEFER:
+		return p.parseDeferStmt();
+	case token.RETURN:
+		return p.parseReturnStmt();
+	case token.BREAK, token.CONTINUE, token.GOTO, token.FALLTHROUGH:
+		return p.parseBranchStmt(p.tok);
+	case token.LBRACE:
+		return p.parseBlockStmt();
+	case token.IF:
+		return p.parseIfStmt();
+	case token.SWITCH:
+		return p.parseSwitchStmt();
+	case token.SELECT:
+		return p.parseSelectStmt();
+	case token.FOR:
+		return p.parseForStmt();
+	case token.SEMICOLON, token.RBRACE:
+		// don't consume the ";", it is the separator following the empty statement
+		return &ast.EmptyStmt{p.pos};
+	}
+
+	// no statement found
+	p.error_expected(p.pos, "statement");
+	p.next();  // make progress
+	return &ast.BadStmt{p.pos};
+}
+
+
+// ----------------------------------------------------------------------------
+// Declarations
+
+type parseSpecFunction func(p *parser, doc ast.Comments) ast.Spec
+
+func parseImportSpec(p *parser, doc ast.Comments) ast.Spec {
+	if p.trace {
+		defer un(trace(p, "ImportSpec"));
+	}
+
+	var ident *ast.Ident;
+	if p.tok == token.PERIOD {
+		ident = &ast.Ident{p.pos, "."};
+		p.next();
+	} else if p.tok == token.IDENT {
+		ident = p.parseIdent();
+	}
+
+	var path []*ast.StringLit;
+	if p.tok == token.STRING {
+		path = p.parseStringList(nil);
+	} else {
+		p.expect(token.STRING);  // use expect() error handling
+	}
+
+	return &ast.ImportSpec{doc, ident, path};
+}
+
+
+func parseConstSpec(p *parser, doc ast.Comments) ast.Spec {
+	if p.trace {
+		defer un(trace(p, "ConstSpec"));
+	}
+
+	idents := p.parseIdentList(nil);
+	typ := p.tryType();
+	var values []ast.Expr;
+	if typ != nil || p.tok == token.ASSIGN {
+		p.expect(token.ASSIGN);
+		values = p.parseExpressionList();
+	}
+
+	return &ast.ValueSpec{doc, idents, typ, values};
+}
+
+
+func parseTypeSpec(p *parser, doc ast.Comments) ast.Spec {
+	if p.trace {
+		defer un(trace(p, "TypeSpec"));
+	}
+
+	ident := p.parseIdent();
+	typ := p.parseType();
+
+	return &ast.TypeSpec{doc, ident, typ};
+}
+
+
+func parseVarSpec(p *parser, doc ast.Comments) ast.Spec {
+	if p.trace {
+		defer un(trace(p, "VarSpec"));
+	}
+
+	idents := p.parseIdentList(nil);
+	typ := p.tryType();
+	var values []ast.Expr;
+	if typ == nil || p.tok == token.ASSIGN {
+		p.expect(token.ASSIGN);
+		values = p.parseExpressionList();
+	}
+
+	return &ast.ValueSpec{doc, idents, typ, values};
+}
+
+
+func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.GenDecl {
+	if p.trace {
+		defer un(trace(p, keyword.String() + "Decl"));
+	}
+
+	doc := p.getDoc();
+	pos := p.expect(keyword);
+	var lparen, rparen token.Position;
+	list := vector.New(0);
+	if p.tok == token.LPAREN {
+		lparen = p.pos;
+		p.next();
+		for p.tok != token.RPAREN && p.tok != token.EOF {
+			doc := p.getDoc();
+			list.Push(f(p, doc));
+			if p.tok == token.SEMICOLON {
+				p.next();
+			} else {
+				break;
+			}
+		}
+		rparen = p.expect(token.RPAREN);
+		p.opt_semi = true;
+	} else {
+		list.Push(f(p, doc));
+	}
+
+	// convert vector
+	specs := make([]ast.Spec, list.Len());
+	for i := 0; i < list.Len(); i++ {
+		specs[i] = list.At(i);
+	}
+	return &ast.GenDecl{doc, pos, keyword, lparen, specs, rparen};
+}
+
+
+func (p *parser) parseReceiver() *ast.Field {
+	if p.trace {
+		defer un(trace(p, "Receiver"));
+	}
+
+	pos := p.pos;
+	par := p.parseParameters(false);
+
+	// must have exactly one receiver
+	if len(par) != 1 || len(par) == 1 && len(par[0].Names) > 1 {
+		p.error_expected(pos, "exactly one receiver");
+		return &ast.Field{nil, nil, &ast.BadExpr{noPos}, nil};
+	}
+
+	recv := par[0];
+
+	// recv type must be TypeName or *TypeName
+	base := recv.Type;
+	if ptr, is_ptr := base.(*ast.StarExpr); is_ptr {
+		base = ptr.X;
+	}
+	if !isTypeName(base) {
+		p.error_expected(base.Pos(), "type name");
+	}
+
+	return recv;
+}
+
+
+func (p *parser) parseFunctionDecl() *ast.FuncDecl {
+	if p.trace {
+		defer un(trace(p, "FunctionDecl"));
+	}
+
+	doc := p.getDoc();
+	pos := p.expect(token.FUNC);
+
+	var recv *ast.Field;
+	if p.tok == token.LPAREN {
+		recv = p.parseReceiver();
+	}
+
+	ident := p.parseIdent();
+	params, results := p.parseSignature();
+
+	var body *ast.BlockStmt;
+	if p.tok == token.LBRACE {
+		body = p.parseBlockStmt();
+	}
+
+	return &ast.FuncDecl{doc, recv, ident, &ast.FuncType{pos, params, results}, body};
+}
+
+
+func (p *parser) parseDeclaration() 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.parseFunctionDecl();
+	default:
+		pos := p.pos;
+		p.error_expected(pos, "declaration");
+		p.next();  // make progress
+		return &ast.BadDecl{pos};
+	}
+
+	return p.parseGenDecl(p.tok, f);
+}
+
+
+// ----------------------------------------------------------------------------
+// Packages
+
+// The mode parameter to the Parse function 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
+)
+
+
+func (p *parser) parsePackage() *ast.Program {
+	if p.trace {
+		defer un(trace(p, "Program"));
+	}
+
+	// package clause
+	comment := p.getDoc();
+	pos := p.expect(token.PACKAGE);
+	ident := p.parseIdent();
+	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.errors.Len() == 0 && p.mode & PackageClauseOnly == 0 {
+		// import decls
+		list := vector.New(0);
+		for p.tok == token.IMPORT {
+			list.Push(p.parseGenDecl(token.IMPORT, parseImportSpec));
+			if p.tok == token.SEMICOLON {
+				p.next();
+			}
+		}
+
+		if p.mode & ImportsOnly == 0 {
+			// rest of package body
+			for p.tok != token.EOF {
+				list.Push(p.parseDeclaration());
+				if p.tok == token.SEMICOLON {
+					p.next();
+				}
+			}
+		}
+
+		// convert declaration list
+		decls = make([]ast.Decl, list.Len());
+		for i := 0; i < list.Len(); i++ {
+			decls[i] = list.At(i).(ast.Decl);
+		}
+	}
+
+	// convert comments list
+	comments := make([]*ast.Comment, p.comments.Len());
+	for i := 0; i < p.comments.Len(); i++ {
+		comments[i] = p.comments.At(i).(*ast.Comment);
+	}
+
+	return &ast.Program{comment, pos, ident, decls, comments};
+}
+
+
+// ----------------------------------------------------------------------------
+// Parsing of entire programs.
+
+func readSource(src interface{}) ([]byte, os.Error) {
+	if src != nil {
+		switch s := src.(type) {
+		case string:
+			return io.StringBytes(s), nil;
+		case []byte:
+			return s, nil;
+		case *io.ByteBuffer:
+			// is io.Read, but src is already available in []byte form
+			if s != nil {
+				return s.Data(), nil;
+			}
+		case io.Reader:
+			var buf io.ByteBuffer;
+			n, err := io.Copy(s, &buf);
+			if err != nil {
+				return nil, err;
+			}
+			return buf.Data(), nil;
+		}
+	}
+	return nil, os.ErrorString("invalid source");
+}
+
+
+// scannerMode returns the scanner mode bits given the parser's mode bits.
+func scannerMode(mode uint) uint {
+	if mode & ParseComments != 0 {
+		return scanner.ScanComments;
+	}
+	return 0;
+}
+
+
+// Parse parses a Go program.
+//
+// The program source src may be provided in a variety of formats. At the
+// moment the following types are supported: string, []byte, and io.Read.
+// The mode parameter controls the amount of source text parsed and other
+// optional parser functionality.
+//
+// Parse returns a complete AST if no error occured. Otherwise, if the
+// source couldn't be read, the returned program 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) and an ErrorList
+// describing the syntax errors.
+//
+func Parse(src interface{}, mode uint) (*ast.Program, os.Error) {
+	data, err := readSource(src);
+	if err != nil {
+		return nil, err;
+	}
+
+	// initialize parser state
+	var p parser;
+	p.errors.Init(0);
+	p.scanner.Init(data, &p, scannerMode(mode));
+	p.mode = mode;
+	p.trace = mode & Trace != 0;  // for convenience (p.trace is used frequently)
+	p.comments.Init(0);
+	p.next();
+
+	// parse program
+	prog := p.parsePackage();
+
+	// convert errors list, if any
+	if p.errors.Len() > 0 {
+		errors := make(ErrorList, p.errors.Len());
+		for i := 0; i < p.errors.Len(); i++ {
+			errors[i] = p.errors.At(i).(*Error);
+		}
+		return prog, errors;
+	}
+
+	return prog, nil;
+}
diff --git a/src/pkg/go/parser/parser_test.go b/src/pkg/go/parser/parser_test.go
new file mode 100644
index 000000000..887fcf80f
--- /dev/null
+++ b/src/pkg/go/parser/parser_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 parser
+
+import (
+	"go/ast";
+	"go/parser";
+	"os";
+	"testing";
+)
+
+
+var illegalInputs = []interface{} {
+	nil,
+	3.14,
+	[]byte(nil),
+	"foo!",
+}
+
+
+func TestParseIllegalInputs(t *testing.T) {
+	for _, src := range illegalInputs {
+		prog, err := Parse(src, 0);
+		if err == nil {
+			t.Errorf("Parse(%v) should have failed", src);
+		}
+	}
+}
+
+
+var validPrograms = []interface{} {
+	`package main`,
+	`package main import "fmt" func main() { fmt.Println("Hello, World!") }`,
+}
+
+
+func TestParseValidPrograms(t *testing.T) {
+	for _, src := range validPrograms {
+		prog, err := Parse(src, 0);
+		if err != nil {
+			t.Errorf("Parse(%q) failed: %v", src, err);
+		}
+	}
+}
+
+
+var validFiles = []string {
+	"parser.go",
+	"parser_test.go",
+}
+
+
+func TestParse3(t *testing.T) {
+	for _, filename := range validFiles {
+		src, err := os.Open(filename, os.O_RDONLY, 0);
+		defer src.Close();
+		if err != nil {
+			t.Fatalf("os.Open(%s): %v\n", filename, err);
+		}
+
+		prog, err := Parse(src, 0);
+		if err != nil {
+			t.Errorf("Parse(%q): %v", src, err);
+		}
+	}
+}
diff --git a/src/pkg/go/scanner/Makefile b/src/pkg/go/scanner/Makefile
new file mode 100644
index 000000000..d47fecb7c
--- /dev/null
+++ b/src/pkg/go/scanner/Makefile
@@ -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.
+
+# DO NOT EDIT.  Automatically generated by gobuild.
+# gobuild -m >Makefile
+
+D=/go/
+
+include $(GOROOT)/src/Make.$(GOARCH)
+AR=gopack
+
+default: packages
+
+clean:
+	rm -rf *.[$(OS)] *.a [$(OS)].out _obj
+
+test: packages
+	gotest
+
+coverage: packages
+	gotest
+	6cov -g `pwd` | grep -v '_test\.go:'
+
+%.$O: %.go
+	$(GC) -I_obj $*.go
+
+%.$O: %.c
+	$(CC) $*.c
+
+%.$O: %.s
+	$(AS) $*.s
+
+O1=\
+	scanner.$O\
+
+
+phases: a1
+_obj$D/scanner.a: phases
+
+a1: $(O1)
+	$(AR) grc _obj$D/scanner.a scanner.$O
+	rm -f $(O1)
+
+
+newpkg: clean
+	mkdir -p _obj$D
+	$(AR) grc _obj$D/scanner.a
+
+$(O1): newpkg
+$(O2): a1
+
+nuke: clean
+	rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/scanner.a
+
+packages: _obj$D/scanner.a
+
+install: packages
+	test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D
+	cp _obj$D/scanner.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/scanner.a
diff --git a/src/pkg/go/scanner/scanner.go b/src/pkg/go/scanner/scanner.go
new file mode 100644
index 000000000..a90e6f259
--- /dev/null
+++ b/src/pkg/go/scanner/scanner.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.
+
+// A scanner for Go source text. Takes a []byte as source which can
+// then be tokenized through repeated calls to the Scan function.
+// For a sample use of a scanner, see the implementation of Tokenize.
+//
+package scanner
+
+import (
+	"go/token";
+	"strconv";
+	"unicode";
+	"utf8";
+)
+
+
+// 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);
+}
+
+
+// A Scanner holds the scanner's internal state while processing
+// a given text.  It can be allocated as part of another data
+// structure but must be initialized via Init before use. For
+// a sample use, see the implementation of Tokenize.
+//
+type Scanner struct {
+	// immutable state
+	src []byte;  // source
+	err ErrorHandler;  // error reporting; or nil
+	mode uint;  // scanning mode
+
+	// scanning state
+	pos token.Position;  // previous reading position (position before ch)
+	offset int;  // current reading offset (position after ch)
+	ch int;  // one char look-ahead
+
+	// 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.offset < len(S.src) {
+		S.pos.Offset = S.offset;
+		S.pos.Column++;
+		r, w := int(S.src[S.offset]), 1;
+		switch {
+		case r == '\n':
+			S.pos.Line++;
+			S.pos.Column = 0;
+		case r >= 0x80:
+			// not ASCII
+			r, w = utf8.DecodeRune(S.src[S.offset : len(S.src)]);
+		}
+		S.offset += w;
+		S.ch = r;
+	} else {
+		S.pos.Offset = len(S.src);
+		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
+)
+
+
+// Init prepares the scanner S to tokenize the text src. Calls to Scan
+// will use the error handler err if they encounter a syntax error and
+// err is not nil. Also, for each error encountered, the Scanner field
+// ErrorCount is incremented by one. The mode parameter determines how
+// comments and illegal characters are handled.
+//
+func (S *Scanner) Init(src []byte, err ErrorHandler, mode uint) {
+	// Explicitly initialize all fields since a scanner may be reused.
+	S.src = src;
+	S.err = err;
+	S.mode = mode;
+	S.pos = token.Position{0, 1, 0};
+	S.offset = 0;
+	S.ErrorCount = 0;
+	S.next();
+}
+
+
+func charString(ch int) string {
+	var s string;
+	switch ch {
+	case '\a': s = `\a`;
+	case '\b': s = `\b`;
+	case '\f': s = `\f`;
+	case '\n': s = `\n`;
+	case '\r': s = `\r`;
+	case '\t': s = `\t`;
+	case '\v': s = `\v`;
+	case '\\': s = `\\`;
+	case '\'': s = `\'`;
+	default  : s = string(ch);
+	}
+	return "'" + s + "' (U+" + strconv.Itob(ch, 16) + ")";
+}
+
+
+func (S *Scanner) error(pos token.Position, msg string) {
+	if S.err != nil {
+		S.err.Error(pos, msg);
+	}
+	S.ErrorCount++;
+}
+
+
+func (S *Scanner) expect(ch int) {
+	if S.ch != ch {
+		S.error(S.pos, "expected " + charString(ch) + ", found " + charString(S.ch));
+	}
+	S.next();  // always make progress
+}
+
+
+func (S *Scanner) scanComment(pos token.Position) {
+	// first '/' already consumed
+
+	if S.ch == '/' {
+		//-style comment
+		for S.ch >= 0 {
+			S.next();
+			if S.ch == '\n' {
+				S.next();  // '\n' belongs to the comment
+				return;
+			}
+		}
+
+	} else {
+		/*-style comment */
+		S.expect('*');
+		for S.ch >= 0 {
+			ch := S.ch;
+			S.next();
+			if ch == '*' && S.ch == '/' {
+				S.next();
+				return;
+			}
+		}
+	}
+
+	S.error(pos, "comment not terminated");
+}
+
+
+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.IsDecimalDigit(ch);
+}
+
+
+func (S *Scanner) scanIdentifier() token.Token {
+	pos := S.pos.Offset;
+	for isLetter(S.ch) || isDigit(S.ch) {
+		S.next();
+	}
+	return token.Lookup(S.src[pos : S.pos.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(seen_decimal_point bool) token.Token {
+	tok := token.INT;
+
+	if seen_decimal_point {
+		tok = token.FLOAT;
+		S.scanMantissa(10);
+		goto exponent;
+	}
+
+	if S.ch == '0' {
+		// int or float
+		S.next();
+		if S.ch == 'x' || S.ch == 'X' {
+			// hexadecimal int
+			S.next();
+			S.scanMantissa(16);
+		} else {
+			// octal int or float
+			S.scanMantissa(8);
+			if digitVal(S.ch) < 10 || S.ch == '.' || S.ch == 'e' || S.ch == 'E' {
+				// float
+				tok = token.FLOAT;
+				goto mantissa;
+			}
+			// octal int
+		}
+		goto exit;
+	}
+
+mantissa:
+	// decimal int or float
+	S.scanMantissa(10);
+
+	if S.ch == '.' {
+		// float
+		tok = token.FLOAT;
+		S.next();
+		S.scanMantissa(10)
+	}
+
+exponent:
+	if S.ch == 'e' || S.ch == 'E' {
+		// float
+		tok = token.FLOAT;
+		S.next();
+		if S.ch == '-' || S.ch == '+' {
+			S.next();
+		}
+		S.scanMantissa(10);
+	}
+
+exit:
+	return tok;
+}
+
+
+func (S *Scanner) scanDigits(base, length int) {
+	for length > 0 && digitVal(S.ch) < base {
+		S.next();
+		length--;
+	}
+	if length > 0 {
+		S.error(S.pos, "illegal char escape");
+	}
+}
+
+
+func (S *Scanner) scanEscape(quote int) {
+	pos := S.pos;
+	ch := S.ch;
+	S.next();
+	switch ch {
+	case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', quote:
+		// nothing to do
+	case '0', '1', '2', '3', '4', '5', '6', '7':
+		S.scanDigits(8, 3 - 1);  // 1 char read already
+	case 'x':
+		S.scanDigits(16, 2);
+	case 'u':
+		S.scanDigits(16, 4);
+	case 'U':
+		S.scanDigits(16, 8);
+	default:
+		S.error(pos, "illegal char escape");
+	}
+}
+
+
+func (S *Scanner) scanChar() {
+	// '\'' already consumed
+
+	ch := S.ch;
+	S.next();
+	if ch == '\\' {
+		S.scanEscape('\'');
+	}
+
+	S.expect('\'');
+}
+
+
+func (S *Scanner) scanString(pos token.Position) {
+	// '"' already consumed
+
+	for S.ch != '"' {
+		ch := S.ch;
+		S.next();
+		if ch == '\n' || ch < 0 {
+			S.error(pos, "string not terminated");
+			break;
+		}
+		if ch == '\\' {
+			S.scanEscape('"');
+		}
+	}
+
+	S.next();
+}
+
+
+func (S *Scanner) scanRawString(pos token.Position) {
+	// '`' already consumed
+
+	for S.ch != '`' {
+		ch := S.ch;
+		S.next();
+		if ch == '\n' || ch < 0 {
+			S.error(pos, "string not terminated");
+			break;
+		}
+	}
+
+	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 pos,
+// the token tok, and the literal text lit corresponding to the
+// token. The source end is indicated by token.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.
+//
+func (S *Scanner) Scan() (pos token.Position, tok token.Token, lit []byte) {
+scan_again:
+	// skip white space
+	for S.ch == ' ' || S.ch == '\t' || S.ch == '\n' || S.ch == '\r' {
+		S.next();
+	}
+
+	// current token start
+	pos, tok = S.pos, token.ILLEGAL;
+
+	// determine token value
+	switch ch := S.ch; {
+	case isLetter(ch):
+		tok = S.scanIdentifier();
+	case digitVal(ch) < 10:
+		tok = S.scanNumber(false);
+	default:
+		S.next();  // always make progress
+		switch ch {
+		case -1  : tok = token.EOF;
+		case '"' : tok = token.STRING; S.scanString(pos);
+		case '\'': tok = token.CHAR; S.scanChar();
+		case '`' : tok = token.STRING; S.scanRawString(pos);
+		case ':' : tok = S.switch2(token.COLON, token.DEFINE);
+		case '.' :
+			if digitVal(S.ch) < 10 {
+				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 ')': tok = token.RPAREN;
+		case '[': tok = token.LBRACK;
+		case ']': tok = token.RBRACK;
+		case '{': tok = token.LBRACE;
+		case '}': tok = token.RBRACE;
+		case '+': tok = S.switch3(token.ADD, token.ADD_ASSIGN, '+', token.INC);
+		case '-': tok = S.switch3(token.SUB, token.SUB_ASSIGN, '-', token.DEC);
+		case '*': tok = S.switch2(token.MUL, token.MUL_ASSIGN);
+		case '/':
+			if S.ch == '/' || S.ch == '*' {
+				S.scanComment(pos);
+				tok = token.COMMENT;
+				if S.mode & ScanComments == 0 {
+					goto scan_again;
+				}
+			} 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(pos, "illegal character " + charString(ch));
+			}
+		}
+	}
+
+	return pos, tok, S.src[pos.Offset : S.pos.Offset];
+}
+
+
+// Tokenize calls a function f with the token position, token value, and token
+// text for each token in the source src. The other parameters have the same
+// meaning as for the Init function. Tokenize keeps scanning until f returns
+// false (usually when the token value is token.EOF). The result is the number
+// of errors encountered.
+//
+func Tokenize(src []byte, err ErrorHandler, mode uint, f func (pos token.Position, tok token.Token, lit []byte) bool) int {
+	var s Scanner;
+	s.Init(src, err, mode);
+	for f(s.Scan()) {
+		// action happens in f
+	}
+	return s.ErrorCount;
+}
diff --git a/src/pkg/go/scanner/scanner_test.go b/src/pkg/go/scanner/scanner_test.go
new file mode 100644
index 000000000..0defece8b
--- /dev/null
+++ b/src/pkg/go/scanner/scanner_test.go
@@ -0,0 +1,276 @@
+// Copyright 2009 The Go Authors. 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/scanner";
+	"go/token";
+	"io";
+	"testing";
+)
+
+
+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
+	elt{ token.COMMENT, "/* a comment */", special },
+	elt{ token.COMMENT, "// a comment \n", special },
+
+	// Identifiers and basic type literals
+	elt{ token.IDENT, "foobar", literal },
+	elt{ token.IDENT, "a۰۱۸", literal },
+	elt{ token.IDENT, "foo६४", literal },
+	elt{ token.IDENT, "bar9876", literal },
+	elt{ token.INT, "0", literal },
+	elt{ token.INT, "01234567", literal },
+	elt{ token.INT, "0xcafebabe", literal },
+	elt{ token.FLOAT, "0.", literal },
+	elt{ token.FLOAT, ".0", literal },
+	elt{ token.FLOAT, "3.14159265", literal },
+	elt{ token.FLOAT, "1e0", literal },
+	elt{ token.FLOAT, "1e+100", literal },
+	elt{ token.FLOAT, "1e-100", literal },
+	elt{ token.FLOAT, "2.71828e-1000", literal },
+	elt{ token.CHAR, "'a'", literal },
+	elt{ token.CHAR, "'\\000'", literal },
+	elt{ token.CHAR, "'\\xFF'", literal },
+	elt{ token.CHAR, "'\\uff16'", literal },
+	elt{ token.CHAR, "'\\U0000ff16'", literal },
+	elt{ token.STRING, "`foobar`", literal },
+
+	// Operators and delimitors
+	elt{ token.ADD, "+", operator },
+	elt{ token.SUB, "-", operator },
+	elt{ token.MUL, "*", operator },
+	elt{ token.QUO, "/", operator },
+	elt{ token.REM, "%", operator },
+
+	elt{ token.AND, "&", operator },
+	elt{ token.OR, "|", operator },
+	elt{ token.XOR, "^", operator },
+	elt{ token.SHL, "<<", operator },
+	elt{ token.SHR, ">>", operator },
+	elt{ token.AND_NOT, "&^", operator },
+
+	elt{ token.ADD_ASSIGN, "+=", operator },
+	elt{ token.SUB_ASSIGN, "-=", operator },
+	elt{ token.MUL_ASSIGN, "*=", operator },
+	elt{ token.QUO_ASSIGN, "/=", operator },
+	elt{ token.REM_ASSIGN, "%=", operator },
+
+	elt{ token.AND_ASSIGN, "&=", operator },
+	elt{ token.OR_ASSIGN, "|=", operator },
+	elt{ token.XOR_ASSIGN, "^=", operator },
+	elt{ token.SHL_ASSIGN, "<<=", operator },
+	elt{ token.SHR_ASSIGN, ">>=", operator },
+	elt{ token.AND_NOT_ASSIGN, "&^=", operator },
+
+	elt{ token.LAND, "&&", operator },
+	elt{ token.LOR, "||", operator },
+	elt{ token.ARROW, "<-", operator },
+	elt{ token.INC, "++", operator },
+	elt{ token.DEC, "--", operator },
+
+	elt{ token.EQL, "==", operator },
+	elt{ token.LSS, "<", operator },
+	elt{ token.GTR, ">", operator },
+	elt{ token.ASSIGN, "=", operator },
+	elt{ token.NOT, "!", operator },
+
+	elt{ token.NEQ, "!=", operator },
+	elt{ token.LEQ, "<=", operator },
+	elt{ token.GEQ, ">=", operator },
+	elt{ token.DEFINE, ":=", operator },
+	elt{ token.ELLIPSIS, "...", operator },
+
+	elt{ token.LPAREN, "(", operator },
+	elt{ token.LBRACK, "[", operator },
+	elt{ token.LBRACE, "{", operator },
+	elt{ token.COMMA, ",", operator },
+	elt{ token.PERIOD, ".", operator },
+
+	elt{ token.RPAREN, ")", operator },
+	elt{ token.RBRACK, "]", operator },
+	elt{ token.RBRACE, "}", operator },
+	elt{ token.SEMICOLON, ";", operator },
+	elt{ token.COLON, ":", operator },
+
+	// Keywords
+	elt{ token.BREAK, "break", keyword },
+	elt{ token.CASE, "case", keyword },
+	elt{ token.CHAN, "chan", keyword },
+	elt{ token.CONST, "const", keyword },
+	elt{ token.CONTINUE, "continue", keyword },
+
+	elt{ token.DEFAULT, "default", keyword },
+	elt{ token.DEFER, "defer", keyword },
+	elt{ token.ELSE, "else", keyword },
+	elt{ token.FALLTHROUGH, "fallthrough", keyword },
+	elt{ token.FOR, "for", keyword },
+
+	elt{ token.FUNC, "func", keyword },
+	elt{ token.GO, "go", keyword },
+	elt{ token.GOTO, "goto", keyword },
+	elt{ token.IF, "if", keyword },
+	elt{ token.IMPORT, "import", keyword },
+
+	elt{ token.INTERFACE, "interface", keyword },
+	elt{ token.MAP, "map", keyword },
+	elt{ token.PACKAGE, "package", keyword },
+	elt{ token.RANGE, "range", keyword },
+	elt{ token.RETURN, "return", keyword },
+
+	elt{ token.SELECT, "select", keyword },
+	elt{ token.STRUCT, "struct", keyword },
+	elt{ token.SWITCH, "switch", keyword },
+	elt{ token.TYPE, "type", keyword },
+	elt{ token.VAR, "var", keyword },
+}
+
+
+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;
+}
+
+
+// Verify that calling Scan() provides the correct results.
+func TestScan(t *testing.T) {
+	// make source
+	var src string;
+	for i, e := range tokens {
+		src += e.lit + whitespace;
+	}
+	whitespace_linecount := NewlineCount(whitespace);
+
+	// verify scan
+	index := 0;
+	eloc := token.Position{0, 1, 1};
+	nerrors := scanner.Tokenize(io.StringBytes(src), &TestErrorHandler{t}, scanner.ScanComments,
+		func (pos token.Position, tok token.Token, litb []byte) bool {
+			e := elt{token.EOF, "", special};
+			if index < len(tokens) {
+				e = tokens[index];
+			}
+			lit := string(litb);
+			if tok == token.EOF {
+				lit = "";
+				eloc.Column = 0;
+			}
+			if pos.Offset != eloc.Offset {
+				t.Errorf("bad position for %s: got %d, expected %d", lit, pos.Offset, eloc.Offset);
+			}
+			if pos.Line != eloc.Line {
+				t.Errorf("bad line for %s: got %d, expected %d", lit, pos.Line, eloc.Line);
+			}
+			if pos.Column!= eloc.Column {
+				t.Errorf("bad column for %s: got %d, expected %d", lit, pos.Column, eloc.Column);
+			}
+			if tok != e.tok {
+				t.Errorf("bad token for %s: got %s, expected %s", lit, tok.String(), e.tok.String());
+			}
+			if e.tok.IsLiteral() && lit != e.lit {
+				t.Errorf("bad literal for %s: got %s, expected %s", lit, lit, e.lit);
+			}
+			if tokenclass(tok) != e.class {
+				t.Errorf("bad class for %s: got %d, expected %d", lit, tokenclass(tok), e.class);
+			}
+			eloc.Offset += len(lit) + len(whitespace);
+			eloc.Line += NewlineCount(lit) + whitespace_linecount;
+			index++;
+			return tok != token.EOF;
+		}
+	);
+	if nerrors != 0 {
+		t.Errorf("found %d errors", nerrors);
+	}
+}
+
+
+// Verify that initializing the same scanner more then once works correctly.
+func TestInit(t *testing.T) {
+	var s scanner.Scanner;
+
+	// 1st init
+	s.Init(io.StringBytes("if true { }"), nil, 0);
+	s.Scan();  // if
+	s.Scan();  // true
+	pos, tok, lit := s.Scan();  // {
+	if tok != token.LBRACE {
+		t.Errorf("bad token: got %s, expected %s", tok.String(), token.LBRACE);
+	}
+
+	// 2nd init
+	s.Init(io.StringBytes("go true { ]"), nil, 0);
+	pos, tok, lit = 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.Scanner;
+
+	const src = "*?*$*@*";
+	s.Init(io.StringBytes(src), &TestErrorHandler{t}, scanner.AllowIllegalChars);
+	for offs, ch := range src {
+		pos, tok, lit := s.Scan();
+		if pos.Offset != offs {
+			t.Errorf("bad position for %s: got %d, expected %d", string(lit), pos.Offset, offs);
+		}
+		if tok == token.ILLEGAL && string(lit) != string(ch) {
+			t.Errorf("bad token: got %s, expected %s", string(lit), string(ch));
+		}
+	}
+
+	if s.ErrorCount != 0 {
+		t.Errorf("found %d errors", s.ErrorCount);
+	}
+}
diff --git a/src/pkg/go/token/Makefile b/src/pkg/go/token/Makefile
new file mode 100644
index 000000000..12ef2a4aa
--- /dev/null
+++ b/src/pkg/go/token/Makefile
@@ -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.
+
+# DO NOT EDIT.  Automatically generated by gobuild.
+# gobuild -m >Makefile
+
+D=/go/
+
+include $(GOROOT)/src/Make.$(GOARCH)
+AR=gopack
+
+default: packages
+
+clean:
+	rm -rf *.[$(OS)] *.a [$(OS)].out _obj
+
+test: packages
+	gotest
+
+coverage: packages
+	gotest
+	6cov -g `pwd` | grep -v '_test\.go:'
+
+%.$O: %.go
+	$(GC) -I_obj $*.go
+
+%.$O: %.c
+	$(CC) $*.c
+
+%.$O: %.s
+	$(AS) $*.s
+
+O1=\
+	token.$O\
+
+
+phases: a1
+_obj$D/token.a: phases
+
+a1: $(O1)
+	$(AR) grc _obj$D/token.a token.$O
+	rm -f $(O1)
+
+
+newpkg: clean
+	mkdir -p _obj$D
+	$(AR) grc _obj$D/token.a
+
+$(O1): newpkg
+$(O2): a1
+
+nuke: clean
+	rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/token.a
+
+packages: _obj$D/token.a
+
+install: packages
+	test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D
+	cp _obj$D/token.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/token.a
diff --git a/src/pkg/go/token/token.go b/src/pkg/go/token/token.go
new file mode 100644
index 000000000..a70a75a54
--- /dev/null
+++ b/src/pkg/go/token/token.go
@@ -0,0 +1,347 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package defines constants representing the lexical
+// tokens of the Go programming language and basic operations
+// on tokens (printing, predicates).
+//
+package token
+
+import "strconv"
+
+// Token is the set of lexical tokens of the Go programming language.
+type Token int
+
+// The list of tokens.
+const (
+	// Special tokens
+	ILLEGAL Token = iota;
+	EOF;
+	COMMENT;
+
+	// Identifiers and basic type literals
+	// (these tokens stand for classes of literals)
+	literal_beg;
+	IDENT;
+	INT;
+	FLOAT;
+	CHAR;
+	STRING;
+	literal_end;
+
+	// Operators and delimiters
+	operator_beg;
+	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;
+
+	// Keywords
+	keyword_beg;
+	BREAK;
+	CASE;
+	CHAN;
+	CONST;
+	CONTINUE;
+
+	DEFAULT;
+	DEFER;
+	ELSE;
+	FALLTHROUGH;
+	FOR;
+
+	FUNC;
+	GO;
+	GOTO;
+	IF;
+	IMPORT;
+
+	INTERFACE;
+	MAP;
+	PACKAGE;
+	RANGE;
+	RETURN;
+
+	SELECT;
+	STRUCT;
+	SWITCH;
+	TYPE;
+	VAR;
+	keyword_end;
+)
+
+
+// At the moment we have no array literal syntax that lets us describe
+// the index for each element - use a map for now to make sure they are
+// in sync.
+var tokens = map [Token] string {
+	ILLEGAL : "ILLEGAL",
+
+	EOF : "EOF",
+	COMMENT : "COMMENT",
+
+	IDENT : "IDENT",
+	INT : "INT",
+	FLOAT : "FLOAT",
+	CHAR : "CHAR",
+	STRING : "STRING",
+
+	ADD : "+",
+	SUB : "-",
+	MUL : "*",
+	QUO : "/",
+	REM : "%",
+
+	AND : "&",
+	OR : "|",
+	XOR : "^",
+	SHL : "<<",
+	SHR : ">>",
+	AND_NOT : "&^",
+
+	ADD_ASSIGN : "+=",
+	SUB_ASSIGN : "-=",
+	MUL_ASSIGN : "+=",
+	QUO_ASSIGN : "/=",
+	REM_ASSIGN : "%=",
+
+	AND_ASSIGN : "&=",
+	OR_ASSIGN : "|=",
+	XOR_ASSIGN : "^=",
+	SHL_ASSIGN : "<<=",
+	SHR_ASSIGN : ">>=",
+	AND_NOT_ASSIGN : "&^=",
+
+	LAND : "&&",
+	LOR : "||",
+	ARROW : "<-",
+	INC : "++",
+	DEC : "--",
+
+	EQL : "==",
+	LSS : "<",
+	GTR : ">",
+	ASSIGN : "=",
+	NOT : "!",
+
+	NEQ : "!=",
+	LEQ : "<=",
+	GEQ : ">=",
+	DEFINE : ":=",
+	ELLIPSIS : "...",
+
+	LPAREN : "(",
+	LBRACK : "[",
+	LBRACE : "{",
+	COMMA : ",",
+	PERIOD : ".",
+
+	RPAREN : ")",
+	RBRACK : "]",
+	RBRACE : "}",
+	SEMICOLON : ";",
+	COLON : ":",
+
+	BREAK : "break",
+	CASE : "case",
+	CHAN : "chan",
+	CONST : "const",
+	CONTINUE : "continue",
+
+	DEFAULT : "default",
+	DEFER : "defer",
+	ELSE : "else",
+	FALLTHROUGH : "fallthrough",
+	FOR : "for",
+
+	FUNC : "func",
+	GO : "go",
+	GOTO : "goto",
+	IF : "if",
+	IMPORT : "import",
+
+	INTERFACE : "interface",
+	MAP : "map",
+	PACKAGE : "package",
+	RANGE : "range",
+	RETURN : "return",
+
+	SELECT : "select",
+	STRUCT : "struct",
+	SWITCH : "switch",
+	TYPE : "type",
+	VAR : "var",
+}
+
+
+// String returns the string corresponding to the token tok.
+// For operators, delimiters, and keywords the string is the actual
+// token character sequence (e.g., for the token ADD, the string is
+// "+"). For all other tokens the string corresponds to the token
+// constant name (e.g. for the token IDENT, the string is "IDENT").
+//
+func (tok Token) String() string {
+	if str, exists := tokens[tok]; exists {
+		return str;
+	}
+	return "token(" + strconv.Itoa(int(tok)) + ")";
+}
+
+
+// A set of constants for precedence-based expression parsing.
+// Non-operators have lowest precedence, followed by operators
+// starting with precedence 1 up to unary operators. The highest
+// precedence corresponds serves as "catch-all" precedence for
+// selector, indexing, and other operator and delimiter tokens.
+//
+const (
+	LowestPrec = 0;  // non-operators
+	UnaryPrec = 7;
+	HighestPrec = 8;
+)
+
+
+// Precedence returns the operator precedence of the binary
+// operator op. If op is not a binary operator, the result
+// is LowestPrecedence.
+//
+func (op Token) Precedence() int {
+	switch op {
+	case LOR:
+		return 1;
+	case LAND:
+		return 2;
+	case ARROW:
+		return 3;
+	case EQL, NEQ, LSS, LEQ, GTR, GEQ:
+		return 4;
+	case ADD, SUB, OR, XOR:
+		return 5;
+	case MUL, QUO, REM, SHL, SHR, AND, AND_NOT:
+		return 6;
+	}
+	return LowestPrec;
+}
+
+
+var keywords map [string] Token;
+
+func init() {
+	keywords = make(map [string] Token);
+	for i := keyword_beg + 1; i < keyword_end; i++ {
+		keywords[tokens[i]] = i;
+	}
+}
+
+
+// Lookup maps an identifier to its keyword token or IDENT (if not a keyword).
+//
+func Lookup(ident []byte) Token {
+	// TODO Maps with []byte key are illegal because []byte does not
+	//      support == . Should find a more efficient solution eventually.
+	if tok, is_keyword := keywords[string(ident)]; is_keyword {
+		return tok;
+	}
+	return IDENT;
+}
+
+
+// Predicates
+
+// IsLiteral returns true for tokens corresponding to identifiers
+// and basic type literals; returns false otherwise.
+//
+func (tok Token) IsLiteral() bool {
+	return literal_beg < tok && tok < literal_end;
+}
+
+// IsOperator returns true for tokens corresponding to operators and
+// delimiters; returns false otherwise.
+//
+func (tok Token) IsOperator() bool {
+	return operator_beg < tok && tok < operator_end;
+}
+
+// IsKeyword returns true for tokens corresponding to keywords;
+// returns false otherwise.
+//
+func (tok Token) IsKeyword() bool {
+	return keyword_beg < tok && tok < keyword_end;
+}
+
+
+// Token source positions are represented by a Position value.
+// A Position is valid if the line number is > 0.
+//
+type Position struct {
+	Offset int;  // byte offset, starting at 0
+	Line int;  // line number, starting at 1
+	Column int;  // column number, starting at 1 (character count)
+}
+
+
+// Pos is an accessor method for anonymous Position fields.
+// It returns its receiver.
+//
+func (pos *Position) Pos() Position {
+	return *pos;
+}
+
+
+// IsValid returns true if the position is valid.
+func (pos *Position) IsValid() bool {
+	return pos.Line > 0
+}
diff --git a/src/pkg/hash/Makefile b/src/pkg/hash/Makefile
new file mode 100644
index 000000000..bdbb6f347
--- /dev/null
+++ b/src/pkg/hash/Makefile
@@ -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.
+
+# DO NOT EDIT.  Automatically generated by gobuild.
+# gobuild -m >Makefile
+
+D=
+
+include $(GOROOT)/src/Make.$(GOARCH)
+AR=gopack
+
+default: packages
+
+clean:
+	rm -rf *.[$(OS)] *.a [$(OS)].out _obj
+
+test: packages
+	gotest
+
+coverage: packages
+	gotest
+	6cov -g `pwd` | grep -v '_test\.go:'
+
+%.$O: %.go
+	$(GC) -I_obj $*.go
+
+%.$O: %.c
+	$(CC) $*.c
+
+%.$O: %.s
+	$(AS) $*.s
+
+O1=\
+	hash.$O\
+
+
+phases: a1
+_obj$D/hash.a: phases
+
+a1: $(O1)
+	$(AR) grc _obj$D/hash.a hash.$O
+	rm -f $(O1)
+
+
+newpkg: clean
+	mkdir -p _obj$D
+	$(AR) grc _obj$D/hash.a
+
+$(O1): newpkg
+$(O2): a1
+
+nuke: clean
+	rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/hash.a
+
+packages: _obj$D/hash.a
+
+install: packages
+	test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D
+	cp _obj$D/hash.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/hash.a
diff --git a/src/pkg/hash/adler32/Makefile b/src/pkg/hash/adler32/Makefile
new file mode 100644
index 000000000..134131259
--- /dev/null
+++ b/src/pkg/hash/adler32/Makefile
@@ -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.
+
+# DO NOT EDIT.  Automatically generated by gobuild.
+# gobuild -m >Makefile
+
+D=/hash/
+
+include $(GOROOT)/src/Make.$(GOARCH)
+AR=gopack
+
+default: packages
+
+clean:
+	rm -rf *.[$(OS)] *.a [$(OS)].out _obj
+
+test: packages
+	gotest
+
+coverage: packages
+	gotest
+	6cov -g `pwd` | grep -v '_test\.go:'
+
+%.$O: %.go
+	$(GC) -I_obj $*.go
+
+%.$O: %.c
+	$(CC) $*.c
+
+%.$O: %.s
+	$(AS) $*.s
+
+O1=\
+	adler32.$O\
+
+
+phases: a1
+_obj$D/adler32.a: phases
+
+a1: $(O1)
+	$(AR) grc _obj$D/adler32.a adler32.$O
+	rm -f $(O1)
+
+
+newpkg: clean
+	mkdir -p _obj$D
+	$(AR) grc _obj$D/adler32.a
+
+$(O1): newpkg
+$(O2): a1
+
+nuke: clean
+	rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/adler32.a
+
+packages: _obj$D/adler32.a
+
+install: packages
+	test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D
+	cp _obj$D/adler32.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/adler32.a
diff --git a/src/pkg/hash/adler32/adler32.go b/src/pkg/hash/adler32/adler32.go
new file mode 100644
index 000000000..fbf9177f8
--- /dev/null
+++ b/src/pkg/hash/adler32/adler32.go
@@ -0,0 +1,96 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements the 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 Hash32 computing the Adler-32 checksum.
+func New() hash.Hash32 {
+	d := new(digest);
+	d.Reset();
+	return d;
+}
+
+func (d *digest) Size() int {
+	return Size;
+}
+
+// Add p to the running checksum a, b.
+func update(a, b uint32, p []byte) (aa, bb uint32) {
+	for i := 0; i < len(p); i++ {
+		a += uint32(p[i]);
+		b += a;
+		// invariant: a <= b
+		if b > (0xffffffff - 255) / 2 {
+			a %= mod;
+			b %= mod;
+			// invariant: a < mod && b < mod
+		} else {
+			// invariant: a + b + 255 <= 2 * b + 255 <= 0xffffffff
+		}
+	}
+	return a, b;
+}
+
+// Return the 32-bit checksum corresponding to a, b.
+func finish(a, b uint32) uint32 {
+	if b >= mod {
+		a %= mod;
+		b %= mod;
+	}
+	return b<<16 | a;
+}
+
+func (d *digest) Write(p []byte) (nn int, err os.Error) {
+	d.a, d.b = update(d.a, d.b, p);
+	return len(p), nil;
+}
+
+func (d *digest) Sum32() uint32 {
+	return finish(d.a, d.b);
+}
+
+func (d *digest) Sum() []byte {
+	p := make([]byte, 4);
+	s := d.Sum32();
+	p[0] = byte(s>>24);
+	p[1] = byte(s>>16);
+	p[2] = byte(s>>8);
+	p[3] = byte(s);
+	return p;
+}
+
+// Checksum returns the Adler-32 checksum of data.
+func Checksum(data []byte) uint32 {
+	return finish(update(1, 0, data));
+}
diff --git a/src/pkg/hash/adler32/adler32_test.go b/src/pkg/hash/adler32/adler32_test.go
new file mode 100644
index 000000000..ce49a110b
--- /dev/null
+++ b/src/pkg/hash/adler32/adler32_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 adler32
+
+import (
+	"hash/adler32";
+	"io";
+	"testing";
+)
+
+type _Adler32Test struct {
+	out uint32;
+	in string;
+}
+
+var golden = []_Adler32Test {
+	_Adler32Test{ 0x1, "" },
+	_Adler32Test{ 0x620062, "a" },
+	_Adler32Test{ 0x12600c4, "ab" },
+	_Adler32Test{ 0x24d0127, "abc" },
+	_Adler32Test{ 0x3d8018b, "abcd" },
+	_Adler32Test{ 0x5c801f0, "abcde" },
+	_Adler32Test{ 0x81e0256, "abcdef" },
+	_Adler32Test{ 0xadb02bd, "abcdefg" },
+	_Adler32Test{ 0xe000325, "abcdefgh" },
+	_Adler32Test{ 0x118e038e, "abcdefghi" },
+	_Adler32Test{ 0x158603f8, "abcdefghij" },
+	_Adler32Test{ 0x3f090f02, "Discard medicine more than two years old." },
+	_Adler32Test{ 0x46d81477, "He who has a shady past knows that nice guys finish last." },
+	_Adler32Test{ 0x40ee0ee1, "I wouldn't marry him with a ten foot pole." },
+	_Adler32Test{ 0x16661315, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave" },
+	_Adler32Test{ 0x5b2e1480, "The days of the digital watch are numbered.  -Tom Stoppard" },
+	_Adler32Test{ 0x8c3c09ea, "Nepal premier won't resign." },
+	_Adler32Test{ 0x45ac18fd, "For every action there is an equal and opposite government program." },
+	_Adler32Test{ 0x53c61462, "His money is twice tainted: 'taint yours and 'taint mine." },
+	_Adler32Test{ 0x7e511e63, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977" },
+	_Adler32Test{ 0xe4801a6a, "It's a tiny change to the code and not completely disgusting. - Bob Manchek" },
+	_Adler32Test{ 0x61b507df, "size:  a.out:  bad magic" },
+	_Adler32Test{ 0xb8631171, "The major problem is with sendmail.  -Mark Horton" },
+	_Adler32Test{ 0x8b5e1904, "Give me a rock, paper and scissors and I will move the world.  CCFestoon" },
+	_Adler32Test{ 0x7cc6102b, "If the enemy is within range, then so are you." },
+	_Adler32Test{ 0x700318e7, "It's well we cannot hear the screams/That we create in others' dreams." },
+	_Adler32Test{ 0x1e601747, "You remind me of a TV show, but that's all right: I watch it anyway." },
+	_Adler32Test{ 0xb55b0b09, "C is as portable as Stonehedge!!" },
+	_Adler32Test{ 0x39111dd0, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley" },
+	_Adler32Test{ 0x91dd304f, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction.  Lewis-Randall Rule" },
+	_Adler32Test{ 0x2e5d1316, "How can you write a big system without C++?  -Paul Glick" },
+	_Adler32Test{ 0xd0201df6, "'Invariant assertions' is the most elegant programming technique!  -Tom Szymanski" },
+}
+
+func TestGolden(t *testing.T) {
+	for i := 0; i < len(golden); i++ {
+		g := golden[i];
+		c := New();
+		io.WriteString(c, g.in);
+		s := c.Sum32();
+		if s != g.out {
+			t.Errorf("adler32(%s) = 0x%x want 0x%x", g.in, s, g.out);
+			t.FailNow();
+		}
+	}
+}
+
diff --git a/src/pkg/hash/crc32/Makefile b/src/pkg/hash/crc32/Makefile
new file mode 100644
index 000000000..08d4f5e4e
--- /dev/null
+++ b/src/pkg/hash/crc32/Makefile
@@ -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.
+
+# DO NOT EDIT.  Automatically generated by gobuild.
+# gobuild -m >Makefile
+
+D=/hash/
+
+include $(GOROOT)/src/Make.$(GOARCH)
+AR=gopack
+
+default: packages
+
+clean:
+	rm -rf *.[$(OS)] *.a [$(OS)].out _obj
+
+test: packages
+	gotest
+
+coverage: packages
+	gotest
+	6cov -g `pwd` | grep -v '_test\.go:'
+
+%.$O: %.go
+	$(GC) -I_obj $*.go
+
+%.$O: %.c
+	$(CC) $*.c
+
+%.$O: %.s
+	$(AS) $*.s
+
+O1=\
+	crc32.$O\
+
+
+phases: a1
+_obj$D/crc32.a: phases
+
+a1: $(O1)
+	$(AR) grc _obj$D/crc32.a crc32.$O
+	rm -f $(O1)
+
+
+newpkg: clean
+	mkdir -p _obj$D
+	$(AR) grc _obj$D/crc32.a
+
+$(O1): newpkg
+$(O2): a1
+
+nuke: clean
+	rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/crc32.a
+
+packages: _obj$D/crc32.a
+
+install: packages
+	test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D
+	cp _obj$D/crc32.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/crc32.a
diff --git a/src/pkg/hash/crc32/crc32.go b/src/pkg/hash/crc32/crc32.go
new file mode 100644
index 000000000..22a0f68f6
--- /dev/null
+++ b/src/pkg/hash/crc32/crc32.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.
+
+// This package implements the 32-bit cyclic redundancy check, or CRC-32, checksum.
+// See http://en.wikipedia.org/wiki/Cyclic_redundancy_check for information.
+package crc32
+
+import (
+	"hash";
+	"os";
+)
+
+// The size of a CRC-32 checksum in bytes.
+const Size = 4;
+
+// Predefined polynomials.
+const (
+	// Far and away the most common CRC-32 polynomial.
+	// Used by ethernet (IEEE 802.3), v.42, fddi, gzip, zip, png, mpeg-2, ...
+	IEEE = 0xedb88320;
+
+	// Castagnoli's polynomial, used in iSCSI.
+	// Has better error detection characteristics than IEEE.
+	// http://dx.doi.org/10.1109/26.231911
+	Castagnoli = 0x82f63b78;
+
+	// Koopman's polynomial.
+	// Also has better error detection characteristics than IEEE.
+	// http://dx.doi.org/10.1109/DSN.2002.1028931
+	Koopman = 0xeb31d82e;
+)
+
+// Table is a 256-word table representing the polynomial for efficient processing.
+type Table [256]uint32
+
+// MakeTable returns the Table constructed from the specified polynomial.
+func MakeTable(poly uint32) *Table {
+	t := new(Table);
+	for i := 0; i < 256; i++ {
+		crc := uint32(i);
+		for j := 0; j < 8; j++ {
+			if crc&1 == 1 {
+				crc = (crc>>1) ^ poly;
+			} else {
+				crc >>= 1;
+			}
+		}
+		t[i] = crc;
+	}
+	return t;
+}
+
+// IEEETable is the table for the IEEE polynomial.
+var IEEETable = MakeTable(IEEE);
+
+// digest represents the partial evaluation of a checksum.
+type digest struct {
+	crc uint32;
+	tab *Table;
+}
+
+// New creates a new Hash 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 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 i := 0; i < len(p); i++ {
+		crc = tab[byte(crc) ^ p[i]] ^ (crc >> 8);
+	}
+	return ^crc;
+}
+
+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_test.go b/src/pkg/hash/crc32/crc32_test.go
new file mode 100644
index 000000000..c037da600
--- /dev/null
+++ b/src/pkg/hash/crc32/crc32_test.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 crc32
+
+import (
+	"hash/crc32";
+	"io";
+	"testing";
+)
+
+type _Crc32Test struct {
+	out uint32;
+	in string;
+}
+
+var golden = []_Crc32Test {
+	_Crc32Test{ 0x0, "" },
+	_Crc32Test{ 0xe8b7be43, "a" },
+	_Crc32Test{ 0x9e83486d, "ab" },
+	_Crc32Test{ 0x352441c2, "abc" },
+	_Crc32Test{ 0xed82cd11, "abcd" },
+	_Crc32Test{ 0x8587d865, "abcde" },
+	_Crc32Test{ 0x4b8e39ef, "abcdef" },
+	_Crc32Test{ 0x312a6aa6, "abcdefg" },
+	_Crc32Test{ 0xaeef2a50, "abcdefgh" },
+	_Crc32Test{ 0x8da988af, "abcdefghi" },
+	_Crc32Test{ 0x3981703a, "abcdefghij" },
+	_Crc32Test{ 0x6b9cdfe7, "Discard medicine more than two years old." },
+	_Crc32Test{ 0xc90ef73f, "He who has a shady past knows that nice guys finish last." },
+	_Crc32Test{ 0xb902341f, "I wouldn't marry him with a ten foot pole." },
+	_Crc32Test{ 0x42080e8, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave" },
+	_Crc32Test{ 0x154c6d11, "The days of the digital watch are numbered.  -Tom Stoppard" },
+	_Crc32Test{ 0x4c418325, "Nepal premier won't resign." },
+	_Crc32Test{ 0x33955150, "For every action there is an equal and opposite government program." },
+	_Crc32Test{ 0x26216a4b, "His money is twice tainted: 'taint yours and 'taint mine." },
+	_Crc32Test{ 0x1abbe45e, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977" },
+	_Crc32Test{ 0xc89a94f7, "It's a tiny change to the code and not completely disgusting. - Bob Manchek" },
+	_Crc32Test{ 0xab3abe14, "size:  a.out:  bad magic" },
+	_Crc32Test{ 0xbab102b6, "The major problem is with sendmail.  -Mark Horton" },
+	_Crc32Test{ 0x999149d7, "Give me a rock, paper and scissors and I will move the world.  CCFestoon" },
+	_Crc32Test{ 0x6d52a33c, "If the enemy is within range, then so are you." },
+	_Crc32Test{ 0x90631e8d, "It's well we cannot hear the screams/That we create in others' dreams." },
+	_Crc32Test{ 0x78309130, "You remind me of a TV show, but that's all right: I watch it anyway." },
+	_Crc32Test{ 0x7d0a377f, "C is as portable as Stonehedge!!" },
+	_Crc32Test{ 0x8c79fd79, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley" },
+	_Crc32Test{ 0xa20b7167, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction.  Lewis-Randall Rule" },
+	_Crc32Test{ 0x8e0bb443, "How can you write a big system without C++?  -Paul Glick" },
+}
+
+func TestGolden(t *testing.T) {
+	for i := 0; i < len(golden); i++ {
+		g := golden[i];
+		c := NewIEEE();
+		io.WriteString(c, g.in);
+		s := c.Sum32();
+		if s != g.out {
+			t.Errorf("crc32(%s) = 0x%x want 0x%x", g.in, s, g.out);
+			t.FailNow();
+		}
+	}
+}
+
diff --git a/src/pkg/hash/hash.go b/src/pkg/hash/hash.go
new file mode 100644
index 000000000..a7c08cfed
--- /dev/null
+++ b/src/pkg/hash/hash.go
@@ -0,0 +1,24 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package hash
+
+import "io";
+
+// Hash is the common interface implemented by all hash functions.
+// The Write method never returns an error.
+// Sum returns the bytes of integer hash codes in big-endian order.
+type Hash interface {
+	io.Writer;
+	Sum() []byte;
+	Reset();
+	Size() int;	// number of bytes Sum returns
+}
+
+// Hash32 is the common interface implemented by all 32-bit hash functions.
+type Hash32 interface {
+	Hash;
+	Sum32() uint32;
+}
+
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/http/Makefile b/src/pkg/http/Makefile
new file mode 100644
index 000000000..0a029497c
--- /dev/null
+++ b/src/pkg/http/Makefile
@@ -0,0 +1,85 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# DO NOT EDIT.  Automatically generated by gobuild.
+# gobuild -m >Makefile
+
+D=
+
+include $(GOROOT)/src/Make.$(GOARCH)
+AR=gopack
+
+default: packages
+
+clean:
+	rm -rf *.[$(OS)] *.a [$(OS)].out _obj
+
+test: packages
+	gotest
+
+coverage: packages
+	gotest
+	6cov -g `pwd` | grep -v '_test\.go:'
+
+%.$O: %.go
+	$(GC) -I_obj $*.go
+
+%.$O: %.c
+	$(CC) $*.c
+
+%.$O: %.s
+	$(AS) $*.s
+
+O1=\
+	status.$O\
+	url.$O\
+
+O2=\
+	request.$O\
+
+O3=\
+	server.$O\
+
+O4=\
+	fs.$O\
+
+
+phases: a1 a2 a3 a4
+_obj$D/http.a: phases
+
+a1: $(O1)
+	$(AR) grc _obj$D/http.a status.$O url.$O
+	rm -f $(O1)
+
+a2: $(O2)
+	$(AR) grc _obj$D/http.a request.$O
+	rm -f $(O2)
+
+a3: $(O3)
+	$(AR) grc _obj$D/http.a server.$O
+	rm -f $(O3)
+
+a4: $(O4)
+	$(AR) grc _obj$D/http.a fs.$O
+	rm -f $(O4)
+
+
+newpkg: clean
+	mkdir -p _obj$D
+	$(AR) grc _obj$D/http.a
+
+$(O1): newpkg
+$(O2): a1
+$(O3): a2
+$(O4): a3
+$(O5): a4
+
+nuke: clean
+	rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/http.a
+
+packages: _obj$D/http.a
+
+install: packages
+	test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D
+	cp _obj$D/http.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/http.a
diff --git a/src/pkg/http/fs.go b/src/pkg/http/fs.go
new file mode 100644
index 000000000..108734c47
--- /dev/null
+++ b/src/pkg/http/fs.go
@@ -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.
+
+// HTTP file system request handler
+
+package http
+
+import (
+	"fmt";
+	"http";
+	"io";
+	"os";
+	"path";
+	"strings";
+	"utf8";
+)
+
+// TODO this should be in a mime package somewhere
+var contentByExt = map[string] string {
+	".css":	"text/css",
+	".gif":	"image/gif",
+	".html":	"text/html; charset=utf-8",
+	".jpg":	"image/jpeg",
+	".js":	"application/x-javascript",
+	".png":	"image/png",
+}
+
+// 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 0x80 <= rune && rune <= 0x9F {
+			return false;
+		}
+		if rune < ' ' {
+			switch rune {
+			case '\n', '\r', '\t':
+				// okay
+			default:
+				// binary garbage
+				return false;
+			}
+		}
+		b = b[size:len(b)];
+	}
+	return true;
+}
+
+func dirList(c *Conn, f *os.File) {
+	fmt.Fprintf(c, "
\n");
+	for {
+		dirs, err := f.Readdir(100);
+		if err != nil || len(dirs) == 0 {
+			break
+		}
+		for i, d := range dirs {
+			name := d.Name;
+			if d.IsDirectory() {
+				name += "/"
+			}
+			// TODO htmlescape
+			fmt.Fprintf(c, "%s\n", name, name);
+		}
+	}
+	fmt.Fprintf(c, "
\n"); +} + + +func serveFileInternal(c *Conn, r *Request, name string, redirect bool) { + const indexPage = "/index.html"; + + // redirect to strip off any index.html + n := len(name) - len(indexPage); + if n >= 0 && name[n:len(name)] == indexPage { + http.Redirect(c, name[0:n+1], StatusMovedPermanently); + return; + } + + f, err := os.Open(name, os.O_RDONLY, 0); + if err != nil { + // TODO expose actual error? + NotFound(c, r); + return; + } + defer f.Close(); + + d, err1 := f.Stat(); + if err1 != nil { + // TODO expose actual error? + NotFound(c, 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] != '/' { + http.Redirect(c, url + "/", StatusMovedPermanently); + return; + } + } else { + if url[len(url)-1] == '/' { + http.Redirect(c, url[0:len(url)-1], StatusMovedPermanently); + return; + } + } + } + + // use contents of index.html for directory, if present + if d.IsDirectory() { + index := name + indexPage; + ff, err := os.Open(index, os.O_RDONLY, 0); + if err == nil { + defer ff.Close(); + dd, err := ff.Stat(); + if err == nil { + name = index; + d = dd; + f = ff; + } + } + } + + if d.IsDirectory() { + dirList(c, f); + return; + } + + // serve file + // use extension to find content type. + ext := path.Ext(name); + if ctype, ok := contentByExt[ext]; ok { + c.SetHeader("Content-Type", ctype); + } else { + // read first chunk to decide between utf-8 text and binary + var buf [1024]byte; + n, err := io.FullRead(f, &buf); + b := buf[0:n]; + if isText(b) { + c.SetHeader("Content-Type", "text-plain; charset=utf-8"); + } else { + c.SetHeader("Content-Type", "application/octet-stream"); // generic binary + } + c.Write(b); + } + io.Copy(f, c); +} + +// ServeFile replies to the request with the contents of the named file or directory. +func ServeFile(c *Conn, r *Request, name string) { + serveFileInternal(c, r, name, false); +} + +type fileHandler struct { + root string; + prefix string; +} + +// FileServer returns a handler that serves HTTP requests +// with the contents of the file system rooted at root. +// It strips prefix from the incoming requests before +// looking up the file name in the file system. +func FileServer(root, prefix string) Handler { + return &fileHandler{root, prefix}; +} + +func (f *fileHandler) ServeHTTP(c *Conn, r *Request) { + path := r.Url.Path; + if !strings.HasPrefix(path, f.prefix) { + NotFound(c, r); + return; + } + path = path[len(f.prefix):len(path)]; + serveFileInternal(c, r, f.root + "/" + path, true); +} + diff --git a/src/pkg/http/request.go b/src/pkg/http/request.go new file mode 100644 index 000000000..76dd6f30c --- /dev/null +++ b/src/pkg/http/request.go @@ -0,0 +1,413 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// HTTP Request reading and parsing. + +// The http package implements parsing of HTTP requests and URLs +// and provides an extensible HTTP server. +// +// In the future it should also implement parsing of HTTP replies +// and provide methods to fetch URLs via HTTP. +package http + +import ( + "bufio"; + "fmt"; + "http"; + "io"; + "os"; + "strconv"; + "strings"; +) + +const ( + maxLineLength = 1024; // assumed < bufio.DefaultBufSize + maxValueLength = 1024; + maxHeaderLines = 1024; +) + +// HTTP request parsing errors. +type ProtocolError struct { + os.ErrorString +} +var ( + LineTooLong = &ProtocolError{"http header line too long"}; + ValueTooLong = &ProtocolError{"http header value too long"}; + HeaderTooLong = &ProtocolError{"http header too long"}; + BadContentLength = &ProtocolError{"invalid content length"}; + ShortEntityBody = &ProtocolError{"entity body too short"}; + BadHeader = &ProtocolError{"malformed http header"}; + BadRequest = &ProtocolError{"invalid http request"}; + BadHTTPVersion = &ProtocolError{"unsupported http version"}; +) + +// A Request represents a parsed HTTP request header. +type Request struct { + Method string; // GET, POST, PUT, etc. + RawUrl string; // The raw URL given in the request. + Url *URL; // Parsed URL. + Proto string; // "HTTP/1.0" + ProtoMajor int; // 1 + ProtoMinor int; // 0 + + // A header mapping request lines to their values. + // If the header says + // + // Accept-Language: en-us + // accept-encoding: gzip, deflate + // Connection: keep-alive + // + // then + // + // Header = map[string]string{ + // "Accept-Encoding": "en-us", + // "Accept-Language": "gzip, deflate", + // "Connection": "keep-alive" + // } + // + // HTTP defines that header names are case-insensitive. + // The request parser implements this by canonicalizing the + // name, making the first character and any characters + // following a hyphen uppercase and the rest lowercase. + Header map[string] string; + + // The message body. + Body io.Reader; + + // Whether to close the connection after replying to this request. + Close bool; + + // The host on which the URL is sought. + // Per RFC 2616, this is either the value of the Host: header + // or the host name given in the URL itself. + Host string; + + // The referring URL, if sent in the request. + // + // Referer is misspelled as in the request itself, + // a mistake from the earliest days of HTTP. + // This value can also be fetched from the Header map + // as Header["Referer"]; the benefit of making it + // available as a structure field is that the compiler + // can diagnose programs that use the alternate + // (correct English) spelling req.Referrer but cannot + // diagnose programs that use Header["Referrer"]. + Referer string; + + // The User-Agent: header string, if sent in the request. + UserAgent string; +} + +// 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 +} + +// 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.ReadLineSlice('\n'); err != nil { + return nil, err + } + if len(p) >= maxLineLength { + return nil, LineTooLong + } + + // 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 +} + +// Read a key/value pair from b. +// A key/value has the form Key: Value\r\n +// and the Value can continue on multiple lines if each continuation line +// starts with a space. +func readKeyValue(b *bufio.Reader) (key, value string, err os.Error) { + line, e := readLineBytes(b); + if e != nil { + return "", "", e + } + if len(line) == 0 { + return "", "", nil + } + + // Scan first line for colon. + for i := 0; i < len(line); i++ { + switch line[i] { + case ' ': + // Key field has space - no good. + return "", "", BadHeader; + case ':': + key = string(line[0:i]); + // Skip initial space before value. + for i++; i < len(line); i++ { + if line[i] != ' ' { + break + } + } + value = string(line[i:len(line)]); + + // Look for extension lines, which must begin with space. + for { + var c byte; + + if c, e = b.ReadByte(); e != nil { + return "", "", e + } + if c != ' ' { + // Not leading space; stop. + b.UnreadByte(); + break + } + + // Eat leading space. + for c == ' ' { + if c, e = b.ReadByte(); e != nil { + return "", "", e + } + } + b.UnreadByte(); + + // Read the rest of the line and add to value. + if line, e = readLineBytes(b); e != nil { + return "", "", e + } + value += " " + string(line); + + if len(value) >= maxValueLength { + return "", "", ValueTooLong + } + } + return key, value, nil + } + } + + // Line ended before space or colon. + return "", "", BadHeader; +} + +// Convert decimal at s[i:len(s)] to integer, +// returning value, string position where the digits stopped, +// and whether there was a valid number (digits, not too big). +func atoi(s string, i int) (n, i1 int, ok bool) { + const Big = 1000000; + if i >= len(s) || s[i] < '0' || s[i] > '9' { + return 0, 0, false + } + n = 0; + for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ { + n = n*10 + int(s[i]-'0'); + if n > Big { + return 0, 0, false + } + } + return n, i, true +} + +// Parse HTTP version: "HTTP/1.2" -> (1, 2, true). +func parseHTTPVersion(vers string) (int, int, bool) { + if vers[0:5] != "HTTP/" { + return 0, 0, false + } + major, i, ok := atoi(vers, 5); + if !ok || i >= len(vers) || vers[i] != '.' { + return 0, 0, false + } + var minor int; + minor, i, ok = atoi(vers, i+1); + if !ok || i != len(vers) { + return 0, 0, false + } + return major, minor, true +} + +var cmap = make(map[string]string) + +// CanonicalHeaderKey returns the canonical format of the +// HTTP header key s. The canonicalization converts the first +// letter and any letter following a hyphen to upper case; +// the rest are converted to lowercase. For example, the +// canonical key for "accept-encoding" is "Accept-Encoding". +func CanonicalHeaderKey(s string) string { + if t, ok := cmap[s]; ok { + return t; + } + + // canonicalize: first letter upper case + // and upper case after each dash. + // (Host, User-Agent, If-Modified-Since). + // HTTP headers are ASCII only, so no Unicode issues. + a := io.StringBytes(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 = false; + if v == '-' { + upper = true; + } + } + t := string(a); + cmap[s] = t; + return t; +} + +// ReadRequest reads and parses a request from b. +func ReadRequest(b *bufio.Reader) (req *Request, err os.Error) { + req = new(Request); + + // First line: GET /index.html HTTP/1.0 + var s string; + if s, err = readLine(b); err != nil { + return nil, err + } + + var f []string; + if f = strings.Split(s, " "); len(f) != 3 { + return nil, BadRequest + } + 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, BadHTTPVersion + } + + if req.Url, err = ParseURL(req.RawUrl); err != nil { + return nil, err + } + + // Subsequent lines: Key: value. + nheader := 0; + req.Header = make(map[string] string); + for { + var key, value string; + if key, value, err = readKeyValue(b); err != nil { + return nil, err + } + if key == "" { + break + } + if nheader++; nheader >= maxHeaderLines { + return nil, HeaderTooLong + } + + key = CanonicalHeaderKey(key); + + // RFC 2616 says that if you send the same header key + // multiple times, it has to be semantically equivalent + // to concatenating the values separated by commas. + oldvalue, present := req.Header[key]; + if present { + req.Header[key] = oldvalue+","+value + } else { + req.Header[key] = value + } + } + + // RFC2616: Must treat + // GET /index.html HTTP/1.1 + // Host: www.google.com + // and + // GET http://www.google.com/index.html HTTP/1.1 + // Host: doesntmatter + // the same. In the second case, any Host line is ignored. + if v, present := req.Header["Host"]; present && req.Url.Host == "" { + req.Host = v + } + + // RFC2616: Should treat + // Pragma: no-cache + // like + // Cache-Control: no-cache + if v, present := req.Header["Pragma"]; present && v == "no-cache" { + if cc, presentcc := req.Header["Cache-Control"]; !presentcc { + req.Header["Cache-Control"] = "no-cache" + } + } + + // Determine whether to hang up after sending the reply. + if req.ProtoMajor < 1 || (req.ProtoMajor == 1 && req.ProtoMinor < 1) { + req.Close = true + } else if v, present := req.Header["Connection"]; present { + // TODO: Should split on commas, toss surrounding white space, + // and check each field. + if v == "close" { + req.Close = true + } + } + + // Pull out useful fields as a convenience to clients. + if v, present := req.Header["Referer"]; present { + req.Referer = v + } + if v, present := req.Header["User-Agent"]; present { + req.UserAgent = v + } + + // 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 + + // A message body exists when either Content-Length or Transfer-Encoding + // headers are present. TODO: Handle Transfer-Encoding. + if v, present := req.Header["Content-Length"]; present { + length, err := strconv.Btoui64(v, 10); + if err != nil { + return nil, BadContentLength + } + // TODO: limit the Content-Length. This is an easy DoS vector. + raw := make([]byte, length); + n, err := b.Read(raw); + if err != nil || uint64(n) < length { + return nil, ShortEntityBody + } + req.Body = io.NewByteReader(raw); + } + + return req, nil +} diff --git a/src/pkg/http/server.go b/src/pkg/http/server.go new file mode 100644 index 000000000..c1de5de78 --- /dev/null +++ b/src/pkg/http/server.go @@ -0,0 +1,575 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// HTTP server. See RFC 2616. + +// TODO(rsc): +// logging +// cgi support +// post support + +package http + +import ( + "bufio"; + "fmt"; + "http"; + "io"; + "log"; + "net"; + "os"; + "path"; + "strconv"; + "strings"; +) + +// Errors introduced by the HTTP server. +var ( + ErrWriteAfterFlush = os.NewError("Conn.Write called after Flush"); + ErrHijacked = os.NewError("Conn has been hijacked"); +) + +type Conn struct + +// Objects implemeting the Handler interface can be +// registered to serve a particular path or subtree +// in the HTTP server. +type Handler interface { + ServeHTTP(*Conn, *Request); +} + +// A Conn represents the server side of a single active HTTP connection. +type Conn struct { + RemoteAddr string; // network address of remote side + Req *Request; // current HTTP request + + rwc io.ReadWriteCloser; // i/o connection + buf *bufio.ReadWriter; // buffered rwc + handler Handler; // request handler + hijacked bool; // connection has been hijacked by handler + + // state for the current reply + closeAfterReply bool; // close connection after this reply + chunking bool; // using chunked transfer encoding for reply body + wroteHeader bool; // reply header has been written + header map[string] string; // reply header parameters + written int64; // number of bytes written in body + status int; // status code passed to WriteHeader +} + +// Create new connection from rwc. +func newConn(rwc io.ReadWriteCloser, raddr string, handler Handler) (c *Conn, err os.Error) { + c = new(Conn); + c.RemoteAddr = raddr; + c.handler = handler; + c.rwc = rwc; + br := bufio.NewReader(rwc); + bw := bufio.NewWriter(rwc); + c.buf = bufio.NewReadWriter(br, bw); + return c, nil +} + +func (c *Conn) SetHeader(hdr, val string) + +// Read next request from connection. +func (c *Conn) readRequest() (req *Request, err os.Error) { + if c.hijacked { + return nil, ErrHijacked + } + if req, err = ReadRequest(c.buf.Reader); err != nil { + return nil, err + } + + // Reset per-request connection state. + c.header = make(map[string] string); + c.wroteHeader = false; + c.Req = req; + + // Default output is HTML encoded in UTF-8. + c.SetHeader("Content-Type", "text/html; charset=utf-8"); + + if req.ProtoAtLeast(1, 1) { + // HTTP/1.1 or greater: use chunked transfer encoding + // to avoid closing the connection at EOF. + c.chunking = true; + c.SetHeader("Transfer-Encoding", "chunked"); + } else { + // HTTP version < 1.1: cannot do chunked transfer + // encoding, so signal EOF by closing connection. + // Could avoid closing the connection if there is + // a Content-Length: header in the response, + // but everyone who expects persistent connections + // does HTTP/1.1 now. + c.closeAfterReply = true; + c.chunking = false; + } + + return req, nil +} + +// SetHeader sets a header line in the eventual reply. +// For example, SetHeader("Content-Type", "text/html; charset=utf-8") +// will result in the header line +// +// Content-Type: text/html; charset=utf-8 +// +// being sent. UTF-8 encoded HTML is the default setting for +// Content-Type in this library, so users need not make that +// particular call. Calls to SetHeader after WriteHeader (or Write) +// are ignored. +func (c *Conn) SetHeader(hdr, val string) { + c.header[CanonicalHeaderKey(hdr)] = val; +} + +// WriteHeader sends an HTTP response header with status code. +// If WriteHeader is not called explicitly, the first call to Write +// will trigger an implicit WriteHeader(http.StatusOK). +// Thus explicit calls to WriteHeader are mainly used to +// send error codes. +func (c *Conn) WriteHeader(code int) { + if c.hijacked { + log.Stderr("http: Conn.WriteHeader on hijacked connection"); + return + } + if c.wroteHeader { + log.Stderr("http: multiple Conn.WriteHeader calls"); + return + } + c.wroteHeader = true; + c.status = code; + c.written = 0; + if !c.Req.ProtoAtLeast(1, 0) { + return + } + proto := "HTTP/1.0"; + if c.Req.ProtoAtLeast(1, 1) { + proto = "HTTP/1.1"; + } + codestring := strconv.Itoa(code); + text, ok := statusText[code]; + if !ok { + text = "status code " + codestring; + } + io.WriteString(c.buf, proto + " " + codestring + " " + text + "\r\n"); + for k,v := range c.header { + io.WriteString(c.buf, k + ": " + v + "\r\n"); + } + io.WriteString(c.buf, "\r\n"); +} + +// Write writes the data to the connection as part of an HTTP reply. +// If WriteHeader has not yet been called, Write calls WriteHeader(http.StatusOK) +// before writing the data. +func (c *Conn) Write(data []byte) (n int, err os.Error) { + if c.hijacked { + log.Stderr("http: Conn.Write on hijacked connection"); + return 0, ErrHijacked + } + if !c.wroteHeader { + c.WriteHeader(StatusOK); + } + if len(data) == 0 { + return 0, nil + } + + c.written += int64(len(data)); // ignoring errors, for errorKludge + + // TODO(rsc): if chunking happened after the buffering, + // then there would be fewer chunk headers. + // On the other hand, it would make hijacking more difficult. + if c.chunking { + fmt.Fprintf(c.buf, "%x\r\n", len(data)); // TODO(rsc): use strconv not fmt + } + n, err = c.buf.Write(data); + if err == nil && c.chunking { + if n != len(data) { + err = io.ErrShortWrite; + } + if err == nil { + io.WriteString(c.buf, "\r\n"); + } + } + + return n, err; +} + +// If this is an error reply (4xx or 5xx) +// and the handler wrote some data explaining the error, +// some browsers (i.e., Chrome, Internet Explorer) +// will show their own error instead unless the error is +// long enough. The minimum lengths used in those +// browsers are in the 256-512 range. +// Pad to 1024 bytes. +func errorKludge(c *Conn, req *Request) { + const min = 1024; + + // Is this an error? + if kind := c.status/100; kind != 4 && kind != 5 { + return; + } + + // Did the handler supply any info? Enough? + if c.written == 0 || c.written >= min { + return; + } + + // Is it text? ("Content-Type" is always in the map) + if s := c.header["Content-Type"]; len(s) < 5 || s[0:5] != "text/" { + return; + } + + // Is it a broken browser? + var msg string; + switch agent := req.UserAgent; { + case strings.Index(agent, "MSIE") >= 0: + msg = "Internet Explorer"; + case strings.Index(agent, "Chrome/") >= 0: + msg = "Chrome"; + default: + return; + } + msg += " would ignore this error page if this text weren't here.\n"; + io.WriteString(c, "\n"); + for c.written < min { + io.WriteString(c, msg); + } +} + +func (c *Conn) flush() { + if !c.wroteHeader { + c.WriteHeader(StatusOK); + } + errorKludge(c, c.Req); + if c.chunking { + io.WriteString(c.buf, "0\r\n"); + // trailer key/value pairs, followed by blank line + io.WriteString(c.buf, "\r\n"); + } + c.buf.Flush(); +} + +// Close the connection. +func (c *Conn) close() { + if c.buf != nil { + c.buf.Flush(); + c.buf = nil; + } + if c.rwc != nil { + c.rwc.Close(); + c.rwc = nil; + } +} + +// Serve a new connection. +func (c *Conn) serve() { + for { + req, err := c.readRequest(); + if err != nil { + break + } + // HTTP cannot have multiple simultaneous active requests. + // Until the server replies to this request, it can't read another, + // so we might as well run the handler in this goroutine. + c.handler.ServeHTTP(c, req); + if c.hijacked { + return; + } + c.flush(); + if c.closeAfterReply { + break; + } + } + c.close(); +} + +// Hijack lets the caller take over the connection. +// After a call to c.Hijack(), the HTTP server library +// will not do anything else with the connection. +// It becomes the caller's responsibility to manage +// and close the connection. +func (c *Conn) Hijack() (rwc io.ReadWriteCloser, buf *bufio.ReadWriter, err os.Error) { + if c.hijacked { + return nil, nil, ErrHijacked; + } + c.hijacked = true; + rwc = c.rwc; + buf = c.buf; + c.rwc = nil; + c.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(*Conn, *Request) + +// ServeHTTP calls f(c, req). +func (f HandlerFunc) ServeHTTP(c *Conn, req *Request) { + f(c, req); +} + +// Helper handlers + +// NotFound replies to the request with an HTTP 404 not found error. +func NotFound(c *Conn, req *Request) { + c.SetHeader("Content-Type", "text/plain; charset=utf-8"); + c.WriteHeader(StatusNotFound); + io.WriteString(c, "404 page not found\n"); +} + +// NotFoundHandler returns a simple request handler +// that replies to each request with a ``404 page not found'' reply. +func NotFoundHandler() Handler { + return HandlerFunc(NotFound) +} + +// Redirect replies to the request with a redirect to url, +// which may be a path relative to the request path. +func Redirect(c *Conn, url string, code int) { + // RFC2616 recommends that a short note "SHOULD" be included in the + // response because older user agents may not understand 301/307. + note := "" + statusText[code] + ".\n"; + if c.Req.Method == "POST" { + note = ""; + } + + u, err := ParseURL(url); + if err != nil { + goto finish + } + + // If url was relative, make absolute by + // combining with request path. + // The browser would probably do this for us, + // but doing it ourselves is more reliable. + + // NOTE(rsc): RFC 2616 says that the Location + // line must be an absolute URI, like + // "http://www.google.com/redirect/", + // not a path like "/redirect/". + // Unfortunately, we don't know what to + // put in the host name section to get the + // client to connect to us again, so we can't + // know the right absolute URI to send back. + // Because of this problem, no one pays attention + // to the RFC; they all send back just a new path. + // So do we. + oldpath := c.Req.Url.Path; + if oldpath == "" { // should not happen, but avoid a crash if it does + oldpath = "/" + } + if u.Scheme == "" { + // no leading http://server + if url == "" || url[0] != '/' { + // make relative path absolute + olddir, oldfile := path.Split(oldpath); + url = olddir + url; + } + + // clean up but preserve trailing slash + trailing := url[len(url) - 1] == '/'; + url = path.Clean(url); + if trailing && url[len(url) - 1] != '/' { + url += "/"; + } + } + +finish: + c.SetHeader("Location", url); + c.WriteHeader(code); + fmt.Fprintf(c, note, url); +} + +// Redirect to a fixed URL +type redirectHandler struct { + url string; + code int; +} +func (rh *redirectHandler) ServeHTTP(c *Conn, req *Request) { + Redirect(c, rh.url, rh.code); +} + +// RedirectHandler returns a request handler that redirects +// each request it receives to the given url using the given +// status code. +func RedirectHandler(url string, code int) Handler { + return &redirectHandler{ url, code } +} + +// ServeMux is an HTTP request multiplexer. +// It matches the URL of each incoming request against a list of registered +// patterns and calls the handler for the pattern that +// most closely matches the URL. +// +// Patterns named fixed paths, like "/favicon.ico", +// or subtrees, like "/images/" (note the trailing slash). +// Patterns must begin with /. +// Longer patterns take precedence over shorter ones, so that +// if there are handlers registered for both "/images/" +// and "/images/thumbnails/", the latter handler will be +// called for paths beginning "/images/thumbnails/" and the +// former will receiver requests for any other paths in the +// "/images/" subtree. +// +// In the future, the pattern syntax may be relaxed to allow +// an optional host-name at the beginning of the pattern, +// so that a handler might register for the two patterns +// "/codesearch" and "codesearch.google.com/" +// without taking over requests for http://www.google.com/. +// +// ServeMux also takes care of sanitizing the URL request path, +// redirecting any request containing . or .. elements to an +// equivalent .- and ..-free URL. +type ServeMux struct { + m map[string] Handler +} + +// NewServeMux allocates and returns a new ServeMux. +func NewServeMux() *ServeMux { + return &ServeMux{make(map[string] Handler)}; +} + +// DefaultServeMux is the default ServeMux used by Serve. +var DefaultServeMux = NewServeMux(); + +// Does path match pattern? +func pathMatch(pattern, path string) bool { + if len(pattern) == 0 { + // should not happen + return false + } + n := len(pattern); + if pattern[n-1] != '/' { + return pattern == path + } + return len(path) >= n && path[0:n] == pattern; +} + +// Return the canonical path for p, eliminating . and .. elements. +func cleanPath(p string) string { + if p == "" { + return "/"; + } + if p[0] != '/' { + p = "/" + p; + } + np := path.Clean(p); + // path.Clean removes trailing slash except for root; + // put the trailing slash back if necessary. + if p[len(p)-1] == '/' && np != "/" { + np += "/"; + } + return np; +} + +// ServeHTTP dispatches the request to the handler whose +// pattern most closely matches the request URL. +func (mux *ServeMux) ServeHTTP(c *Conn, req *Request) { + // Clean path to canonical form and redirect. + if p := cleanPath(req.Url.Path); p != req.Url.Path { + c.SetHeader("Location", p); + c.WriteHeader(StatusMovedPermanently); + return; + } + + // Most-specific (longest) pattern wins. + var h Handler; + var n = 0; + for k, v := range mux.m { + if !pathMatch(k, req.Url.Path) { + continue; + } + if h == nil || len(k) > n { + n = len(k); + h = v; + } + } + if h == nil { + h = NotFoundHandler(); + } + h.ServeHTTP(c, req); +} + +// Handle registers the handler for the given pattern. +func (mux *ServeMux) Handle(pattern string, handler Handler) { + if pattern == "" || pattern[0] != '/' { + panicln("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); + } +} + +// Handle registers the handler for the given pattern +// in the DefaultServeMux. +func Handle(pattern string, handler Handler) { + DefaultServeMux.Handle(pattern, handler); +} + +// Serve accepts incoming HTTP connections on the listener l, +// creating a new service thread for each. The service threads +// read requests and then call handler to reply to them. +// Handler is typically nil, in which case the DefaultServeMux is used. +func Serve(l net.Listener, handler Handler) os.Error { + if handler == nil { + handler = DefaultServeMux; + } + for { + rw, raddr, e := l.Accept(); + if e != nil { + return e + } + c, err := newConn(rw, raddr, handler); + if err != nil { + continue; + } + go c.serve(); + } + panic("not reached") +} + +// ListenAndServe listens on the TCP network address addr +// and then calls Serve with handler to handle requests +// on incoming connections. Handler is typically nil, +// in which case the DefaultServeMux is used. +// +// A trivial example server is: +// +// package main +// +// import ( +// "http"; +// "io"; +// ) +// +// // hello world, the web server +// func HelloServer(c *http.Conn, req *http.Request) { +// io.WriteString(c, "hello, world!\n"); +// } +// +// func main() { +// http.Handle("/hello", http.HandlerFunc(HelloServer)); +// err := http.ListenAndServe(":12345", nil); +// if err != nil { +// panic("ListenAndServe: ", err.String()) +// } +// } +func ListenAndServe(addr string, handler Handler) os.Error { + l, e := net.Listen("tcp", addr); + if e != nil { + return e + } + e = Serve(l, handler); + l.Close(); + return e +} + diff --git a/src/pkg/http/status.go b/src/pkg/http/status.go new file mode 100644 index 000000000..6d1c5ab28 --- /dev/null +++ b/src/pkg/http/status.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. + +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", +} + diff --git a/src/pkg/http/triv.go b/src/pkg/http/triv.go new file mode 100644 index 000000000..fc9501769 --- /dev/null +++ b/src/pkg/http/triv.go @@ -0,0 +1,159 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "bufio"; + "exvar"; + "flag"; + "fmt"; + "http"; + "io"; + "log"; + "net"; + "os"; + "strconv"; +) + + +// hello world, the web server +var helloRequests = exvar.NewInt("hello-requests"); +func HelloServer(c *http.Conn, req *http.Request) { + helloRequests.Add(1); + io.WriteString(c, "hello, world!\n"); +} + +// Simple counter server. POSTing to it will set the value. +type Counter struct { + n int; +} + +// This makes Counter satisfy the exvar.Var interface, so we can export +// it directly. +func (ctr *Counter) String() string { + return fmt.Sprintf("%d", ctr.n) +} + +func (ctr *Counter) ServeHTTP(c *http.Conn, req *http.Request) { + switch req.Method { + case "GET": + ctr.n++; + case "POST": + buf := new(io.ByteBuffer); + io.Copy(req.Body, buf); + body := string(buf.Data()); + if n, err := strconv.Atoi(body); err != nil { + fmt.Fprintf(c, "bad POST: %v\nbody: [%v]\n", err, body); + } else { + ctr.n = n; + fmt.Fprint(c, "counter reset\n"); + } + } + fmt.Fprintf(c, "counter = %d\n", ctr.n); +} + +// simple file server +var webroot = flag.String("root", "/home/rsc", "web root directory") +var pathVar = exvar.NewMap("file-requests"); +func FileServer(c *http.Conn, req *http.Request) { + c.SetHeader("content-type", "text/plain; charset=utf-8"); + pathVar.Add(req.Url.Path, 1); + path := *webroot + req.Url.Path; // TODO: insecure: use os.CleanName + f, err := os.Open(path, os.O_RDONLY, 0); + if err != nil { + c.WriteHeader(http.StatusNotFound); + fmt.Fprintf(c, "open %s: %v\n", path, err); + return; + } + n, err1 := io.Copy(f, c); + fmt.Fprintf(c, "[%d bytes]\n", n); + f.Close(); +} + +// simple flag server +var booleanflag = flag.Bool("boolean", true, "another flag for testing") +func FlagServer(c *http.Conn, req *http.Request) { + c.SetHeader("content-type", "text/plain; charset=utf-8"); + fmt.Fprint(c, "Flags:\n"); + flag.VisitAll(func (f *flag.Flag) { + if f.Value.String() != f.DefValue { + fmt.Fprintf(c, "%s = %s [default = %s]\n", f.Name, f.Value.String(), f.DefValue); + } else { + fmt.Fprintf(c, "%s = %s\n", f.Name, f.Value.String()); + } + }); +} + +// simple argument server +func ArgServer(c *http.Conn, req *http.Request) { + for i, s := range os.Args { + fmt.Fprint(c, 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(c *http.Conn, req *http.Request) { + io.WriteString(c, fmt.Sprintf("channel send #%d\n", <-ch)); +} + +// exec a program, redirecting output +func DateServer(c *http.Conn, req *http.Request) { + c.SetHeader("content-type", "text/plain; charset=utf-8"); + r, w, err := os.Pipe(); + if err != nil { + fmt.Fprintf(c, "pipe: %s\n", err); + return; + } + pid, err := os.ForkExec("/bin/date", []string{"date"}, os.Environ(), "", []*os.File{nil, w, w}); + defer r.Close(); + w.Close(); + if err != nil { + fmt.Fprintf(c, "fork/exec: %s\n", err); + return; + } + io.Copy(r, c); + wait, err := os.Wait(pid, 0); + if err != nil { + fmt.Fprintf(c, "wait: %s\n", err); + return; + } + if !wait.Exited() || wait.ExitStatus() != 0 { + fmt.Fprintf(c, "date: %v\n", wait); + return; + } +} + +func main() { + flag.Parse(); + + // The counter is published as a variable directly. + ctr := new(Counter); + http.Handle("/counter", ctr); + exvar.Publish("counter", ctr); + + http.Handle("/go/", http.HandlerFunc(FileServer)); + 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.Crash("ListenAndServe: ", err) + } +} + diff --git a/src/pkg/http/url.go b/src/pkg/http/url.go new file mode 100644 index 000000000..0325b04ee --- /dev/null +++ b/src/pkg/http/url.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. + +// Parse URLs (actually URIs, but that seems overly pedantic). +// RFC 2396 + +package http + +import ( + "os"; + "strings" +) + +// Errors introduced by ParseURL. +type BadURL struct { + os.ErrorString +} + +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 +} + +// Return true if the specified character should be escaped when appearing in a +// URL string. +// +// TODO: for now, this is a hack; it only flags a few common characters that have +// special meaning in URLs. That will get the job done in the common cases. +func shouldEscape(c byte) bool { + switch c { + case ' ', '?', '&', '=', '#', '+', '%': + return true; + } + return false; +} + +// URLUnescape unescapes a URL-encoded string, +// converting %AB into the byte 0xAB and '+' into ' ' (space). +// It returns a BadURL error if any % is not followed +// by two hexadecimal digits. +func URLUnescape(s string) (string, os.Error) { + // Count %, check that they're well-formed. + n := 0; + anyPlusses := 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]) { + return "", BadURL{"invalid hexadecimal escape"} + } + i += 3; + case '+': + anyPlusses = true; + i++; + default: + i++ + } + } + + if n == 0 && !anyPlusses { + 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 '+': + t[j] = ' '; + j++; + i++; + default: + t[j] = s[i]; + j++; + i++; + } + } + return string(t), nil; +} + +// URLEscape converts a string into URL-encoded form. +func URLEscape(s string) string { + spaceCount, hexCount := 0, 0; + for i := 0; i < len(s); i++ { + c := s[i]; + if (shouldEscape(c)) { + if (c == ' ') { + 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++ { + c := s[i]; + if !shouldEscape(c) { + t[j] = s[i]; + j++; + } else if (c == ' ') { + t[j] = '+'; + j++; + } else { + t[j] = '%'; + t[j+1] = "0123456789abcdef"[c>>4]; + t[j+2] = "0123456789abcdef"[c&15]; + j += 3; + } + } + return string(t); +} + +// A URL represents a parsed URL (technically, a URI reference). +// The general form represented is: +// scheme://[userinfo@]host/path[?query][#fragment] +// The Raw, RawPath, and RawQuery fields are in "wire format" (special +// characters must be hex-escaped if not meant to have special meaning). +// All other fields are logical values; '+' or '%' represent themselves. +// +// Note, the reason for using wire format for the query is that it needs +// to be split into key/value pairs before decoding. +type URL struct { + Raw string; // the original string + Scheme string; // scheme + RawPath string; // //[userinfo@]host/path[?query][#fragment] + Authority string; // [userinfo@]host + Userinfo string; // userinfo + Host string; // host + Path string; // /path + 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 "", "", BadURL{"missing protocol scheme"} + } + return rawurl[0:i], rawurl[i+1:len(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:len(s)] + } + return s[0:i], s[i:len(s)] + } + } + return s, "" +} + +// BUG(rsc): ParseURL should canonicalize the path, +// removing unnecessary . and .. elements. + +// ParseURL parses rawurl into a URL structure. +// The string rawurl is assumed not to have a #fragment suffix. +// (Web browsers strip #fragment before sending the URL to a web server.) +func ParseURL(rawurl string) (url *URL, err os.Error) { + if rawurl == "" { + return nil, BadURL{"empty url"} + } + url = new(URL); + url.Raw = rawurl; + + // split off possible leading "http:", "mailto:", etc. + var path string; + if url.Scheme, path, err = getscheme(rawurl); err != nil { + return nil, err + } + url.RawPath = path; + + // RFC 2396: a relative URI (no scheme) has a ?query, + // but absolute URIs only have query if path begins with / + if url.Scheme == "" || len(path) > 0 && path[0] == '/' { + path, url.RawQuery = split(path, '?', true); + } + + // Maybe path is //authority/path + if len(path) > 2 && path[0:2] == "//" { + url.Authority, path = split(path[2:len(path)], '/', false); + } + + // If there's no @, split's default is wrong. Check explicitly. + if strings.Index(url.Authority, "@") < 0 { + url.Host = url.Authority; + } else { + url.Userinfo, url.Host = split(url.Authority, '@', true); + } + + // What's left is the path. + // TODO: Canonicalize (remove . and ..)? + if url.Path, err = URLUnescape(path); err != nil { + return nil, err + } + + // Remove escapes from the Authority and Userinfo fields, and verify + // that Scheme and Host contain no escapes (that would be illegal). + if url.Authority, err = URLUnescape(url.Authority); err != nil { + return nil, err + } + if url.Userinfo, err = URLUnescape(url.Userinfo); err != nil { + return nil, err + } + if (strings.Index(url.Scheme, "%") >= 0) { + return nil, BadURL{"hexadecimal escape in scheme"} + } + if (strings.Index(url.Host, "%") >= 0) { + return nil, BadURL{"hexadecimal escape in host"} + } + + return url, nil +} + +// ParseURLReference is like ParseURL but allows a trailing #fragment. +func ParseURLReference(rawurlref string) (url *URL, err os.Error) { + // Cut off #frag. + rawurl, frag := split(rawurlref, '#', true); + if url, err = ParseURL(rawurl); err != nil { + return nil, err + } + if url.Fragment, err = URLUnescape(frag); err != nil { + return nil, 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, Userinfo, +// RawQuery, and Fragment, but not Raw, RawPath or Authority. +func (url *URL) String() string { + result := ""; + if url.Scheme != "" { + result += url.Scheme + ":"; + } + if url.Host != "" || url.Userinfo != "" { + result += "//"; + if url.Userinfo != "" { + result += URLEscape(url.Userinfo) + "@"; + } + result += url.Host; + } + result += URLEscape(url.Path); + if url.RawQuery != "" { + result += "?" + url.RawQuery; + } + if url.Fragment != "" { + result += "#" + URLEscape(url.Fragment); + } + return result; +} diff --git a/src/pkg/http/url_test.go b/src/pkg/http/url_test.go new file mode 100644 index 000000000..8d8fabad5 --- /dev/null +++ b/src/pkg/http/url_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 http + +import ( + "fmt"; + "http"; + "os"; + "reflect"; + "testing"; +) + +// TODO(rsc): +// test URLUnescape +// test URLEscape +// test ParseURL + +type URLTest struct { + in string; + out *URL; + roundtrip string; // expected result of reserializing the URL; empty means same as "in". +} + +var urltests = []URLTest { + // no path + URLTest{ + "http://www.google.com", + &URL{ + "http://www.google.com", + "http", "//www.google.com", + "www.google.com", "", "www.google.com", + "", "", "" + }, + "" + }, + // path + URLTest{ + "http://www.google.com/", + &URL{ + "http://www.google.com/", + "http", "//www.google.com/", + "www.google.com", "", "www.google.com", + "/", "", "" + }, + "" + }, + // path with hex escaping... note that space roundtrips to + + URLTest{ + "http://www.google.com/file%20one%26two", + &URL{ + "http://www.google.com/file%20one%26two", + "http", "//www.google.com/file%20one%26two", + "www.google.com", "", "www.google.com", + "/file one&two", "", "" + }, + "http://www.google.com/file+one%26two" + }, + // user + URLTest{ + "ftp://webmaster@www.google.com/", + &URL{ + "ftp://webmaster@www.google.com/", + "ftp", "//webmaster@www.google.com/", + "webmaster@www.google.com", "webmaster", "www.google.com", + "/", "", "" + }, + "" + }, + // escape sequence in username + URLTest{ + "ftp://john%20doe@www.google.com/", + &URL{ + "ftp://john%20doe@www.google.com/", + "ftp", "//john%20doe@www.google.com/", + "john doe@www.google.com", "john doe", "www.google.com", + "/", "", "" + }, + "ftp://john+doe@www.google.com/" + }, + // query + URLTest{ + "http://www.google.com/?q=go+language", + &URL{ + "http://www.google.com/?q=go+language", + "http", "//www.google.com/?q=go+language", + "www.google.com", "", "www.google.com", + "/", "q=go+language", "" + }, + "" + }, + // query with hex escaping: NOT parsed + URLTest{ + "http://www.google.com/?q=go%20language", + &URL{ + "http://www.google.com/?q=go%20language", + "http", "//www.google.com/?q=go%20language", + "www.google.com", "", "www.google.com", + "/", "q=go%20language", "" + }, + "" + }, + // path without /, so no query parsing + URLTest{ + "http:www.google.com/?q=go+language", + &URL{ + "http:www.google.com/?q=go+language", + "http", "www.google.com/?q=go+language", + "", "", "", + "www.google.com/?q=go language", "", "" + }, + "http:www.google.com/%3fq%3dgo+language" + }, + // non-authority + URLTest{ + "mailto:/webmaster@golang.org", + &URL{ + "mailto:/webmaster@golang.org", + "mailto", "/webmaster@golang.org", + "", "", "", + "/webmaster@golang.org", "", "" + }, + "" + }, + // non-authority + URLTest{ + "mailto:webmaster@golang.org", + &URL{ + "mailto:webmaster@golang.org", + "mailto", "webmaster@golang.org", + "", "", "", + "webmaster@golang.org", "", "" + }, + "" + }, +} + +var urlnofragtests = []URLTest { + URLTest{ + "http://www.google.com/?q=go+language#foo", + &URL{ + "http://www.google.com/?q=go+language#foo", + "http", "//www.google.com/?q=go+language#foo", + "www.google.com", "", "www.google.com", + "/", "q=go+language#foo", "" + }, + "" + }, +} + +var urlfragtests = []URLTest { + URLTest{ + "http://www.google.com/?q=go+language#foo", + &URL{ + "http://www.google.com/?q=go+language", + "http", "//www.google.com/?q=go+language", + "www.google.com", "", "www.google.com", + "/", "q=go+language", "foo" + }, + "" + }, + URLTest{ + "http://www.google.com/?q=go+language#foo%26bar", + &URL{ + "http://www.google.com/?q=go+language", + "http", "//www.google.com/?q=go+language", + "www.google.com", "", "www.google.com", + "/", "q=go+language", "foo&bar" + }, + "" + }, +} + +// more useful string for debugging than fmt's struct printer +func ufmt(u *URL) string { + return fmt.Sprintf("%q, %q, %q, %q, %q, %q, %q, %q, %q", + u.Raw, u.Scheme, u.RawPath, u.Authority, u.Userinfo, + u.Host, u.Path, u.RawQuery, u.Fragment); +} + +func DoTest(t *testing.T, parse func(string) (*URL, os.Error), name string, tests []URLTest) { + for i, tt := range tests { + u, err := parse(tt.in); + if err != nil { + t.Errorf("%s(%q) returned error %s", name, tt.in, err); + continue; + } + if !reflect.DeepEqual(u, tt.out) { + t.Errorf("%s(%q):\n\thave %v\n\twant %v\n", + name, tt.in, ufmt(u), ufmt(tt.out)); + } + } +} + +func TestParseURL(t *testing.T) { + DoTest(t, ParseURL, "ParseURL", urltests); + DoTest(t, ParseURL, "ParseURL", urlnofragtests); +} + +func TestParseURLReference(t *testing.T) { + DoTest(t, ParseURLReference, "ParseURLReference", urltests); + DoTest(t, ParseURLReference, "ParseURLReference", urlfragtests); +} + +func DoTestString(t *testing.T, parse func(string) (*URL, os.Error), name string, tests []URLTest) { + for i, tt := range tests { + u, err := parse(tt.in); + if err != nil { + t.Errorf("%s(%q) returned error %s", name, tt.in, err); + continue; + } + s := u.String(); + expected := tt.in; + if len(tt.roundtrip) > 0 { + expected = tt.roundtrip; + } + if s != expected { + t.Errorf("%s(%q).String() == %q (expected %q)", name, tt.in, s, expected); + } + } +} + +func TestURLString(t *testing.T) { + DoTestString(t, ParseURL, "ParseURL", urltests); + DoTestString(t, ParseURL, "ParseURL", urlfragtests); + DoTestString(t, ParseURL, "ParseURL", urlnofragtests); + DoTestString(t, ParseURLReference, "ParseURLReference", urltests); + DoTestString(t, ParseURLReference, "ParseURLReference", urlfragtests); + DoTestString(t, ParseURLReference, "ParseURLReference", urlnofragtests); +} + +type URLEscapeTest struct { + in string; + out string; + err os.Error; +} + +var unescapeTests = []URLEscapeTest { + URLEscapeTest{ + "", + "", + nil + }, + URLEscapeTest{ + "abc", + "abc", + nil + }, + URLEscapeTest{ + "1%41", + "1A", + nil + }, + URLEscapeTest{ + "1%41%42%43", + "1ABC", + nil + }, + URLEscapeTest{ + "%4a", + "J", + nil + }, + URLEscapeTest{ + "%6F", + "o", + nil + }, + URLEscapeTest{ + "%", // not enough characters after % + "", + BadURL{"invalid hexadecimal escape"} + }, + URLEscapeTest{ + "%a", // not enough characters after % + "", + BadURL{"invalid hexadecimal escape"} + }, + URLEscapeTest{ + "%1", // not enough characters after % + "", + BadURL{"invalid hexadecimal escape"} + }, + URLEscapeTest{ + "123%45%6", // not enough characters after % + "", + BadURL{"invalid hexadecimal escape"} + }, + URLEscapeTest{ + "%zz", // invalid hex digits + "", + BadURL{"invalid hexadecimal escape"} + }, +} + +func TestURLUnescape(t *testing.T) { + for i, tt := range unescapeTests { + actual, err := URLUnescape(tt.in); + if actual != tt.out || (err != nil) != (tt.err != nil) { + t.Errorf("URLUnescape(%q) = %q, %s; want %q, %s", tt.in, actual, err, tt.out, tt.err); + } + } +} + +var escapeTests = []URLEscapeTest { + URLEscapeTest{ + "", + "", + nil + }, + URLEscapeTest{ + "abc", + "abc", + nil + }, + URLEscapeTest{ + "one two", + "one+two", + nil + }, + URLEscapeTest{ + "10%", + "10%25", + nil + }, + URLEscapeTest{ + " ?&=#+%!", + "+%3f%26%3d%23%2b%25!", + nil + }, +} + +func TestURLEscape(t *testing.T) { + for i, tt := range escapeTests { + actual := URLEscape(tt.in); + if tt.out != actual { + t.Errorf("URLEscape(%q) = %q, want %q", tt.in, actual, tt.out); + } + + // for bonus points, verify that escape:unescape is an identity. + roundtrip, err := URLUnescape(actual); + if roundtrip != tt.in || err != nil { + t.Errorf("URLUnescape(%q) = %q, %s; want %q, %s", actual, roundtrip, err, tt.in, "[no error]"); + } + } +} + diff --git a/src/pkg/io/Makefile b/src/pkg/io/Makefile new file mode 100644 index 000000000..219ea776b --- /dev/null +++ b/src/pkg/io/Makefile @@ -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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D= + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + bytebuffer.$O\ + io.$O\ + +O2=\ + pipe.$O\ + utils.$O\ + + +phases: a1 a2 +_obj$D/io.a: phases + +a1: $(O1) + $(AR) grc _obj$D/io.a bytebuffer.$O io.$O + rm -f $(O1) + +a2: $(O2) + $(AR) grc _obj$D/io.a pipe.$O utils.$O + rm -f $(O2) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/io.a + +$(O1): newpkg +$(O2): a1 +$(O3): a2 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/io.a + +packages: _obj$D/io.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/io.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/io.a diff --git a/src/pkg/io/bytebuffer.go b/src/pkg/io/bytebuffer.go new file mode 100644 index 000000000..921ddb17a --- /dev/null +++ b/src/pkg/io/bytebuffer.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 io + +// Simple byte buffer for marshaling data. + +import ( + "io"; + "os"; +) + +func bytecopy(dst []byte, doff int, src []byte, soff int, count int) { + for ; count > 0; count-- { + dst[doff] = src[soff]; + doff++; + soff++; + } +} + +// A ByteBuffer is a simple implementation of the io.Read and io.Write interfaces +// connected to a buffer of bytes. +// The zero value for ByteBuffer is an empty buffer ready to use. +type ByteBuffer struct { + buf []byte; // contents are the bytes buf[off : len(buf)] + off int; // read at &buf[off], write at &buf[len(buf)] +} + +// Data returns the contents of the unread portion of the buffer; +// len(b.Data()) == b.Len(). +func (b *ByteBuffer) Data() []byte { + return b.buf[b.off : len(b.buf)] +} + +// Len returns the number of bytes of the unread portion of the buffer; +// b.Len() == len(b.Data()). +func (b *ByteBuffer) 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 *ByteBuffer) Truncate(n int) { + 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 *ByteBuffer) Reset() { + b.Truncate(0); +} + +// Write appends the contents of p to the buffer. The return +// value n is the length of p; err is always nil. +func (b *ByteBuffer) Write(p []byte) (n int, err os.Error) { + m := b.Len(); + n = len(p); + + if len(b.buf) + n > cap(b.buf) { + // not enough space at end + buf := b.buf; + if m + n > cap(b.buf) { + // not enough space anywhere + buf = make([]byte, 2*cap(b.buf) + n) + } + bytecopy(buf, 0, b.buf, b.off, m); + b.buf = buf; + b.off = 0 + } + + b.buf = b.buf[0 : b.off + m + n]; + bytecopy(b.buf, b.off + m, p, 0, n); + return n, nil +} + +// 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 *ByteBuffer) WriteByte(c byte) os.Error { + b.Write([]byte{c}); + return 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; err is always nil. +func (b *ByteBuffer) Read(p []byte) (n int, err os.Error) { + m := b.Len(); + n = len(p); + + if n > m { + // more bytes requested than available + n = m + } + + bytecopy(p, 0, b.buf, b.off, n); + b.off += n; + return n, nil +} + +// NewByteBufferFromArray creates and initializes a new ByteBuffer +// with buf as its initial contents. +func NewByteBufferFromArray(buf []byte) *ByteBuffer { + return &ByteBuffer{buf, 0}; +} diff --git a/src/pkg/io/bytebuffer_test.go b/src/pkg/io/bytebuffer_test.go new file mode 100644 index 000000000..5a5432223 --- /dev/null +++ b/src/pkg/io/bytebuffer_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 io + +import ( + "io"; + "rand"; + "testing"; +) + + +const N = 10000; // make this bigger for a larger (and slower) test +var data []byte; // test data for write tests + + +func init() { + data = make([]byte, N); + for i := 0; i < len(data); i++ { + data[i] = 'a' + byte(i % 26) + } +} + + +// Verify that contents of buf match the string s. +func check(t *testing.T, testname string, buf *ByteBuffer, s string) { + if buf.Len() != len(buf.Data()) { + t.Errorf("%s: buf.Len() == %d, len(buf.Data()) == %d\n", testname, buf.Len(), len(buf.Data())) + } + + if buf.Len() != len(s) { + t.Errorf("%s: buf.Len() == %d, len(s) == %d\n", testname, buf.Len(), len(s)) + } + + if string(buf.Data()) != s { + t.Errorf("%s: string(buf.Data()) == %q, s == %q\n", testname, string(buf.Data()), s) + } +} + + +// Fill buf through n writes of fub. +// The initial contents of buf corresponds to the string s; +// the result is the final contents of buf returned as a string. +func fill(t *testing.T, testname string, buf *ByteBuffer, 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\n", m, len(fub)); + } + if err != nil { + t.Errorf(testname + " (fill 3): err should always be nil, found err == %s\n", err); + } + s += string(fub); + check(t, testname + " (fill 4)", buf, s); + } + return s; +} + + +// 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 *ByteBuffer, 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\n", err); + } + s = s[n : len(s)]; + check(t, testname + " (empty 3)", buf, s); + } + + check(t, testname + " (empty 4)", buf, ""); +} + + +func TestBasicOperations(t *testing.T) { + var buf ByteBuffer; + + 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(data[0 : 1]); + if n != 1 { + t.Errorf("wrote 1 byte, but n == %d\n", n); + } + if err != nil { + t.Errorf("err should always be nil, but err == %s\n", err); + } + check(t, "TestBasicOperations (4)", &buf, "a"); + + buf.WriteByte(data[1]); + check(t, "TestBasicOperations (5)", &buf, "ab"); + + n, err = buf.Write(data[2 : 26]); + if n != 24 { + t.Errorf("wrote 25 bytes, but n == %d\n", 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)); + } +} + + +func TestLargeWrites(t *testing.T) { + var buf ByteBuffer; + for i := 3; i < 30; i += 3 { + s := fill(t, "TestLargeWrites (1)", &buf, "", 5, data); + empty(t, "TestLargeWrites (2)", &buf, s, make([]byte, len(data)/i)); + } + check(t, "TestLargeWrites (3)", &buf, ""); +} + + +func TestLargeReads(t *testing.T) { + var buf ByteBuffer; + for i := 3; i < 30; i += 3 { + s := fill(t, "TestLargeReads (1)", &buf, "", 5, data[0 : len(data)/i]); + empty(t, "TestLargeReads (2)", &buf, s, make([]byte, len(data))); + } + check(t, "TestLargeReads (3)", &buf, ""); +} + + +func TestMixedReadsAndWrites(t *testing.T) { + var buf ByteBuffer; + s := ""; + for i := 0; i < 50; i++ { + wlen := rand.Intn(len(data)); + s = fill(t, "TestMixedReadsAndWrites (1)", &buf, s, 1, data[0 : wlen]); + + rlen := rand.Intn(len(data)); + fub := make([]byte, rlen); + n, err := buf.Read(fub); + s = s[n : len(s)]; + } + empty(t, "TestMixedReadsAndWrites (2)", &buf, s, make([]byte, buf.Len())); +} diff --git a/src/pkg/io/io.go b/src/pkg/io/io.go new file mode 100644 index 000000000..ba0449ac1 --- /dev/null +++ b/src/pkg/io/io.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. + +// This package provides basic interfaces to I/O primitives. +// Its primary job is to wrap existing implementations of such primitives, +// such as those in package os, into shared public interfaces that +// abstract the functionality. +// It also provides buffering primitives and some other basic operations. +package io + +import ( + "bytes"; + "os"; +) + +// Error represents an unexpected I/O behavior. +type Error struct { + os.ErrorString +} + +// ErrEOF means that data was expected, but a read got EOF instead. +var ErrEOF os.Error = &Error{"EOF"} + +// ErrShortWrite means that a write accepted fewer bytes than requested +// but failed to return an explicit error. +var ErrShortWrite os.Error = &Error{"short write"} + + +// Reader is the interface that wraps the basic Read method. +// An implementation of Read is allowed to use all of p for +// scratch space during the call, even if it eventually returns +// n < len(p). +type Reader interface { + Read(p []byte) (n int, err os.Error); +} + +// Writer is the interface that wraps the basic Write method. +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; +} + +// ReadWrite 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; +} + +// Convert a string to an array of bytes for easy marshaling. +func StringBytes(s string) []byte { + b := make([]byte, len(s)); + for i := 0; i < len(s); i++ { + b[i] = s[i]; + } + return b; +} + +// WriteString writes the contents of the string s to w, which accepts an array of bytes. +func WriteString(w Writer, s string) (n int, err os.Error) { + return w.Write(StringBytes(s)) +} + +// ReadAtLeast reads r into buf until at least min bytes have been read, +// or until EOF or error. +func ReadAtLeast(r Reader, buf []byte, min int) (n int, err os.Error) { + n = 0; + for n < min { + nn, e := r.Read(buf[n:len(buf)]); + if nn > 0 { + n += nn + } + if e != nil { + return n, e + } + if nn <= 0 { + return n, ErrEOF // no error but insufficient data + } + } + return n, nil +} + +// FullRead reads r until the buffer buf is full, or until EOF or error. +func FullRead(r Reader, buf []byte) (n int, err os.Error) { + // TODO(rsc): 6g bug prevents obvious return + n, err = ReadAtLeast(r, buf, len(buf)); + return; +} + +// Convert something that implements Read into something +// whose Reads are always FullReads +type fullRead struct { + r Reader; +} + +func (fr *fullRead) Read(p []byte) (n int, err os.Error) { + n, err = FullRead(fr.r, p); + return n, err +} + +// MakeFullReader takes r, an implementation of Read, and returns an object +// that still implements Read but always calls FullRead underneath. +func MakeFullReader(r Reader) Reader { + if fr, ok := r.(*fullRead); ok { + // already a fullRead + return r + } + return &fullRead{r} +} + +// Copy n copies n bytes (or until EOF is reached) from src to dst. +// It returns the number of bytes copied and the error, if any. +func Copyn(src Reader, dst Writer, n int64) (written int64, err os.Error) { + 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 = os.EIO; + break; + } + } + if er != nil { + err = er; + break; + } + if nr == 0 { + err = ErrEOF; + break; + } + } + return written, err +} + +// Copy copies from src to dst until EOF is reached. +// It returns the number of bytes copied and the error, if any. +func Copy(src Reader, dst Writer) (written int64, err os.Error) { + 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 = os.EIO; + break; + } + } + if er != nil { + err = er; + break; + } + if nr == 0 { + break; + } + } + return written, err +} + +// A ByteReader satisfies Reads by consuming data from a slice of bytes. +// Clients can call NewByteReader to create one or wrap pointers +// to their own slices: r := ByteReader{&data}. +type ByteReader struct { + Data *[]byte +} + +func (r ByteReader) Read(p []byte) (int, os.Error) { + n := len(p); + b := r.Data; + if n > len(b) { + n = len(b); + } + bytes.Copy(p, b[0:n]); + *b = b[n:len(b)]; + return n, nil; +} + +// NewByteReader returns a new ByteReader reading from data. +func NewByteReader(data []byte) ByteReader { + return ByteReader{ &data }; +} + diff --git a/src/pkg/io/pipe.go b/src/pkg/io/pipe.go new file mode 100644 index 000000000..1a443ddce --- /dev/null +++ b/src/pkg/io/pipe.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. + +// Pipe adapter to connect code expecting an io.Read +// with code expecting an io.Write. + +package io + +import ( + "io"; + "os"; + "sync"; +) + +type pipeReturn struct { + n int; + err os.Error; +} + +// Shared pipe structure. +type pipe struct { + rclosed bool; // Read end closed? + rerr os.Error; // Error supplied to CloseReader + wclosed bool; // Write end closed? + werr os.Error; // Error supplied to CloseWriter + wpend []byte; // Written data waiting to be read. + wtot int; // Bytes consumed so far in current write. + cr chan []byte; // Write sends data here... + cw chan pipeReturn; // ... and reads the n, err back from here. +} + +func (p *pipe) Read(data []byte) (n int, err os.Error) { + if p == nil || p.rclosed { + return 0, os.EINVAL; + } + + // Wait for next write block if necessary. + if p.wpend == nil { + if !p.wclosed { + p.wpend = <-p.cr; + } + if p.wpend == nil { + return 0, p.werr; + } + p.wtot = 0; + } + + // Read from current write block. + n = len(data); + if n > len(p.wpend) { + n = len(p.wpend); + } + for i := 0; i < n; i++ { + data[i] = p.wpend[i]; + } + p.wtot += n; + p.wpend = p.wpend[n:len(p.wpend)]; + + // If write block is done, finish the write. + if len(p.wpend) == 0 { + p.wpend = nil; + p.cw <- pipeReturn{p.wtot, nil}; + p.wtot = 0; + } + + return n, nil; +} + +func (p *pipe) Write(data []byte) (n int, err os.Error) { + if p == nil || p.wclosed { + return 0, os.EINVAL; + } + if p.rclosed { + return 0, p.rerr; + } + + // Send data to reader. + p.cr <- data; + + // Wait for reader to finish copying it. + res := <-p.cw; + return res.n, res.err; +} + +func (p *pipe) CloseReader(rerr os.Error) os.Error { + if p == nil || p.rclosed { + return os.EINVAL; + } + + // Stop any future writes. + p.rclosed = true; + if rerr == nil { + rerr = os.EPIPE; + } + p.rerr = rerr; + + // Stop the current write. + if !p.wclosed { + p.cw <- pipeReturn{p.wtot, rerr}; + } + + return nil; +} + +func (p *pipe) CloseWriter(werr os.Error) os.Error { + if p == nil || p.wclosed { + return os.EINVAL; + } + + // Stop any future reads. + p.wclosed = true; + p.werr = werr; + + // Stop the current read. + if !p.rclosed { + p.cr <- nil; + } + + return nil; +} + +// Read/write halves of the pipe. +// They are separate structures for two reasons: +// 1. If one end becomes garbage without being Closed, +// its finisher can Close so that the other end +// does not hang indefinitely. +// 2. Clients cannot use interface conversions on the +// read end to find the Write method, and vice versa. + +// A PipeReader is the read half of a pipe. +type PipeReader struct { + lock sync.Mutex; + 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 nil. +func (r *PipeReader) Read(data []byte) (n int, err os.Error) { + r.lock.Lock(); + defer r.lock.Unlock(); + + 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 { + r.lock.Lock(); + defer r.lock.Unlock(); + + return r.p.CloseReader(nil); +} + +// CloseWithError closes the reader; subsequent writes +// to the write half of the pipe will return the error rerr. +func (r *PipeReader) CloseWithError(rerr os.Error) os.Error { + r.lock.Lock(); + defer r.lock.Unlock(); + + return r.p.CloseReader(rerr); +} + +func (r *PipeReader) finish() { + r.Close(); +} + +// Write half of pipe. +type PipeWriter struct { + lock sync.Mutex; + 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) { + w.lock.Lock(); + defer w.lock.Unlock(); + + return w.p.Write(data); +} + +// Close closes the writer; subsequent reads from the +// read half of the pipe will return no bytes and a nil error. +func (w *PipeWriter) Close() os.Error { + w.lock.Lock(); + defer w.lock.Unlock(); + + return w.p.CloseWriter(nil); +} + +// CloseWithError closes the writer; subsequent reads from the +// read half of the pipe will return no bytes and the error werr. +func (w *PipeWriter) CloseWithError(werr os.Error) os.Error { + w.lock.Lock(); + defer w.lock.Unlock(); + + return w.p.CloseWriter(werr); +} + +func (w *PipeWriter) finish() { + w.Close(); +} + +// 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.cr = make(chan []byte, 1); + p.cw = make(chan pipeReturn, 1); + r := new(PipeReader); + r.p = p; + w := new(PipeWriter); + w.p = 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..277f44525 --- /dev/null +++ b/src/pkg/io/pipe_test.go @@ -0,0 +1,225 @@ +// Copyright 2009 The Go Authors. 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 ( + "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, StringBytes("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 != nil { + t.Errorf("read: %v", err); + } + c <- n; + if n == 0 { + break; + } + } +} + +// 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); + } +} + +// 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 { + 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 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 { + pipeTest{ true, nil, false }, + pipeTest{ true, nil, true }, + pipeTest{ true, io.ErrShortWrite, true }, + pipeTest{ false, nil, false }, + pipeTest{ false, nil, true }, + pipeTest{ false, io.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; + if err != tt.err { + t.Errorf("read from closed pipe: %v want %v", err, tt.err); + } + 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 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); + } + } +} diff --git a/src/pkg/io/utils.go b/src/pkg/io/utils.go new file mode 100644 index 000000000..a4cbb2d9a --- /dev/null +++ b/src/pkg/io/utils.go @@ -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. + +// Utility functions. + +package io + +import ( + "io"; + "os"; +) + +// ReadAll reads from r until an error or EOF and returns the data it read. +func ReadAll(r Reader) ([]byte, os.Error) { + var buf ByteBuffer; + n, err := io.Copy(r, &buf); + return buf.Data(), err; +} + +// ReadFile reads the file named by filename and returns the contents. +func ReadFile(filename string) ([]byte, os.Error) { + f, err := os.Open(filename, os.O_RDONLY, 0); + if err != nil { + return nil, err; + } + defer f.Close(); + return ReadAll(f); +} diff --git a/src/pkg/io/utils_test.go b/src/pkg/io/utils_test.go new file mode 100644 index 000000000..f35dad60c --- /dev/null +++ b/src/pkg/io/utils_test.go @@ -0,0 +1,37 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package io + +import ( + "io"; + "os"; + "testing"; +) + +func checkSize(t *testing.T, path string, size uint64) { + 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 = "utils_test.go"; + contents, err = ReadFile(filename); + if err != nil { + t.Fatalf("ReadFile %s: %v", filename, err); + } + + checkSize(t, filename, uint64(len(contents))); +} diff --git a/src/pkg/json/Makefile b/src/pkg/json/Makefile new file mode 100644 index 000000000..2d70c2cf8 --- /dev/null +++ b/src/pkg/json/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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D= + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + parse.$O\ + +O2=\ + generic.$O\ + struct.$O\ + + +phases: a1 a2 +_obj$D/json.a: phases + +a1: $(O1) + $(AR) grc _obj$D/json.a parse.$O + rm -f $(O1) + +a2: $(O2) + $(AR) grc _obj$D/json.a generic.$O struct.$O + rm -f $(O2) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/json.a + +$(O1): newpkg +$(O2): a1 +$(O3): a2 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/json.a + +packages: _obj$D/json.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/json.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/json.a diff --git a/src/pkg/json/generic.go b/src/pkg/json/generic.go new file mode 100644 index 000000000..e3194eb17 --- /dev/null +++ b/src/pkg/json/generic.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. + +// Generic representation of JSON objects. + +package json + +import ( + "container/vector"; + "fmt"; + "json"; + "math"; + "strconv"; + "strings"; +) + +// Integers identifying the data type in the Json interface. +const ( + StringKind = iota; + NumberKind; + MapKind; // JSON term is "Object", but in Go, it's a map + ArrayKind; + BoolKind; + NullKind; +) + +// The Json interface is implemented by all JSON objects. +type Json interface { + Kind() int; // StringKind, NumberKind, etc. + String() string; // a string form (any kind) + Number() float64; // numeric form (NumberKind) + Bool() bool; // boolean (BoolKind) + Get(s string) Json; // field lookup (MapKind) + Elem(i int) Json; // element lookup (ArrayKind) + Len() int; // length (ArrayKind, MapKind) +} + +// JsonToString returns the textual JSON syntax representation +// for the JSON object j. +// +// JsonToString differs from j.String() in the handling +// of string objects. If j represents the string abc, +// j.String() == `abc`, but JsonToString(j) == `"abc"`. +func JsonToString(j Json) string { + if j == nil { + return "null" + } + if j.Kind() == StringKind { + return Quote(j.String()) + } + return j.String() +} + +type _Null struct { } + +// Null is the JSON object representing the null data object. +var Null Json = &_Null{} + +func (*_Null) Kind() int { return NullKind } +func (*_Null) String() string { return "null" } +func (*_Null) Number() float64 { return 0 } +func (*_Null) Bool() bool { return false } +func (*_Null) Get(s string) Json { return Null } +func (*_Null) Elem(int) Json { return Null } +func (*_Null) Len() int { return 0 } + +type _String struct { s string; _Null } +func (j *_String) Kind() int { return StringKind } +func (j *_String) String() string { return j.s } + +type _Number struct { f float64; _Null } +func (j *_Number) Kind() int { return NumberKind } +func (j *_Number) Number() float64 { return j.f } +func (j *_Number) String() string { + if math.Floor(j.f) == j.f { + return fmt.Sprintf("%.0f", j.f); + } + return fmt.Sprintf("%g", j.f); +} + +type _Array struct { a *vector.Vector; _Null } +func (j *_Array) Kind() int { return ArrayKind } +func (j *_Array) Len() int { return j.a.Len() } +func (j *_Array) Elem(i int) Json { + if i < 0 || i >= j.a.Len() { + return Null + } + return j.a.At(i).(Json) +} +func (j *_Array) String() string { + s := "["; + for i := 0; i < j.a.Len(); i++ { + if i > 0 { + s += ","; + } + s += JsonToString(j.a.At(i).(Json)); + } + s += "]"; + return s; +} + +type _Bool struct { b bool; _Null } +func (j *_Bool) Kind() int { return BoolKind } +func (j *_Bool) Bool() bool { return j.b } +func (j *_Bool) String() string { + if j.b { + return "true" + } + return "false" +} + +type _Map struct { m map[string]Json; _Null } +func (j *_Map) Kind() int { return MapKind } +func (j *_Map) Len() int { return len(j.m) } +func (j *_Map) Get(s string) Json { + if j.m == nil { + return Null + } + v, ok := j.m[s]; + if !ok { + return Null + } + return v; +} +func (j *_Map) String() string { + s := "{"; + first := true; + for k,v := range j.m { + if first { + first = false; + } else { + s += ","; + } + s += Quote(k); + s += ":"; + s += JsonToString(v); + } + s += "}"; + return s; +} + +// Walk evaluates path relative to the JSON object j. +// Path is taken as a sequence of slash-separated field names +// or numbers that can be used to index into JSON map and +// array objects. +// +// For example, if j is the JSON object for +// {"abc": [true, false]}, then Walk(j, "abc/1") returns the +// JSON object for true. +func Walk(j Json, path string) Json { + for len(path) > 0 { + var elem string; + if i := strings.Index(path, "/"); i >= 0 { + elem = path[0:i]; + path = path[i+1:len(path)]; + } else { + elem = path; + path = ""; + } + switch j.Kind() { + case ArrayKind: + indx, err := strconv.Atoi(elem); + if err != nil { + return Null + } + j = j.Elem(indx); + case MapKind: + j = j.Get(elem); + default: + return Null + } + } + return j +} + +// Equal returns whether a and b are indistinguishable JSON objects. +func Equal(a, b Json) bool { + switch { + case a == nil && b == nil: + return true; + case a == nil || b == nil: + return false; + case a.Kind() != b.Kind(): + return false; + } + + switch a.Kind() { + case NullKind: + return true; + case StringKind: + return a.String() == b.String(); + case NumberKind: + return a.Number() == b.Number(); + case BoolKind: + return a.Bool() == b.Bool(); + case ArrayKind: + if a.Len() != b.Len() { + return false; + } + for i := 0; i < a.Len(); i++ { + if !Equal(a.Elem(i), b.Elem(i)) { + return false; + } + } + return true; + case MapKind: + m := a.(*_Map).m; + if len(m) != len(b.(*_Map).m) { + return false; + } + for k,v := range m { + if !Equal(v, b.Get(k)) { + return false; + } + } + return true; + } + + // invalid kind + return false; +} + + +// Parse builder for JSON objects. + +type _JsonBuilder struct { + // either writing to *ptr + ptr *Json; + + // or to a[i] (can't set ptr = &a[i]) + a *vector.Vector; + i int; + + // or to m[k] (can't set ptr = &m[k]) + m map[string] Json; + k string; +} + +func (b *_JsonBuilder) Put(j Json) { + switch { + case b.ptr != nil: + *b.ptr = j; + case b.a != nil: + b.a.Set(b.i, j); + case b.m != nil: + b.m[b.k] = j; + } +} + +func (b *_JsonBuilder) Get() Json { + switch { + case b.ptr != nil: + return *b.ptr; + case b.a != nil: + return b.a.At(b.i).(Json); + case b.m != nil: + return b.m[b.k]; + } + return nil +} + +func (b *_JsonBuilder) Float64(f float64) { + b.Put(&_Number{f, _Null{}}) +} + +func (b *_JsonBuilder) Int64(i int64) { + b.Float64(float64(i)) +} + +func (b *_JsonBuilder) Uint64(i uint64) { + b.Float64(float64(i)) +} + +func (b *_JsonBuilder) Bool(tf bool) { + b.Put(&_Bool{tf, _Null{}}) +} + +func (b *_JsonBuilder) Null() { + b.Put(Null) +} + +func (b *_JsonBuilder) String(s string) { + b.Put(&_String{s, _Null{}}) +} + + +func (b *_JsonBuilder) Array() { + b.Put(&_Array{vector.New(0), _Null{}}) +} + +func (b *_JsonBuilder) Map() { + b.Put(&_Map{make(map[string]Json), _Null{}}) +} + +func (b *_JsonBuilder) Elem(i int) Builder { + bb := new(_JsonBuilder); + bb.a = b.Get().(*_Array).a; + bb.i = i; + for i >= bb.a.Len() { + bb.a.Push(Null) + } + return bb +} + +func (b *_JsonBuilder) Key(k string) Builder { + bb := new(_JsonBuilder); + bb.m = b.Get().(*_Map).m; + bb.k = k; + bb.m[k] = Null; + return bb +} + +// StringToJson parses the string s as a JSON-syntax string +// and returns the generic JSON object representation. +// On success, StringToJson returns with ok set to true and errtok empty. +// If StringToJson encounters a syntax error, it returns with +// ok set to false and errtok set to a fragment of the offending syntax. +func StringToJson(s string) (json Json, ok bool, errtok string) { + var errindx int; + var j Json; + b := new(_JsonBuilder); + b.ptr = &j; + ok, errindx, errtok = Parse(s, b); + if !ok { + return nil, false, errtok + } + return j, true, "" +} + +// BUG(rsc): StringToJson should return an os.Error instead of a bool. diff --git a/src/pkg/json/generic_test.go b/src/pkg/json/generic_test.go new file mode 100644 index 000000000..68868d7a5 --- /dev/null +++ b/src/pkg/json/generic_test.go @@ -0,0 +1,76 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package json + +import ( + "json"; + "testing"; +) + +var jsontests = []string { + `null`, + `true`, + `false`, + `"abc"`, + `123`, + `0.1`, + `1e-10`, + `[]`, + `[1,2,3,4]`, + `[1,2,"abc",null,true,false]`, + `{}`, + `{"a":1}`, +} + +func TestJson(t *testing.T) { + for i := 0; i < len(jsontests); i++ { + val, ok, errtok := StringToJson(jsontests[i]); + if !ok { + t.Errorf("StringToJson(%#q) => error near %v", jsontests[i], errtok); + continue; + } + str := JsonToString(val); + if str != jsontests[i] { + t.Errorf("JsonToString(StringToJson(%#q)) = %#q", jsontests[i], str); + continue; + } + } +} + +func TestJsonMap(t *testing.T) { + values := make(map[string]Json); + mapstr := "{"; + for i := 0; i < len(jsontests); i++ { + val, ok, errtok := StringToJson(jsontests[i]); + if !ok { + t.Errorf("StringToJson(%#q) => error near %v", jsontests[i], errtok); + } + if i > 0 { + mapstr += ","; + } + values[jsontests[i]] = val; + mapstr += Quote(jsontests[i]); + mapstr += ":"; + mapstr += JsonToString(val); + } + mapstr += "}"; + + mapv, ok, errtok := StringToJson(mapstr); + if !ok { + t.Fatalf("StringToJson(%#q) => error near %v", mapstr, errtok); + } + if mapv == nil { + t.Fatalf("StringToJson(%#q) => nil, %v, %v", mapstr, ok, errtok); + } + if cnt := mapv.Len(); cnt != len(jsontests) { + t.Errorf("StringToJson(%#q).Len() => %v, want %v", mapstr, cnt, + len(jsontests)); + } + for k,v := range values { + if v1 := mapv.Get(k); !Equal(v1, v) { + t.Errorf("MapTest: Walk(%#q) => %v, want %v", k, v1, v); + } + } +} diff --git a/src/pkg/json/parse.go b/src/pkg/json/parse.go new file mode 100644 index 000000000..e33b9dbc1 --- /dev/null +++ b/src/pkg/json/parse.go @@ -0,0 +1,419 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// JSON (JavaScript Object Notation) parser. +// See http://www.json.org/ + +// The json package implements a simple parser and +// representation for JSON (JavaScript Object Notation), +// as defined at http://www.json.org/. +package json + +import ( + "fmt"; + "io"; + "math"; + "strconv"; + "strings"; + "utf8"; +) + +// Strings +// +// Double quoted with escapes: \" \\ \/ \b \f \n \r \t \uXXXX. +// No literal control characters, supposedly. +// Have also seen \' and embedded newlines. + +func _UnHex(p string, r, l int) (v int, ok bool) { + v = 0; + for i := r; i < l; i++ { + if i >= len(p) { + return 0, false + } + v *= 16; + switch { + case '0' <= p[i] && p[i] <= '9': + v += int(p[i] - '0'); + case 'a' <= p[i] && p[i] <= 'f': + v += int(p[i] - 'a' + 10); + case 'A' <= p[i] && p[i] <= 'F': + v += int(p[i] - 'A' + 10); + default: + return 0, false; + } + } + return v, true; +} + +// Unquote unquotes the JSON-quoted string s, +// returning a raw string t. If s is not a valid +// JSON-quoted string, Unquote returns with ok set to false. +func Unquote(s string) (t string, ok bool) { + if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' { + return + } + b := make([]byte, len(s)); + w := 0; + for r := 1; r < len(s)-1; { + switch { + case s[r] == '\\': + r++; + if r >= len(s)-1 { + return + } + switch s[r] { + default: + return; + case '"', '\\', '/', '\'': + b[w] = s[r]; + r++; + w++; + case 'b': + b[w] = '\b'; + r++; + w++; + case 'f': + b[w] = '\f'; + r++; + w++; + case 'n': + b[w] = '\n'; + r++; + w++; + case 'r': + b[w] = '\r'; + r++; + w++; + case 't': + b[w] = '\t'; + r++; + w++; + case 'u': + r++; + rune, ok := _UnHex(s, r, 4); + if !ok { + return + } + r += 4; + w += utf8.EncodeRune(rune, b[w:len(b)]); + } + // Control characters are invalid, but we've seen raw \n. + case s[r] < ' ' && s[r] != '\n': + if s[r] == '\n' { + b[w] = '\n'; + r++; + w++; + break; + } + return; + // ASCII + case s[r] < utf8.RuneSelf: + b[w] = s[r]; + r++; + w++; + // Coerce to well-formed UTF-8. + default: + rune, size := utf8.DecodeRuneInString(s[r:len(s)]); + r += size; + w += utf8.EncodeRune(rune, b[w:len(b)]); + } + } + return string(b[0:w]), true +} + +// Quote quotes the raw string s using JSON syntax, +// so that Unquote(Quote(s)) = s, true. +func Quote(s string) string { + chr := make([]byte, utf8.UTFMax); + chr0 := chr[0:1]; + b := new(io.ByteBuffer); + chr[0] = '"'; + b.Write(chr0); + for i := 0; i < len(s); i++ { + switch { + case s[i]=='"' || s[i]=='\\': + chr[0] = '\\'; + chr[1] = s[i]; + b.Write(chr[0:2]); + + case s[i] == '\b': + chr[0] = '\\'; + chr[1] = 'b'; + b.Write(chr[0:2]); + + case s[i] == '\f': + chr[0] = '\\'; + chr[1] = 'f'; + b.Write(chr[0:2]); + + case s[i] == '\n': + chr[0] = '\\'; + chr[1] = 'n'; + b.Write(chr[0:2]); + + case s[i] == '\r': + chr[0] = '\\'; + chr[1] = 'r'; + b.Write(chr[0:2]); + + case s[i] == '\t': + chr[0] = '\\'; + chr[1] = 't'; + b.Write(chr[0:2]); + + case 0x20 <= s[i] && s[i] < utf8.RuneSelf: + chr[0] = s[i]; + b.Write(chr0); + } + } + chr[0] = '"'; + b.Write(chr0); + return string(b.Data()); +} + + +// _Lexer + +type _Lexer struct { + s string; + i int; + kind int; + token string; +} + +func punct(c byte) bool { + return c=='"' || c=='[' || c==']' || c==':' || c=='{' || c=='}' || c==',' +} + +func white(c byte) bool { + return c==' ' || c=='\t' || c=='\n' || c=='\v' +} + +func skipwhite(p string, i int) int { + for i < len(p) && white(p[i]) { + i++ + } + return i +} + +func skiptoken(p string, i int) int { + for i < len(p) && !punct(p[i]) && !white(p[i]) { + i++ + } + return i +} + +func skipstring(p string, i int) int { + for i++; i < len(p) && p[i] != '"'; i++ { + if p[i] == '\\' { + i++ + } + } + if i >= len(p) { + return i + } + return i+1 +} + +func (t *_Lexer) Next() { + i, s := t.i, t.s; + i = skipwhite(s, i); + if i >= len(s) { + t.kind = 0; + t.token = ""; + t.i = len(s); + return; + } + + c := s[i]; + switch { + case c == '-' || '0' <= c && c <= '9': + j := skiptoken(s, i); + t.kind = '1'; + t.token = s[i:j]; + i = j; + + case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z': + j := skiptoken(s, i); + t.kind = 'a'; + t.token = s[i:j]; + i = j; + + case c == '"': + j := skipstring(s, i); + t.kind = '"'; + t.token = s[i:j]; + i = j; + + case c == '[', c == ']', c == ':', c == '{', c == '}', c == ',': + t.kind = int(c); + t.token = s[i:i+1]; + i++; + + default: + t.kind = '?'; + t.token = s[i:i+1]; + } + + t.i = i; +} + + +// Parser +// +// Implements parsing but not the actions. Those are +// carried out by the implementation of the Builder interface. +// A Builder represents the object being created. +// Calling a method like Int64(i) sets that object to i. +// Calling a method like Elem(i) or Key(s) creates a +// new builder for a subpiece of the object (logically, +// an array element or a map key). +// +// There are two Builders, in other files. +// The JsonBuilder builds a generic Json structure +// in which maps are maps. +// The StructBuilder copies data into a possibly +// nested data structure, using the "map keys" +// as struct field names. + +type _Value interface {} + +// BUG(rsc): The json Builder interface needs to be +// reconciled with the xml Builder interface. + +// A Builder is an interface implemented by clients and passed +// to the JSON parser. It gives clients full control over the +// eventual representation returned by the parser. +type Builder interface { + // Set value + Int64(i int64); + Uint64(i uint64); + Float64(f float64); + String(s string); + Bool(b bool); + Null(); + Array(); + Map(); + + // Create sub-Builders + Elem(i int) Builder; + Key(s string) Builder; +} + +func parse(lex *_Lexer, build Builder) bool { + ok := false; +Switch: + switch lex.kind { + case 0: + break; + case '1': + // If the number is exactly an integer, use that. + if i, err := strconv.Atoi64(lex.token); err == nil { + build.Int64(i); + ok = true; + } + else if i, err := strconv.Atoui64(lex.token); err == nil { + build.Uint64(i); + ok = true; + } + // Fall back to floating point. + else if f, err := strconv.Atof64(lex.token); err == nil { + build.Float64(f); + ok = true; + } + + case 'a': + switch lex.token { + case "true": + build.Bool(true); + ok = true; + case "false": + build.Bool(false); + ok = true; + case "null": + build.Null(); + ok = true; + } + + case '"': + if str, ok1 := Unquote(lex.token); ok1 { + build.String(str); + ok = true; + } + + case '[': + // array + build.Array(); + lex.Next(); + n := 0; + for lex.kind != ']' { + if n > 0 { + if lex.kind != ',' { + break Switch; + } + lex.Next(); + } + if !parse(lex, build.Elem(n)) { + break Switch; + } + n++; + } + ok = true; + + case '{': + // map + lex.Next(); + build.Map(); + n := 0; + for lex.kind != '}' { + if n > 0 { + if lex.kind != ',' { + break Switch; + } + lex.Next(); + } + if lex.kind != '"' { + break Switch; + } + key, ok := Unquote(lex.token); + if !ok { + break Switch; + } + lex.Next(); + if lex.kind != ':' { + break Switch; + } + lex.Next(); + if !parse(lex, build.Key(key)) { + break Switch; + } + n++; + } + ok = true; + } + + if ok { + lex.Next(); + } + return ok; +} + +// Parse parses the JSON syntax string s and makes calls to +// the builder to construct a parsed representation. +// On success, it returns with ok set to true. +// On error, it returns with ok set to false, errindx set +// to the byte index in s where a syntax error occurred, +// and errtok set to the offending token. +func Parse(s string, builder Builder) (ok bool, errindx int, errtok string) { + lex := new(_Lexer); + lex.s = s; + lex.Next(); + if parse(lex, builder) { + if lex.kind == 0 { // EOF + return true, 0, "" + } + } + return false, lex.i, lex.token +} + diff --git a/src/pkg/json/struct.go b/src/pkg/json/struct.go new file mode 100644 index 000000000..ac2689557 --- /dev/null +++ b/src/pkg/json/struct.go @@ -0,0 +1,269 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Marshalling and unmarshalling of +// JSON data into Go structs using reflection. + +package json + +import ( + "json"; + "reflect"; +) + +type _StructBuilder struct { + val reflect.Value +} + +var nobuilder *_StructBuilder + +func setfloat(v reflect.Value, f float64) { + switch v.Kind() { + case reflect.FloatKind: + v.(reflect.FloatValue).Set(float(f)); + case reflect.Float32Kind: + v.(reflect.Float32Value).Set(float32(f)); + case reflect.Float64Kind: + v.(reflect.Float64Value).Set(float64(f)); + } +} + +func setint(v reflect.Value, i int64) { + switch v.Kind() { + case reflect.IntKind: + v.(reflect.IntValue).Set(int(i)); + case reflect.Int8Kind: + v.(reflect.Int8Value).Set(int8(i)); + case reflect.Int16Kind: + v.(reflect.Int16Value).Set(int16(i)); + case reflect.Int32Kind: + v.(reflect.Int32Value).Set(int32(i)); + case reflect.Int64Kind: + v.(reflect.Int64Value).Set(int64(i)); + case reflect.UintKind: + v.(reflect.UintValue).Set(uint(i)); + case reflect.Uint8Kind: + v.(reflect.Uint8Value).Set(uint8(i)); + case reflect.Uint16Kind: + v.(reflect.Uint16Value).Set(uint16(i)); + case reflect.Uint32Kind: + v.(reflect.Uint32Value).Set(uint32(i)); + case reflect.Uint64Kind: + v.(reflect.Uint64Value).Set(uint64(i)); + } +} + +func (b *_StructBuilder) Int64(i int64) { + if b == nil { + return + } + v := b.val; + switch v.Kind() { + case reflect.FloatKind, reflect.Float32Kind, reflect.Float64Kind: + setfloat(v, float64(i)); + default: + setint(v, i); + } +} + +func (b *_StructBuilder) Uint64(i uint64) { + if b == nil { + return + } + v := b.val; + switch v.Kind() { + case reflect.FloatKind, reflect.Float32Kind, reflect.Float64Kind: + setfloat(v, float64(i)); + default: + setint(v, int64(i)); + } +} + +func (b *_StructBuilder) Float64(f float64) { + if b == nil { + return + } + v := b.val; + switch v.Kind() { + case reflect.FloatKind, reflect.Float32Kind, reflect.Float64Kind: + setfloat(v, f); + default: + setint(v, int64(f)); + } +} + +func (b *_StructBuilder) Null() { +} + +func (b *_StructBuilder) String(s string) { + if b == nil { + return + } + if v := b.val; v.Kind() == reflect.StringKind { + v.(reflect.StringValue).Set(s); + } +} + +func (b *_StructBuilder) Bool(tf bool) { + if b == nil { + return + } + if v := b.val; v.Kind() == reflect.BoolKind { + v.(reflect.BoolValue).Set(tf); + } +} + +func (b *_StructBuilder) Array() { + if b == nil { + return + } + if v := b.val; v.Kind() == reflect.PtrKind { + pv := v.(reflect.PtrValue); + psubtype := pv.Type().(reflect.PtrType).Sub(); + if pv.Get() == nil && psubtype.Kind() == reflect.ArrayKind { + av := reflect.NewSliceValue(psubtype.(reflect.ArrayType), 0, 8); + pv.SetSub(av); + } + } +} + +func (b *_StructBuilder) Elem(i int) Builder { + if b == nil || i < 0 { + return nobuilder + } + v := b.val; + if v.Kind() == reflect.PtrKind { + // If we have a pointer to an array, allocate or grow + // the array as necessary. Then set v to the array itself. + pv := v.(reflect.PtrValue); + psub := pv.Sub(); + if psub.Kind() == reflect.ArrayKind { + av := psub.(reflect.ArrayValue); + if i > av.Cap() { + n := av.Cap(); + if n < 8 { + n = 8 + } + for n <= i { + n *= 2 + } + av1 := reflect.NewSliceValue(av.Type().(reflect.ArrayType), av.Len(), n); + av1.CopyFrom(av, av.Len()); + pv.SetSub(av1); + av = av1; + } + } + v = psub; + } + if v.Kind() == reflect.ArrayKind { + // Array was grown above, or is fixed size. + av := v.(reflect.ArrayValue); + if av.Len() <= i && i < av.Cap() { + av.SetLen(i+1); + } + if i < av.Len() { + return &_StructBuilder{ av.Elem(i) } + } + } + return nobuilder +} + +func (b *_StructBuilder) Map() { + if b == nil { + return + } + if v := b.val; v.Kind() == reflect.PtrKind { + pv := v.(reflect.PtrValue); + if pv.Get() == nil { + pv.SetSub(reflect.NewZeroValue(pv.Type().(reflect.PtrType).Sub())) + } + } +} + +func (b *_StructBuilder) Key(k string) Builder { + if b == nil { + return nobuilder + } + v := b.val; + if v.Kind() == reflect.PtrKind { + v = v.(reflect.PtrValue).Sub(); + } + if v.Kind() == reflect.StructKind { + sv := v.(reflect.StructValue); + t := v.Type().(reflect.StructType); + for i := 0; i < t.Len(); i++ { + name, typ, tag, off := t.Field(i); + if k == name { + return &_StructBuilder{ sv.Field(i) } + } + } + } + return nobuilder +} + +// Unmarshal parses the JSON syntax string s and fills in +// an arbitrary struct or array pointed at by val. +// It uses the reflection library to assign to fields +// and arrays embedded in val. Well-formed data that does not fit +// into the struct is discarded. +// +// For example, given the following definitions: +// +// type Email struct { +// where string; +// addr string; +// } +// +// type Result struct { +// name string; +// phone string; +// emails []Email +// } +// +// var r = Result{ "name", "phone", nil } +// +// unmarshalling the JSON syntax string +// +// { +// "email": [ +// { +// "where": "home", +// "addr": "gre@example.com" +// }, +// { +// "where": "work", +// "addr": "gre@work.com" +// } +// ], +// "name": "Grace R. Emlin", +// "address": "123 Main Street" +// } +// +// via Unmarshal(s, &r) is equivalent to assigning +// +// r = Result{ +// "Grace R. Emlin", // name +// "phone", // no phone given +// []Email{ +// Email{ "home", "gre@example.com" }, +// Email{ "work", "gre@work.com" } +// } +// } +// +// Note that the field r.phone has not been modified and +// that the JSON field "address" was discarded. +// +// On success, Unmarshal returns with ok set to true. +// On a syntax error, it returns with ok set to false and errtok +// set to the offending token. +func Unmarshal(s string, val interface{}) (ok bool, errtok string) { + var errindx int; + var val1 interface{}; + b := &_StructBuilder{ reflect.NewValue(val) }; + ok, errindx, errtok = Parse(s, b); + if !ok { + return false, errtok + } + return true, "" +} diff --git a/src/pkg/json/struct_test.go b/src/pkg/json/struct_test.go new file mode 100644 index 000000000..88d9e9ec4 --- /dev/null +++ b/src/pkg/json/struct_test.go @@ -0,0 +1,82 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package json + +import ( + "json"; + "testing"; +) + +type _MyStruct struct { + t bool; + f bool; + s string; + i8 int8; + i16 int16; + i32 int32; + i64 int64; + u8 uint8; + u16 uint16; + u32 uint32; + u64 uint64; + i int; + u uint; + fl float; + fl32 float32; + fl64 float64; + a *[]string; // TODO(rsc): Should be able to use []string. + my *_MyStruct; +}; + +const _Encoded = + `{"t":true,"f":false,"s":"abc","i8":1,"i16":2,"i32":3,"i64":4,` + ` "u8":5,"u16":6,"u32":7,"u64":8,` + ` "i":-9,"u":10,"bogusfield":"should be ignored",` + ` "fl":11.5,"fl32":12.25,"fl64":13.75,` + ` "a":["x","y","z"],"my":{"s":"subguy"}}`; + + +func _Check(t *testing.T, ok bool, name string, v interface{}) { + if !ok { + t.Errorf("%s = %v (BAD)", name, v); + } else { + t.Logf("%s = %v (good)", name, v); + } +} + +func TestUnmarshal(t *testing.T) { + var m _MyStruct; + m.f = true; + ok, errtok := Unmarshal(_Encoded, &m); + if !ok { + t.Fatalf("Unmarshal failed near %s", errtok); + } + _Check(t, m.t==true, "t", m.t); + _Check(t, m.f==false, "f", m.f); + _Check(t, m.s=="abc", "s", m.s); + _Check(t, m.i8==1, "i8", m.i8); + _Check(t, m.i16==2, "i16", m.i16); + _Check(t, m.i32==3, "i32", m.i32); + _Check(t, m.i64==4, "i64", m.i64); + _Check(t, m.u8==5, "u8", m.u8); + _Check(t, m.u16==6, "u16", m.u16); + _Check(t, m.u32==7, "u32", m.u32); + _Check(t, m.u64==8, "u64", m.u64); + _Check(t, m.i==-9, "i", m.i); + _Check(t, m.u==10, "u", m.u); + _Check(t, m.fl==11.5, "fl", m.fl); + _Check(t, m.fl32==12.25, "fl32", m.fl32); + _Check(t, m.fl64==13.75, "fl64", m.fl64); + _Check(t, m.a!=nil, "a", m.a); + if m.a != nil { + _Check(t, m.a[0]=="x", "a[0]", m.a[0]); + _Check(t, m.a[1]=="y", "a[1]", m.a[1]); + _Check(t, m.a[2]=="z", "a[2]", m.a[2]); + } + _Check(t, m.my!=nil, "my", m.my); + if m.my != nil { + _Check(t, m.my.s=="subguy", "my.s", m.my.s); + } +} diff --git a/src/pkg/log/Makefile b/src/pkg/log/Makefile new file mode 100644 index 000000000..4b1c4b5a2 --- /dev/null +++ b/src/pkg/log/Makefile @@ -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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D= + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + log.$O\ + + +phases: a1 +_obj$D/log.a: phases + +a1: $(O1) + $(AR) grc _obj$D/log.a log.$O + rm -f $(O1) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/log.a + +$(O1): newpkg +$(O2): a1 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/log.a + +packages: _obj$D/log.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/log.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/log.a diff --git a/src/pkg/log/log.go b/src/pkg/log/log.go new file mode 100644 index 000000000..8fcd73190 --- /dev/null +++ b/src/pkg/log/log.go @@ -0,0 +1,195 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Rudimentary logging package. Defines a type, Logger, with simple +// methods for formatting output to one or two destinations. Also has +// predefined Loggers accessible through helper functions Stdout[f], +// Stderr[f], Exit[f], and Crash[f], which are easier to use than creating +// a Logger manually. +// Exit exits when written to. +// Crash causes a crash when written to. +package log + +import ( + "fmt"; + "io"; + "runtime"; + "os"; + "time"; +) + +// These flags define the properties of the Logger and the output they produce. +const ( + // Flags + Lok = iota; + Lexit; // terminate execution when written + Lcrash; // crash (panic) when written + // Bits or'ed together to control what's printed. There is no control over the + // order they appear (the order listed here) or the format they present (as + // described in the comments). A colon appears after these items: + // 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 + lAllBits = Ldate | Ltime | Lmicroseconds | Llongfile | Lshortfile; +) + +// Logger represents an active logging object. +type Logger struct { + out0 io.Writer; // first destination for output + out1 io.Writer; // second destination for output; may be nil + prefix string; // prefix to write at beginning of each line + flag int; // properties +} + +// New creates a new Logger. The out0 and out1 variables set the +// destinations to which log data will be written; out1 may be nil. +// The prefix appears at the beginning of each generated log line. +// The flag argument defines the logging properties. +func New(out0, out1 io.Writer, prefix string, flag int) *Logger { + return &Logger{out0, out1, prefix, flag} +} + +var ( + stdout = New(os.Stdout, nil, "", Lok|Ldate|Ltime); + stderr = New(os.Stderr, nil, "", Lok|Ldate|Ltime); + exit = New(os.Stderr, nil, "", Lexit|Ldate|Ltime); + crash = New(os.Stderr, nil, "", Lcrash|Ldate|Ltime); +) + +var shortnames = make(map[string] string) // cache of short names to avoid allocation. + +// Cheap integer to fixed-width decimal ASCII. Use a negative width to avoid zero-padding +func itoa(i int, wid int) string { + var u uint = uint(i); + if u == 0 && wid <= 1 { + return "0" + } + + // 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'; + } + + return string(b[bp:len(b)]) +} + +func (l *Logger) formatHeader(ns int64, calldepth int) string { + h := l.prefix; + if l.flag & (Ldate | Ltime | Lmicroseconds) != 0 { + t := time.SecondsToLocalTime(ns/1e9); + if l.flag & (Ldate) != 0 { + h += itoa(int(t.Year), 4) + "/" + itoa(t.Month, 2) + itoa(t.Day, 2) + " " + } + if l.flag & (Ltime | Lmicroseconds) != 0 { + h += itoa(t.Hour, 2) + ":" + itoa(t.Minute, 2) + ":" + itoa(t.Second, 2); + if l.flag & Lmicroseconds != 0 { + h += "." + itoa(int(ns % 1e9)/1e3, 6); + } + h += " "; + } + } + if l.flag & (Lshortfile | Llongfile) != 0 { + pc, file, line, ok := runtime.Caller(calldepth); + if ok { + if l.flag & Lshortfile != 0 { + short, ok := shortnames[file]; + if !ok { + short = file; + for i := len(file) - 1; i > 0; i-- { + if file[i] == '/' { + short = file[i+1:len(file)]; + break; + } + } + shortnames[file] = short; + } + file = short; + } + } else { + file = "???"; + line = 0; + } + h += file + ":" + itoa(line, -1) + ": "; + } + return h; +} + +// Output writes the output for a logging event. The string s contains the text to print after +// the time stamp; calldepth is used to recover the PC. It is provided for generality, although +// at the moment on all pre-defined paths it will be 2. +func (l *Logger) Output(calldepth int, s string) { + now := time.Nanoseconds(); // get this early. + newline := "\n"; + if len(s) > 0 && s[len(s)-1] == '\n' { + newline = "" + } + s = l.formatHeader(now, calldepth+1) + s + newline; + io.WriteString(l.out0, s); + if l.out1 != nil { + io.WriteString(l.out1, s); + } + switch l.flag & ^lAllBits { + case Lcrash: + panic("log: fatal error"); + case Lexit: + os.Exit(1); + } +} + +// Logf is analogous to Printf() for a Logger. +func (l *Logger) Logf(format string, v ...) { + l.Output(2, fmt.Sprintf(format, v)) +} + +// Log is analogouts to Print() for a Logger. +func (l *Logger) Log(v ...) { + l.Output(2, fmt.Sprintln(v)) +} + +// Stdout is a helper function for easy logging to stdout. It is analogous to Print(). +func Stdout(v ...) { + stdout.Output(2, fmt.Sprint(v)) +} + +// Stderr is a helper function for easy logging to stderr. It is analogous to Fprint(os.Stderr). +func Stderr(v ...) { + stderr.Output(2, fmt.Sprintln(v)) +} + +// Stdoutf is a helper functions for easy formatted logging to stdout. It is analogous to Printf(). +func Stdoutf(format string, v ...) { + stdout.Output(2, fmt.Sprintf(format, v)) +} + +// Stderrf is a helper function for easy formatted logging to stderr. It is analogous to Fprintf(os.Stderr). +func Stderrf(format string, v ...) { + stderr.Output(2, fmt.Sprintf(format, v)) +} + +// Exit is equivalent to Stderr() followed by a call to os.Exit(1). +func Exit(v ...) { + exit.Output(2, fmt.Sprintln(v)) +} + +// Exitf is equivalent to Stderrf() followed by a call to os.Exit(1). +func Exitf(format string, v ...) { + exit.Output(2, fmt.Sprintf(format, v)) +} + +// Crash is equivalent to Stderrf() followed by a call to panic(). +func Crash(v ...) { + crash.Output(2, fmt.Sprintln(v)) +} + +// Crashf is equivalent to Stderrf() followed by a call to panic(). +func Crashf(format string, v ...) { + crash.Output(2, fmt.Sprintf(format, v)) +} diff --git a/src/pkg/log/log_test.go b/src/pkg/log/log_test.go new file mode 100644 index 000000000..0cfb2e36f --- /dev/null +++ b/src/pkg/log/log_test.go @@ -0,0 +1,82 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package log + +// These tests are too simple. + +import ( + "bufio"; + "log"; + "os"; + "regexp"; + "testing"; +) + +const ( + Rdate = `[0-9][0-9][0-9][0-9]/[0-9][0-9][0-9][0-9]`; + Rtime = `[0-9][0-9]:[0-9][0-9]:[0-9][0-9]`; + Rmicroseconds = `\.[0-9][0-9][0-9][0-9][0-9][0-9]`; + Rline = `[0-9]+:`; + 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: + tester{ 0, "", "" }, + tester{ 0, "XXX", "XXX" }, + tester{ Lok|Ldate, "", Rdate+" " }, + tester{ Lok|Ltime, "", Rtime+" " }, + tester{ Lok|Ltime|Lmicroseconds, "", Rtime+Rmicroseconds+" " }, + tester{ Lok|Lmicroseconds, "", Rtime+Rmicroseconds+" " }, // microsec implies time + tester{ Lok|Llongfile, "", Rlongfile+" " }, + tester{ Lok|Lshortfile, "", Rshortfile+" " }, + tester{ Lok|Llongfile|Lshortfile, "", Rshortfile+" " }, // shortfile overrides longfile + // everything at once: + tester{ Lok|Ldate|Ltime|Lmicroseconds|Llongfile, "XXX", "XXX"+Rdate+" "+Rtime+Rmicroseconds+" "+Rlongfile+" " }, + tester{ Lok|Ldate|Ltime|Lmicroseconds|Lshortfile, "XXX", "XXX"+Rdate+" "+Rtime+Rmicroseconds+" "+Rshortfile+" " }, +} + +// Test using Log("hello", 23, "world") or using Logf("hello %d world", 23) +func testLog(t *testing.T, flag int, prefix string, pattern string, useLogf bool) { + r, w, err1 := os.Pipe(); + if err1 != nil { + t.Fatal("pipe", err1); + } + defer r.Close(); + defer w.Close(); + buf := bufio.NewReader(r); + l := New(w, nil, prefix, flag); + if useLogf { + l.Logf("hello %d world", 23); + } else { + l.Log("hello", 23, "world"); + } + line, err3 := buf.ReadLineString('\n', false); + if err3 != nil { + t.Fatal("log error", err3); + } + pattern = "^"+pattern+"hello 23 world$"; + matched, err4 := regexp.Match(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); + } +} + +func TestAllLog(t *testing.T) { + for i, testcase := range(tests) { + testLog(t, testcase.flag, testcase.prefix, testcase.pattern, false); + testLog(t, testcase.flag, testcase.prefix, testcase.pattern, true); + } +} diff --git a/src/pkg/malloc/Makefile b/src/pkg/malloc/Makefile new file mode 100644 index 000000000..61894f71f --- /dev/null +++ b/src/pkg/malloc/Makefile @@ -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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D= + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + malloc.$O\ + + +phases: a1 +_obj$D/malloc.a: phases + +a1: $(O1) + $(AR) grc _obj$D/malloc.a malloc.$O + rm -f $(O1) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/malloc.a + +$(O1): newpkg +$(O2): a1 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/malloc.a + +packages: _obj$D/malloc.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/malloc.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/malloc.a diff --git a/src/pkg/malloc/malloc.go b/src/pkg/malloc/malloc.go new file mode 100644 index 000000000..fec53f08f --- /dev/null +++ b/src/pkg/malloc/malloc.go @@ -0,0 +1,24 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Go declarations for malloc. +// The actual functions are written in C +// and part of the runtime library. + +package malloc + +type Stats struct { + Alloc uint64; + Sys uint64; + Stacks uint64; + InusePages uint64; + NextGC uint64; + EnableGC bool; +} + +func Alloc(uintptr) *byte +func Free(*byte) +func GetStats() *Stats +func Lookup(*byte) (*byte, uintptr) +func GC() diff --git a/src/pkg/math/Makefile b/src/pkg/math/Makefile new file mode 100644 index 000000000..058049072 --- /dev/null +++ b/src/pkg/math/Makefile @@ -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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D= + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + const.$O\ + fabs.$O\ + hypot.$O\ + pow10.$O\ + runtime.$O\ + +O2=\ + atan.$O\ + exp.$O\ + floor.$O\ + fmod.$O\ + log.$O\ + sin.$O\ + sqrt.$O\ + tan.$O\ + +O3=\ + asin.$O\ + atan2.$O\ + pow.$O\ + sinh.$O\ + +O4=\ + tanh.$O\ + + +phases: a1 a2 a3 a4 +_obj$D/math.a: phases + +a1: $(O1) + $(AR) grc _obj$D/math.a const.$O fabs.$O hypot.$O pow10.$O runtime.$O + rm -f $(O1) + +a2: $(O2) + $(AR) grc _obj$D/math.a atan.$O exp.$O floor.$O fmod.$O log.$O sin.$O sqrt.$O tan.$O + rm -f $(O2) + +a3: $(O3) + $(AR) grc _obj$D/math.a asin.$O atan2.$O pow.$O sinh.$O + rm -f $(O3) + +a4: $(O4) + $(AR) grc _obj$D/math.a tanh.$O + rm -f $(O4) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/math.a + +$(O1): newpkg +$(O2): a1 +$(O3): a2 +$(O4): a3 +$(O5): a4 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/math.a + +packages: _obj$D/math.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/math.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/math.a diff --git a/src/pkg/math/all_test.go b/src/pkg/math/all_test.go new file mode 100644 index 000000000..c5d5c01c4 --- /dev/null +++ b/src/pkg/math/all_test.go @@ -0,0 +1,278 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package math + +import ( + "math"; + "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, +} +var asin = []float64 { + 5.2117697218417440e-01, + 8.8495619865825236e-01, + -2.7691544662819413e-02, + -5.2482360935268932e-01, + 1.3002662421166553e+00, + 2.9698415875871901e-01, + 5.5025938468083364e-01, + 2.7629597861677200e-01, + 1.8355989225745148e-01, + -1.0523547536021498e+00, +} +var atan = []float64 { + 1.3725902621296217e+00, + 1.4422906096452980e+00, + -2.7011324359471755e-01, + -1.3738077684543379e+00, + 1.4673921193587666e+00, + 1.2415173565870167e+00, + 1.3818396865615167e+00, + 1.2194305844639670e+00, + 1.0696031952318783e+00, + -1.4561721938838085e+00, +} +var exp = []float64 { + 1.4533071302642137e+02, + 2.2958822575694450e+03, + 7.5814542574851666e-01, + 6.6668778421791010e-03, + 1.5310493273896035e+04, + 1.8659907517999329e+01, + 1.8662167355098713e+02, + 1.5301332413189379e+01, + 6.2047063430646876e+00, + 1.6894712385826522e-04, +} +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 log = []float64 { + 1.6052314626930630e+00, + 2.0462560018708768e+00, + -1.2841708730962657e+00, + 1.6115563905281544e+00, + 2.2655365644872018e+00, + 1.0737652208918380e+00, + 1.6542360106073545e+00, + 1.0035467127723465e+00, + 6.0174879014578053e-01, + 2.1617038728473527e+00, +} +var pow = []float64 { + 9.5282232631648415e+04, + 5.4811599352999900e+07, + 5.2859121715894400e-01, + 9.7587991957286472e-06, + 4.3280643293460450e+09, + 8.4406761805034551e+02, + 1.6946633276191194e+05, + 5.3449040147551940e+02, + 6.6881821384514159e+01, + 2.0609869004248744e-09, +} +var sin = []float64 { + -9.6466616586009283e-01, + 9.9338225271646543e-01, + -2.7335587039794395e-01, + 9.5586257685042800e-01, + -2.0994210667799692e-01, + 2.1355787807998605e-01, + -8.6945689711673619e-01, + 4.0195666811555783e-01, + 9.6778633541688000e-01, + -6.7344058690503452e-01, +} +var sinh = []float64 { + 7.2661916084208533e+01, + 1.1479409110035194e+03, + -2.8043136512812520e-01, + -7.4994290911815868e+01, + 7.6552466042906761e+03, + 9.3031583421672010e+00, + 9.3308157558281088e+01, + 7.6179893137269143e+00, + 3.0217691805496156e+00, + -2.9595057572444951e+03, +} +var sqrt = []float64 { + 2.2313699659365484e+00, + 2.7818829009464263e+00, + 5.2619393496314792e-01, + 2.2384377628763938e+00, + 3.1042380236055380e+00, + 1.7106657298385224e+00, + 2.2867189227054791e+00, + 1.6516476350711160e+00, + 1.3510396336454586e+00, + 2.9471892997524950e+00, +} +var tan = []float64 { + -3.6613165650402277e+00, + 8.6490023264859754e+00, + -2.8417941955033615e-01, + 3.2532901859747287e+00, + 2.1472756403802937e-01, + -2.1860091071106700e-01, + -1.7600028178723679e+00, + -4.3898089147528178e-01, + -3.8438855602011305e+00, + 9.1098879337768517e-01, +} +var tanh = []float64 { + 9.9990531206936328e-01, + 9.9999962057085307e-01, + -2.7001505097318680e-01, + -9.9991110943061700e-01, + 9.9999999146798441e-01, + 9.9427249436125233e-01, + 9.9994257600983156e-01, + 9.9149409509772863e-01, + 9.4936501296239700e-01, + -9.9999994291374019e-01, +} + +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 close(a,b float64) bool { + return tolerance(a, b, 1e-14); +} +func veryclose(a,b float64) bool { + return tolerance(a, b, 4e-16); +} + +func TestAsin(t *testing.T) { + for i := 0; i < len(vf); i++ { + if f := math.Asin(vf[i]/10); !veryclose(asin[i], f) { + t.Errorf("math.Asin(%g) = %g, want %g\n", vf[i]/10, f, asin[i]); + } + } +} + +func TestAtan(t *testing.T) { + for i := 0; i < len(vf); i++ { + if f := math.Atan(vf[i]); !veryclose(atan[i], f) { + t.Errorf("math.Atan(%g) = %g, want %g\n", vf[i], f, atan[i]); + } + } +} + +func TestExp(t *testing.T) { + for i := 0; i < len(vf); i++ { + if f := math.Exp(vf[i]); !veryclose(exp[i], f) { + t.Errorf("math.Exp(%g) = %g, want %g\n", vf[i], f, exp[i]); + } + } +} + +func TestFloor(t *testing.T) { + for i := 0; i < len(vf); i++ { + if f := math.Floor(vf[i]); floor[i] != f { + t.Errorf("math.Floor(%g) = %g, want %g\n", vf[i], f, floor[i]); + } + } +} + +func TestLog(t *testing.T) { + for i := 0; i < len(vf); i++ { + a := math.Fabs(vf[i]); + if f := math.Log(a); log[i] != f { + t.Errorf("math.Log(%g) = %g, want %g\n", a, f, log[i]); + } + } + if f := math.Log(10); f != math.Ln10 { + t.Errorf("math.Log(%g) = %g, want %g\n", 10, f, math.Ln10); + } +} + +func TestPow(t *testing.T) { + for i := 0; i < len(vf); i++ { + if f := math.Pow(10, vf[i]); !close(pow[i], f) { + t.Errorf("math.Pow(10, %.17g) = %.17g, want %.17g\n", vf[i], f, pow[i]); + } + } +} + +func TestSin(t *testing.T) { + for i := 0; i < len(vf); i++ { + if f := math.Sin(vf[i]); !close(sin[i], f) { + t.Errorf("math.Sin(%g) = %g, want %g\n", vf[i], f, sin[i]); + } + } +} + +func TestSinh(t *testing.T) { + for i := 0; i < len(vf); i++ { + if f := math.Sinh(vf[i]); !veryclose(sinh[i], f) { + t.Errorf("math.Sinh(%g) = %g, want %g\n", vf[i], f, sinh[i]); + } + } +} + +func TestSqrt(t *testing.T) { + for i := 0; i < len(vf); i++ { + a := math.Fabs(vf[i]); + if f := math.Sqrt(a); !veryclose(sqrt[i], f) { + t.Errorf("math.Sqrt(%g) = %g, want %g\n", a, f, floor[i]); + } + } +} + +func TestTan(t *testing.T) { + for i := 0; i < len(vf); i++ { + if f := math.Tan(vf[i]); !close(tan[i], f) { + t.Errorf("math.Tan(%g) = %g, want %g\n", vf[i], f, tan[i]); + } + } +} + +func TestTanh(t *testing.T) { + for i := 0; i < len(vf); i++ { + if f := math.Tanh(vf[i]); !veryclose(tanh[i], f) { + t.Errorf("math.Tanh(%g) = %g, want %g\n", vf[i], f, tanh[i]); + } + } +} + +func TestHypot(t *testing.T) { + for i := 0; i < len(vf); i++ { + a := math.Fabs(tanh[i]*math.Sqrt(2)); + if f := math.Hypot(tanh[i], tanh[i]); !veryclose(a, f) { + t.Errorf("math.Hypot(%g, %g) = %g, want %g\n", tanh[i], tanh[i], f, a); + } + } +} diff --git a/src/pkg/math/asin.go b/src/pkg/math/asin.go new file mode 100644 index 000000000..23c9a1069 --- /dev/null +++ b/src/pkg/math/asin.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 math + +import "math" + +/* + * asin(arg) and acos(arg) return the arcsin, arccos, + * respectively of their arguments. + * + * Arctan is called after appropriate range reduction. + */ + +// Asin returns the arc sine of x. +func Asin(x float64) float64 { + sign := false; + if x < 0 { + x = -x; + sign = true; + } + if x > 1 { + return NaN(); + } + + temp := Sqrt(1 - x*x); + if x > 0.7 { + temp = Pi/2 - Atan(temp/x); + } else { + temp = Atan(x/temp); + } + + if sign { + temp = -temp; + } + return temp; +} + +// Acos returns the arc cosine of x. +func Acos(x float64) float64 { + if x > 1 || x < -1 { + return NaN(); + } + return Pi/2 - Asin(x); +} diff --git a/src/pkg/math/atan.go b/src/pkg/math/atan.go new file mode 100644 index 000000000..4b18f76aa --- /dev/null +++ b/src/pkg/math/atan.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 + +import "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 makes its argument positive and + * calls the inner routine satan. + */ + +// Atan returns the arc tangent of x. +func Atan(x float64) float64 { + 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..72f2117b3 --- /dev/null +++ b/src/pkg/math/atan2.go @@ -0,0 +1,28 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package math + +import "math" + +// Atan returns the arc tangent of y/x, using +// the signs of the two to determine the quadrant +// of the return value. +func Atan2(x, y float64) float64 { + // Determine the quadrant and call atan. + if x+y == x { + if x >= 0 { + return Pi/2; + } + return -Pi/2; + } + q := Atan(x/y); + if y < 0 { + if q <= 0 { + return q + Pi; + } + return q - Pi; + } + return q; +} diff --git a/src/pkg/math/const.go b/src/pkg/math/const.go new file mode 100644 index 000000000..259660fea --- /dev/null +++ b/src/pkg/math/const.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. + +// The math package provides basic constants and mathematical functions. +package math + +// Mathematical constants. +// Reference: http://www.research.att.com/~njas/sequences/Axxxxxx +const ( + E = 2.71828182845904523536028747135266249775724709369995957496696763; // A001113 + Pi = 3.14159265358979323846264338327950288419716939937510582097494459; // A000796 + Phi = 1.61803398874989484820458683436563811772030917980576286213544862; // A001622 + + Sqrt2 = 1.41421356237309504880168872420969807856967187537694807317667974; // A002193 + SqrtE = 1.64872127070012814684865078781416357165377610071014801157507931; // A019774 + SqrtPi = 1.77245385090551602729816748334114518279754945612238712821380779; // A002161 + SqrtPhi = 1.27201964951406896425242246173749149171560804184009624861664038; // A139339 + + Ln2 = 0.693147180559945309417232121458176568075500134360255254120680009; // A002162 + Log2E = 1/Ln2; + Ln10 = 2.30258509299404568401799145468436420760110148862877297603332790; // A002392 + Log10E = 1/Ln10; +) + +// BUG(rsc): The manual should define the special cases for all of these functions. diff --git a/src/pkg/math/exp.go b/src/pkg/math/exp.go new file mode 100644 index 000000000..a32c7e1d5 --- /dev/null +++ b/src/pkg/math/exp.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 math + +import "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 -Inf or +Inf. +// Very small values underflow to 1. +func Exp(x float64) float64 { + const ( + Ln2Hi = 6.93147180369123816490e-01; + Ln2Lo = 1.90821492927058770002e-10; + Log2e = 1.44269504088896338700e+00; + + P1 = 1.66666666666666019037e-01; /* 0x3FC55555; 0x5555553E */ + P2 = -2.77777777770155933842e-03; /* 0xBF66C16C; 0x16BEBD93 */ + P3 = 6.61375632143793436117e-05; /* 0x3F11566A; 0xAF25DE2C */ + P4 = -1.65339022054652515390e-06; /* 0xBEBBBD41; 0xC5D26BF1 */ + P5 = 4.13813679705723846039e-08; /* 0x3E663769; 0x72BEA4D0 */ + + Overflow = 7.09782712893383973096e+02; + Underflow = -7.45133219101941108420e+02; + NearZero = 1.0/(1<<28); // 2^-28 + ) + + // special cases + switch { + case IsNaN(x) || IsInf(x, 1): + return x; + case IsInf(x, -1): + return 0; + case x > Overflow: + return Inf(1); + case x < Underflow: + return 0; + case -NearZero < x && x < NearZero: + return 1; + } + + // reduce; computed as r = hi - lo for extra precision. + var k int; + switch { + case x < 0: + k = int(Log2e*x - 0.5); + case x > 0: + k = int(Log2e*x + 0.5); + } + hi := x - float64(k)*Ln2Hi; + lo := float64(k)*Ln2Lo; + r := hi - lo; + + // compute + t := r * r; + c := r - t*(P1+t*(P2+t*(P3+t*(P4+t*P5)))); + y := 1 - ((lo - (r*c)/(2-c)) - hi); + // TODO(rsc): make sure Ldexp can handle boundary k + return Ldexp(y, k); +} diff --git a/src/pkg/math/fabs.go b/src/pkg/math/fabs.go new file mode 100644 index 000000000..9427c5726 --- /dev/null +++ b/src/pkg/math/fabs.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 + +// Fabs returns the absolute value of x. +func Fabs(x float64) float64 { + if x < 0 { + return -x; + } + return x; +} + diff --git a/src/pkg/math/floor.go b/src/pkg/math/floor.go new file mode 100644 index 000000000..48a1003f0 --- /dev/null +++ b/src/pkg/math/floor.go @@ -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. + +package math + +import "math" + +// Floor returns the greatest integer value less than or equal to x. +func Floor(x float64) float64 { + if x < 0 { + d, fract := Modf(-x); + if fract != 0.0 { + d = d+1; + } + return -d; + } + d, fract := Modf(x); + return d; +} + +// Ceil returns the least integer value greater than or equal to x. +func Ceil(x float64) float64 { + return -Floor(-x); +} diff --git a/src/pkg/math/fmod.go b/src/pkg/math/fmod.go new file mode 100644 index 000000000..617f5408b --- /dev/null +++ b/src/pkg/math/fmod.go @@ -0,0 +1,41 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package math + +import "math" + +/* + * floating-point mod func without infinity or NaN checking + */ + +// Fmod returns the floating-point remainder of x/y. +func Fmod(x, y float64) float64 { + if y == 0 { + return x; + } + 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/hypot.go b/src/pkg/math/hypot.go new file mode 100644 index 000000000..411f74e4f --- /dev/null +++ b/src/pkg/math/hypot.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 + +/* + * 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. +func Hypot(p, q float64) float64 { + 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/log.go b/src/pkg/math/log.go new file mode 100644 index 000000000..b24175b63 --- /dev/null +++ b/src/pkg/math/log.go @@ -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. + +package math + +import "math" + +// The original C code, the long comment, and the constants +// below are from FreeBSD's /usr/src/lib/msun/src/e_log.c +// and came with this notice. The go code is a simpler +// version of the original C. +// +// ==================================================== +// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +// +// Developed at SunPro, a Sun Microsystems, Inc. business. +// Permission to use, copy, modify, and distribute this +// software is freely granted, provided that this notice +// is preserved. +// ==================================================== +// +// __ieee754_log(x) +// Return the logrithm of x +// +// Method : +// 1. Argument Reduction: find k and f such that +// x = 2^k * (1+f), +// where sqrt(2)/2 < 1+f < sqrt(2) . +// +// 2. Approximation of log(1+f). +// Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s) +// = 2s + 2/3 s**3 + 2/5 s**5 + ....., +// = 2s + s*R +// We use a special Reme algorithm on [0,0.1716] to generate +// a polynomial of degree 14 to approximate R The maximum error +// of this polynomial approximation is bounded by 2**-58.45. In +// other words, +// 2 4 6 8 10 12 14 +// R(z) ~ L1*s +L2*s +L3*s +L4*s +L5*s +L6*s +L7*s +// (the values of L1 to L7 are listed in the program) +// and +// | 2 14 | -58.45 +// | L1*s +...+L7*s - R(z) | <= 2 +// | | +// Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2. +// In order to guarantee error in log below 1ulp, we compute log +// by +// log(1+f) = f - s*(f - R) (if f is not too large) +// log(1+f) = f - (hfsq - s*(hfsq+R)). (better accuracy) +// +// 3. Finally, log(x) = k*Ln2 + log(1+f). +// = k*Ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*Ln2_lo))) +// Here Ln2 is split into two floating point number: +// Ln2_hi + Ln2_lo, +// where n*Ln2_hi is always exact for |n| < 2000. +// +// Special cases: +// log(x) is NaN with signal if x < 0 (including -INF) ; +// log(+INF) is +INF; log(0) is -INF with signal; +// log(NaN) is that NaN with no signal. +// +// Accuracy: +// according to an error analysis, the error is always less than +// 1 ulp (unit in the last place). +// +// Constants: +// The hexadecimal values are the intended ones for the following +// constants. The decimal values may be used, provided that the +// compiler will convert from decimal to binary accurately enough +// to produce the hexadecimal values shown. + +// Log returns the natural logarithm of x. +// +// Special cases are: +// Log(+Inf) = +Inf +// Log(0) = -Inf +// Log(x < 0) = NaN +// Log(NaN) = NaN +func Log(x float64) float64 { + const ( + Ln2Hi = 6.93147180369123816490e-01; /* 3fe62e42 fee00000 */ + Ln2Lo = 1.90821492927058770002e-10; /* 3dea39ef 35793c76 */ + L1 = 6.666666666666735130e-01; /* 3FE55555 55555593 */ + L2 = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */ + L3 = 2.857142874366239149e-01; /* 3FD24924 94229359 */ + L4 = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */ + L5 = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */ + L6 = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */ + L7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + ) + + // special cases + switch { + case 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); +} + +// Log10 returns the decimal logarthm of x. +// The special cases are the same as for Log. +func Log10(x float64) float64 { + if x <= 0 { + return NaN(); + } + return Log(x) * (1/Ln10); +} + diff --git a/src/pkg/math/pow.go b/src/pkg/math/pow.go new file mode 100644 index 000000000..920d210b5 --- /dev/null +++ b/src/pkg/math/pow.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 math + +import "math" + +// Pow returns x**y, the base-x exponential of y. +func Pow(x, y float64) float64 { + // TODO: x or y NaN, ±Inf, maybe ±0. + switch { + case y == 0: + return 1; + case y == 1: + return x; + case x == 0 && y > 0: + return 0; + case x == 0 && y < 0: + return Inf(1); + case y == 0.5: + return Sqrt(x); + case y == -0.5: + return 1 / Sqrt(x); + } + + 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 := float64(1); + 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..fcdd6e0a1 --- /dev/null +++ b/src/pkg/math/pow10.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 math + +/* + * 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 GO converts fp numbers better + * than multipication of lower powers of 10. + */ + +var pow10tab [70]float64; + +// Pow10 returns 10**x, the base-10 exponential of x. +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; iexp, +// with the absolute value of frac in the interval [½, 1). +func Frexp(f float64) (frac float64, exp int) + +// Inf returns positive infinity if sign >= 0, negative infinity if sign < 0. +func Inf(sign int32) (f float64) + +// 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) (is bool) + +// IsNaN returns whether f is an IEEE 754 ``not-a-number'' value. +func IsNaN(f float64) (is bool) + +// Ldexp is the inverse of Frexp. +// It returns frac × 2exp. +func Ldexp(frac float64, exp int) (f float64) + +// Modf returns integer and fractional floating-point numbers +// that sum to f. +// Integer and frac have the same sign as f. +func Modf(f float64) (integer float64, frac float64) + +// NaN returns an IEEE 754 ``not-a-number'' value. +func NaN() (f float64) diff --git a/src/pkg/math/sin.go b/src/pkg/math/sin.go new file mode 100644 index 000000000..9fc69606c --- /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 + +import "math" + +func sinus(x float64, quad int) float64 { + // Coefficients are #3370 from Hart & Cheney (18.80D). + 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); + temp1, 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/sinh.go b/src/pkg/math/sinh.go new file mode 100644 index 000000000..ef70989fb --- /dev/null +++ b/src/pkg/math/sinh.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 math + +import "math" + +/* + * Sinh(x) returns the hyperbolic sine of x + * + * 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..79384f648 --- /dev/null +++ b/src/pkg/math/sqrt.go @@ -0,0 +1,66 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package math + +import "math" + +/* + * sqrt returns the square root of its floating + * point argument. Newton's method. + * + * calls frexp + */ + +// Sqrt returns the square root of x. +// +// Special cases are: +// Sqrt(+Inf) = +Inf +// Sqrt(0) = 0 +// Sqrt(x < 0) = NaN +func Sqrt(x float64) float64 { + if IsInf(x, 1) { + return x; + } + + if x <= 0 { + if x < 0 { + return NaN(); + } + return 0; + } + + y, exp := Frexp(x); + for y < 0.5 { + y = y*2; + exp = exp-1; + } + + if exp&1 != 0 { + y = y*2; + exp = exp-1; + } + temp := 0.5 * (1+y); + + for exp > 60 { + temp = temp * float64(1<<30); + exp = exp - 60; + } + for exp < -60 { + temp = temp / float64(1<<30); + exp = exp + 60; + } + if exp >= 0 { + exp = 1 << uint(exp/2); + temp = temp * float64(exp); + } else { + exp = 1 << uint(-exp/2); + temp = temp / float64(exp); + } + + for i:=0; i<=4; i++ { + temp = 0.5*(temp + x/temp); + } + return temp; +} diff --git a/src/pkg/math/tan.go b/src/pkg/math/tan.go new file mode 100644 index 000000000..2d4a044b8 --- /dev/null +++ b/src/pkg/math/tan.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 + +import "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) { + panic(NaN()); + } + temp = 1/temp; + } + if sign { + temp = -temp; + } + return temp; +} diff --git a/src/pkg/math/tanh.go b/src/pkg/math/tanh.go new file mode 100644 index 000000000..18d38ae8f --- /dev/null +++ b/src/pkg/math/tanh.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 + +import "math" + +/* + * tanh(x) computes the hyperbolic tangent of its floating + * point argument. + * + * 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/net/Makefile b/src/pkg/net/Makefile new file mode 100644 index 000000000..61c872089 --- /dev/null +++ b/src/pkg/net/Makefile @@ -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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m dnsclient.go dnsconfig.go dnsmsg.go fd.go fd_${GOOS}.go ip.go net.go parse.go port.go >Makefile + +D= + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + dnsmsg.$O\ + parse.$O\ + +O2=\ + fd_$(GOOS).$O\ + ip.$O\ + port.$O\ + +O3=\ + dnsconfig.$O\ + fd.$O\ + +O4=\ + net.$O\ + +O5=\ + dnsclient.$O\ + + +phases: a1 a2 a3 a4 a5 +_obj$D/net.a: phases + +a1: $(O1) + $(AR) grc _obj$D/net.a dnsmsg.$O parse.$O + rm -f $(O1) + +a2: $(O2) + $(AR) grc _obj$D/net.a fd_$(GOOS).$O ip.$O port.$O + rm -f $(O2) + +a3: $(O3) + $(AR) grc _obj$D/net.a dnsconfig.$O fd.$O + rm -f $(O3) + +a4: $(O4) + $(AR) grc _obj$D/net.a net.$O + rm -f $(O4) + +a5: $(O5) + $(AR) grc _obj$D/net.a dnsclient.$O + rm -f $(O5) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/net.a + +$(O1): newpkg +$(O2): a1 +$(O3): a2 +$(O4): a3 +$(O5): a4 +$(O6): a5 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/net.a + +packages: _obj$D/net.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/net.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/net.a diff --git a/src/pkg/net/dialgoogle_test.go b/src/pkg/net/dialgoogle_test.go new file mode 100644 index 000000000..1e0c0aaf0 --- /dev/null +++ b/src/pkg/net/dialgoogle_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 net + +import ( + "flag"; + "fmt"; + "io"; + "net"; + "os"; + "syscall"; + "testing"; +) + +// If an IPv6 tunnel is running (see go/stubl), 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 net.Conn, network, addr string) { + req := io.StringBytes("GET /intl/en/privacy.html HTTP/1.0\r\nHost: www.google.com\r\n\r\n"); + n, err := fd.Write(req); + + buf := make([]byte, 1000); + n, err = io.FullRead(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 := net.Dial(network, "", addr); + if err != nil { + t.Errorf("net.Dial(%q, %q, %q) = _, %v", network, "", addr, err); + return + } + fetchGoogle(t, fd, network, addr); + fd.Close() +} + +func doDialTCP(t *testing.T, network, addr string) { + fd, err := net.DialTCP(network, "", addr); + if err != nil { + t.Errorf("net.DialTCP(%q, %q, %q) = _, %v", network, "", addr, err); + } else { + fetchGoogle(t, fd, network, addr); + } + fd.Close() +} + +var googleaddrs = []string { + "74.125.19.99:80", + "www.google.com:80", + "74.125.19.99:http", + "www.google.com:http", + "074.125.019.099:0080", + "[::ffff:74.125.19.99]:80", + "[::ffff:4a7d:1363]:80", + "[0:0:0:0:0000:ffff:74.125.19.99]:80", + "[0:0:0:0:000000:ffff:74.125.19.99]:80", + "[0:0:0:0:0:ffff::74.125.19.99]:80", + "[2001:4860:0:2001::68]:80" // ipv6.google.com; removed if ipv6 flag not set +} + +func TestDialGoogle(t *testing.T) { + // If no ipv6 tunnel, don't try the last address. + if !*ipv6 { + googleaddrs[len(googleaddrs)-1] = "" + } + + for i := 0; i < len(googleaddrs); i++ { + addr := googleaddrs[i]; + if addr == "" { + continue + } + t.Logf("-- %s --", addr); + doDial(t, "tcp", addr); + doDialTCP(t, "tcp", addr); + if addr[0] != '[' { + doDial(t, "tcp4", addr); + doDialTCP(t, "tcp4", addr); + + if !preferIPv4 { + // make sure preferIPv4 flag works. + preferIPv4 = true; + syscall.SocketDisableIPv6 = true; + doDial(t, "tcp4", addr); + doDialTCP(t, "tcp4", addr); + syscall.SocketDisableIPv6 = false; + preferIPv4 = false; + } + } + doDial(t, "tcp6", addr); + doDialTCP(t, "tcp6", addr) + } +} diff --git a/src/pkg/net/dnsclient.go b/src/pkg/net/dnsclient.go new file mode 100644 index 000000000..cfd67eabe --- /dev/null +++ b/src/pkg/net/dnsclient.go @@ -0,0 +1,227 @@ +// Copyright 2009 The Go 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. +// 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. +// More substantial error reporting. +// Remove use of fmt? + +package net + +import ( + "fmt"; + "io"; + "net"; + "once"; + "os"; + "strings"; +) + +// DNS errors returned by LookupHost. +type DNSError struct { + os.ErrorString +} +var ( + DNS_InternalError os.Error = &DNSError{"internal dns error"}; + DNS_MissingConfig os.Error = &DNSError{"no dns configuration"}; + DNS_No_Answer os.Error = &DNSError{"dns got no answer"}; + DNS_BadRequest os.Error = &DNSError{"malformed dns request"}; + DNS_BadReply os.Error = &DNSError{"malformed dns reply"}; + DNS_ServerFailure os.Error = &DNSError{"dns server failure"}; + DNS_NoServers os.Error = &DNSError{"no dns servers"}; + DNS_NameTooLong os.Error = &DNSError{"dns name too long"}; + DNS_RedirectLoop os.Error = &DNSError{"dns redirect loop"}; + DNS_NameNotFound os.Error = &DNSError{"dns name not found"}; +) + +// Send a request on the connection and hope for a reply. +// Up to cfg.attempts attempts. +func _Exchange(cfg *_DNS_Config, c Conn, name string) (m *_DNS_Msg, err os.Error) { + if len(name) >= 256 { + return nil, DNS_NameTooLong + } + out := new(_DNS_Msg); + out.id = 0x1234; + out.question = []_DNS_Question{ + _DNS_Question{ name, _DNS_TypeA, _DNS_ClassINET } + }; + out.recursion_desired = true; + msg, ok := out.Pack(); + if !ok { + return nil, DNS_InternalError + } + + for attempt := 0; attempt < cfg.attempts; attempt++ { + n, err := c.Write(msg); + if err != nil { + return nil, err + } + + c.SetReadTimeout(1e9); // nanoseconds + + buf := make([]byte, 2000); // More than enough. + n, err = c.Read(buf); + if err == os.EAGAIN { + continue; + } + if err != nil { + return nil, err; + } + buf = buf[0:n]; + in := new(_DNS_Msg); + if !in.Unpack(buf) || in.id != out.id { + continue + } + return in, nil + } + return nil, DNS_No_Answer +} + + +// Find answer for name in dns message. +// On return, if err == nil, addrs != nil. +// TODO(rsc): Maybe return []IP instead? +func answer(name string, dns *_DNS_Msg) (addrs []string, err os.Error) { + addrs = make([]string, 0, len(dns.answer)); + + if dns.rcode == _DNS_RcodeNameError && dns.authoritative { + return nil, DNS_NameNotFound // authoritative "no such host" + } + if dns.rcode != _DNS_RcodeSuccess { + // 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, DNS_ServerFailure + } + + // Look for the name. + // Presotto says it's okay to assume that servers listed in + // /etc/resolv.conf are recursive resolvers. + // We asked for recursion, so it should have included + // all the answers we need in this one packet. +Cname: + for cnameloop := 0; cnameloop < 10; cnameloop++ { + addrs = addrs[0:0]; + for i := 0; i < len(dns.answer); i++ { + rr := dns.answer[i]; + h := rr.Header(); + if h.class == _DNS_ClassINET && h.name == name { + switch h.rrtype { + case _DNS_TypeA: + n := len(addrs); + a := rr.(*_DNS_RR_A).a; + addrs = addrs[0:n+1]; + addrs[n] = fmt.Sprintf("%d.%d.%d.%d", (a>>24), (a>>16)&0xFF, (a>>8)&0xFF, a&0xFF); + case _DNS_TypeCNAME: + // redirect to cname + name = rr.(*_DNS_RR_CNAME).cname; + continue Cname + } + } + } + if len(addrs) == 0 { + return nil, DNS_NameNotFound + } + return addrs, nil + } + + // Too many redirects + return nil, DNS_RedirectLoop +} + +// Do a lookup for a single name, which must be rooted +// (otherwise answer will not find the answers). +func tryOneName(cfg *_DNS_Config, name string) (addrs []string, err os.Error) { + err = DNS_NoServers; + 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. + c, cerr := Dial("udp", "", cfg.servers[i] + ":53"); + if cerr != nil { + err = cerr; + continue; + } + msg, merr := _Exchange(cfg, c, name); + c.Close(); + if merr != nil { + err = merr; + continue; + } + addrs, aerr := answer(name, msg); + if aerr != nil && aerr != DNS_NameNotFound { + err = aerr; + continue; + } + return addrs, aerr; + } + return; +} + +var cfg *_DNS_Config +var dnserr os.Error + +func loadConfig() { + cfg, dnserr = _DNS_ReadConfig(); +} + +// LookupHost looks up the host name using the local DNS resolver. +// It returns the canonical name for the host and an array of that +// host's addresses. +func LookupHost(name string) (cname string, addrs []string, err os.Error) +{ + // TODO(rsc): Pick out obvious non-DNS names to avoid + // sending stupid requests to the server? + + once.Do(loadConfig); + if dnserr != nil || cfg == nil { + // better error than file not found. + err = DNS_MissingConfig; + 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 || strings.Count(name, ".") >= cfg.ndots { + rname := name; + if !rooted { + rname += "."; + } + // Can try as ordinary name. + addrs, aerr := tryOneName(cfg, rname); + if aerr == nil { + return rname, addrs, nil; + } + err = aerr; + } + if rooted { + return + } + + // Otherwise, try suffixes. + for i := 0; i < len(cfg.search); i++ { + newname := name+"."+cfg.search[i]; + if newname[len(newname)-1] != '.' { + newname += "." + } + addrs, aerr := tryOneName(cfg, newname); + if aerr == nil { + return newname, addrs, nil; + } + err = aerr; + } + return +} diff --git a/src/pkg/net/dnsconfig.go b/src/pkg/net/dnsconfig.go new file mode 100644 index 000000000..e56d964f2 --- /dev/null +++ b/src/pkg/net/dnsconfig.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. + +// Read system DNS config from /etc/resolv.conf + +package net + +import ( + "io"; + "net"; + "os"; + "strconv"; +) + +type _DNS_Config 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 _DNS_configError os.Error; + +// 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 _DNS_ReadConfig() (*_DNS_Config, os.Error) { + // TODO(rsc): 6g won't let me say file, err := + var file *file; + var err os.Error; + file, err = open("/etc/resolv.conf"); + if err != nil { + return nil, err + } + conf := new(_DNS_Config); + conf.servers = make([]string, 3)[0:0]; // small, but the standard limit + conf.search = make([]string, 0); + conf.ndots = 1; + conf.timeout = 1; + conf.attempts = 1; + 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]; + if len(ParseIP(name)) != 0 { + 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, i, ok := dtoi(s, 6); + if n < 1 { + n = 1 + } + conf.ndots = n; + case len(s) >= 8 && s[0:8] == "timeout:": + n, i, ok := dtoi(s, 8); + if n < 1 { + n = 1 + } + conf.timeout = n; + case len(s) >= 8 && s[0:9] == "attempts:": + n, i, ok := 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..d7a467fc6 --- /dev/null +++ b/src/pkg/net/dnsmsg.go @@ -0,0 +1,679 @@ +// Copyright 2009 The Go 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. +// +// 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 _DNS_RR_Header.rrtype and _DNS_Question.qtype + _DNS_TypeA = 1; + _DNS_TypeNS = 2; + _DNS_TypeMD = 3; + _DNS_TypeMF = 4; + _DNS_TypeCNAME = 5; + _DNS_TypeSOA = 6; + _DNS_TypeMB = 7; + _DNS_TypeMG = 8; + _DNS_TypeMR = 9; + _DNS_TypeNULL = 10; + _DNS_TypeWKS = 11; + _DNS_TypePTR = 12; + _DNS_TypeHINFO = 13; + _DNS_TypeMINFO = 14; + _DNS_TypeMX = 15; + _DNS_TypeTXT = 16; + + // valid _DNS_Question.qtype only + _DNS_TypeAXFR = 252; + _DNS_TypeMAILB = 253; + _DNS_TypeMAILA = 254; + _DNS_TypeALL = 255; + + // valid _DNS_Question.qclass + _DNS_ClassINET = 1; + _DNS_ClassCSNET = 2; + _DNS_ClassCHAOS = 3; + _DNS_ClassHESIOD = 4; + _DNS_ClassANY = 255; + + // _DNS_Msg.rcode + _DNS_RcodeSuccess = 0; + _DNS_RcodeFormatError = 1; + _DNS_RcodeServerFailure = 2; + _DNS_RcodeNameError = 3; + _DNS_RcodeNotImplemented = 4; + _DNS_RcodeRefused = 5; +) + +// The wire format for the DNS packet header. +type __DNS_Header struct { + id uint16; + bits uint16; + qdcount, ancount, nscount, arcount uint16; +} + +const ( + // __DNS_Header.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 _DNS_Question 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 _DNS_RR_Header struct { + name string "domain-name"; + rrtype uint16; + class uint16; + ttl uint32; + rdlength uint16; // length of data after header +} + +func (h *_DNS_RR_Header) Header() *_DNS_RR_Header { + return h +} + +type _DNS_RR interface { + Header() *_DNS_RR_Header +} + + +// Specific DNS RR formats for each query type. + +type _DNS_RR_CNAME struct { + _DNS_RR_Header; + cname string "domain-name"; +} + +type _DNS_RR_HINFO struct { + _DNS_RR_Header; + cpu string; + os string; +} + +type _DNS_RR_MB struct { + _DNS_RR_Header; + mb string "domain-name"; +} + +type _DNS_RR_MG struct { + _DNS_RR_Header; + mg string "domain-name"; +} + +type _DNS_RR_MINFO struct { + _DNS_RR_Header; + rmail string "domain-name"; + email string "domain-name"; +} + +type _DNS_RR_MR struct { + _DNS_RR_Header; + mr string "domain-name"; +} + +type _DNS_RR_MX struct { + _DNS_RR_Header; + pref uint16; + mx string "domain-name"; +} + +type _DNS_RR_NS struct { + _DNS_RR_Header; + ns string "domain-name"; +} + +type _DNS_RR_PTR struct { + _DNS_RR_Header; + ptr string "domain-name"; +} + +type _DNS_RR_SOA struct { + _DNS_RR_Header; + ns string "domain-name"; + mbox string "domain-name"; + serial uint32; + refresh uint32; + retry uint32; + expire uint32; + minttl uint32; +} + +type _DNS_RR_TXT struct { + _DNS_RR_Header; + txt string; // not domain name +} + +type _DNS_RR_A struct { + _DNS_RR_Header; + a uint32 "ipv4"; +} + + +// 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()_DNS_RR { + _DNS_TypeCNAME: func() _DNS_RR { return new(_DNS_RR_CNAME) }, + _DNS_TypeHINFO: func() _DNS_RR { return new(_DNS_RR_HINFO) }, + _DNS_TypeMB: func() _DNS_RR { return new(_DNS_RR_MB) }, + _DNS_TypeMG: func() _DNS_RR { return new(_DNS_RR_MG) }, + _DNS_TypeMINFO: func() _DNS_RR { return new(_DNS_RR_MINFO) }, + _DNS_TypeMR: func() _DNS_RR { return new(_DNS_RR_MR) }, + _DNS_TypeMX: func() _DNS_RR { return new(_DNS_RR_MX) }, + _DNS_TypeNS: func() _DNS_RR { return new(_DNS_RR_NS) }, + _DNS_TypePTR: func() _DNS_RR { return new(_DNS_RR_PTR) }, + _DNS_TypeSOA: func() _DNS_RR { return new(_DNS_RR_SOA) }, + _DNS_TypeTXT: func() _DNS_RR { return new(_DNS_RR_TXT) }, + _DNS_TypeA: func() _DNS_RR { return new(_DNS_RR_A) }, +} + +// Pack a domain name s into msg[off:]. +// Domain names are a sequence of counted strings +// split at the dots. They end with a zero-length string. +func packDomainName(s string, msg []byte, off int) (off1 int, ok bool) { + // Add trailing dot to canonicalize name. + if n := len(s); n == 0 || s[n-1] != '.' { + s += "."; + } + + // Each dot ends a segment of the name. + // We trade each dot byte for a length byte. + // There is also a trailing zero. + // Check that we have all the space we need. + tot := len(s) + 1; + if off+tot > len(msg) { + return len(msg), false + } + + // Emit sequence of counted strings, chopping at dots. + begin := 0; + for i := 0; i < len(s); i++ { + if s[i] == '.' { + if i - begin >= 1<<6 { // top two bits of length must be clear + return len(msg), false + } + msg[off] = byte(i - begin); + off++; + for j := begin; j < i; j++ { + msg[off] = s[j]; + off++; + } + begin = i+1; + } + } + msg[off] = 0; + off++; + return off, true +} + +// Unpack a domain name. +// In addition to the simple sequences of counted strings above, +// domain names are allowed to refer to strings elsewhere in the +// packet, to avoid repeating common suffixes when returning +// many entries in a single domain. The pointers are marked +// by a length byte with the top two bits set. Ignoring those +// two bits, that byte and the next give a 14 bit offset from msg[0] +// where we should pick up the trail. +// Note that if we jump elsewhere in the packet, +// we return off1 == the offset after the first pointer we found, +// which is where the next record will start. +// In theory, the pointers are only allowed to jump backward. +// We let them jump anywhere and stop jumping after a while. +func unpackDomainName(msg []byte, off int) (s string, off1 int, ok bool) { + s = ""; + ptr := 0; // number of pointers followed +Loop: + for { + if off >= len(msg) { + return "", len(msg), false + } + c := int(msg[off]); + off++; + switch c&0xC0 { + case 0x00: + if c == 0x00 { + // end of name + break Loop + } + // literal string + if off+c > len(msg) { + return "", len(msg), false + } + s += string(msg[off:off+c]) + "."; + off += c; + case 0xC0: + // pointer to somewhere else in msg. + // remember location after first ptr, + // since that's how many bytes we consumed. + // also, don't follow too many pointers -- + // maybe there's a loop. + if off >= len(msg) { + return "", len(msg), false + } + c1 := msg[off]; + off++; + if ptr == 0 { + off1 = off + } + if ptr++; ptr > 10 { + return "", len(msg), false + } + off = (c^0xC0)<<8 | int(c1); + default: + // 0x80 and 0x40 are reserved + return "", len(msg), false + } + } + if ptr == 0 { + off1 = off + } + return s, off1, true +} + +// Pack a reflect.StructValue into msg. Struct members can only be uint16, uint32, string, +// and other (often anonymous) structs. +func packStructValue(val reflect.StructValue, msg []byte, off int) (off1 int, ok bool) { + for i := 0; i < val.Len(); i++ { + fld := val.Field(i); + name, typ, tag, xxx := val.Type().(reflect.StructType).Field(i); + switch fld.Kind() { + default: + fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", fld.Type()); + return len(msg), false; + case reflect.StructKind: + off, ok = packStructValue(fld.(reflect.StructValue), msg, off); + case reflect.Uint16Kind: + i := fld.(reflect.Uint16Value).Get(); + if off+2 > len(msg) { + return len(msg), false + } + msg[off] = byte(i>>8); + msg[off+1] = byte(i); + off += 2; + case reflect.Uint32Kind: + i := fld.(reflect.Uint32Value).Get(); + 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+4] = byte(i); + off += 4; + case reflect.StringKind: + // There are multiple string encodings. + // The tag distinguishes ordinary strings from domain names. + s := fld.(reflect.StringValue).Get(); + switch tag { + default: + fmt.Fprintf(os.Stderr, "net: dns: unknown string tag %v", 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++; + for i := 0; i < len(s); i++ { + msg[off+i] = s[i]; + } + off += len(s); + } + } + } + return off, true +} + +func packStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) { + val := reflect.NewValue(any).(reflect.PtrValue).Sub().(reflect.StructValue); + off, ok = packStructValue(val, msg, off); + return off, ok +} + +// 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.Len(); i++ { + name, typ, tag, xxx := val.Type().(reflect.StructType).Field(i); + fld := val.Field(i); + switch fld.Kind() { + default: + fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", fld.Type()); + return len(msg), false; + case reflect.StructKind: + off, ok = unpackStructValue(fld.(reflect.StructValue), msg, off); + case reflect.Uint16Kind: + if off+2 > len(msg) { + return len(msg), false + } + i := uint16(msg[off])<<8 | uint16(msg[off+1]); + fld.(reflect.Uint16Value).Set(i); + off += 2; + case reflect.Uint32Kind: + 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]); + fld.(reflect.Uint32Value).Set(i); + off += 4; + case reflect.StringKind: + var s string; + switch tag { + default: + fmt.Fprintf(os.Stderr, "net: dns: unknown string tag %v", 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); + } + fld.(reflect.StringValue).Set(s); + } + } + return off, true +} + +func unpackStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) { + val := reflect.NewValue(any).(reflect.PtrValue).Sub().(reflect.StructValue); + off, ok = unpackStructValue(val, msg, off); + return off, ok +} + +// Generic struct printer. +// Doesn't care about the string tag "domain-name", +// but does look for an "ipv4" tag on uint32 variables, +// printing them as IP addresses. +func printStructValue(val reflect.StructValue) string { + s := "{"; + for i := 0; i < val.Len(); i++ { + if i > 0 { + s += ", "; + } + name, typ, tag, xxx := val.Type().(reflect.StructType).Field(i); + fld := val.Field(i); + if name != "" && name != "?" { // BUG? Shouldn't the reflect library hide "?" ? + s += name + "="; + } + kind := fld.Kind(); + switch { + case kind == reflect.StructKind: + s += printStructValue(fld.(reflect.StructValue)); + case kind == reflect.Uint32Kind && tag == "ipv4": + i := fld.(reflect.Uint32Value).Get(); + s += fmt.Sprintf("%d.%d.%d.%d", (i>>24)&0xFF, (i>>16)&0xFF, (i>>8)&0xFF, i&0xFF); + default: + s += fmt.Sprint(fld.Interface()) + } + } + s += "}"; + return s; +} + +func printStruct(any interface{}) string { + val := reflect.NewValue(any).(reflect.PtrValue).Sub().(reflect.StructValue); + s := printStructValue(val); + return s +} + +// Resource record packer. +func packRR(rr _DNS_RR, 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 _DNS_RR, off1 int, ok bool) { + // unpack just the header, to find the rr type and length + var h _DNS_RR_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 __DNS_Msg_Top struct { + id uint16; + response bool; + opcode int; + authoritative bool; + truncated bool; + recursion_desired bool; + recursion_available bool; + rcode int; +} + +type _DNS_Msg struct { + __DNS_Msg_Top; + question []_DNS_Question; + answer []_DNS_RR; + ns []_DNS_RR; + extra []_DNS_RR; +} + + +func (dns *_DNS_Msg) Pack() (msg []byte, ok bool) { + var dh __DNS_Header; + + // Convert convenient _DNS_Msg into wire-like __DNS_Header. + 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 = packStruct(answer[i], msg, off); + } + for i := 0; i < len(ns); i++ { + off, ok = packStruct(ns[i], msg, off); + } + for i := 0; i < len(extra); i++ { + off, ok = packStruct(extra[i], msg, off); + } + if !ok { + return nil, false + } + return msg[0:off], true +} + +func (dns *_DNS_Msg) Unpack(msg []byte) bool { + // Header. + var dh __DNS_Header; + 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([]_DNS_Question, dh.qdcount); + dns.answer = make([]_DNS_RR, dh.ancount); + dns.ns = make([]_DNS_RR, dh.nscount); + dns.extra = make([]_DNS_RR, 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 *_DNS_Msg) String() string { + s := "DNS: "+printStruct(&dns.__DNS_Msg_Top)+"\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/fd.go b/src/pkg/net/fd.go new file mode 100644 index 000000000..9404ed0bd --- /dev/null +++ b/src/pkg/net/fd.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. + +// TODO(rsc): All the prints in this file should go to standard error. + +package net + +import ( + "net"; + "once"; + "os"; + "sync"; + "syscall"; +) + +// Network file descriptor. +type netFD struct { + // immutable until Close + fd int; + file *os.File; + cr chan *netFD; + cw chan *netFD; + net string; + laddr string; + raddr string; + + // 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; +} + +// 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. + +type pollServer struct { + cr, cw chan *netFD; // buffered >= 1 + pr, pw *os.File; + pending map[int] *netFD; + poll *pollster; // low-level OS hooks + deadline int64; // next deadline (nsec since 1970) +} +func (s *pollServer) Run(); + +func newPollServer() (s *pollServer, err os.Error) { + s = new(pollServer); + s.cr = make(chan *netFD, 1); + s.cw = make(chan *netFD, 1); + if s.pr, s.pw, err = os.Pipe(); err != nil { + return nil, err + } + var e int; + if e = syscall.SetNonblock(s.pr.Fd(), true); e != 0 { + Errno: + err = os.ErrnoToError(e); + Error: + s.pr.Close(); + s.pw.Close(); + return nil, err; + } + if e = syscall.SetNonblock(s.pw.Fd(), true); e != 0 { + goto Errno; + } + if s.poll, err = newpollster(); err != nil { + goto Error; + } + if err = s.poll.AddFD(s.pr.Fd(), 'r', true); err != nil { + s.poll.Close(); + goto Error + } + s.pending = make(map[int] *netFD); + go s.Run(); + return s, nil +} + +func (s *pollServer) AddFD(fd *netFD, mode int) { + // TODO(rsc): This check handles a race between + // one goroutine reading and another one closing, + // but it doesn't solve the race completely: + // it still could happen that one goroutine closes + // but we read fd.fd before it does, and then + // another goroutine creates a new open file with + // that fd, which we'd now be referring to. + // The fix is probably to send the Close call + // through the poll server too, except that + // not all Reads and Writes go through the poll + // server even now. + intfd := fd.fd; + if intfd < 0 { + // fd closed underfoot + if mode == 'r' { + fd.cr <- fd + } else { + fd.cw <- fd + } + return + } + if err := s.poll.AddFD(intfd, mode, false); err != nil { + panicln("pollServer AddFD ", intfd, ": ", err.String(), "\n"); + return + } + + var t int64; + key := intfd << 1; + if mode == 'r' { + fd.ncr++; + t = fd.rdeadline; + } else { + fd.ncw++; + key++; + t = fd.wdeadline; + } + s.pending[key] = fd; + if t > 0 && (s.deadline == 0 || t < s.deadline) { + s.deadline = t; + } +} + +func (s *pollServer) LookupFD(fd int, mode int) *netFD { + key := fd << 1; + if mode == 'w' { + key++; + } + netfd, ok := s.pending[key]; + if !ok { + return nil + } + s.pending[key] = nil, false; + return netfd +} + +func (s *pollServer) WakeFD(fd *netFD, mode int) { + if mode == 'r' { + for fd.ncr > 0 { + fd.ncr--; + fd.cr <- fd + } + } else { + for fd.ncw > 0 { + fd.ncw--; + fd.cw <- fd + } + } +} + +func (s *pollServer) Now() int64 { + sec, nsec, err := os.Time(); + if err != nil { + panic("net: os.Time: ", err.String()); + } + nsec += sec * 1e9; + return nsec; +} + +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.fd, mode); + fd.rdeadline = -1; + } else { + s.poll.DelFD(fd.fd, mode); + fd.wdeadline = -1; + } + s.WakeFD(fd, mode); + } else if next_deadline == 0 || t < next_deadline { + next_deadline = t; + } + } + } + s.deadline = next_deadline; +} + +func (s *pollServer) Run() { + var scratch [100]byte; + for { + var t = s.deadline; + if t > 0 { + t = t - s.Now(); + if t < 0 { + s.CheckDeadlines(); + continue; + } + } + fd, mode, err := s.poll.WaitFD(t); + if err != nil { + print("pollServer WaitFD: ", err.String(), "\n"); + return + } + if fd < 0 { + // Timeout happened. + s.CheckDeadlines(); + continue; + } + if fd == s.pr.Fd() { + // Drain our wakeup pipe. + for nn, e := s.pr.Read(&scratch); nn > 0; { + nn, e = s.pr.Read(&scratch) + } + + // Read from channels + for fd, ok := <-s.cr; ok; fd, ok = <-s.cr { + s.AddFD(fd, 'r') + } + for fd, ok := <-s.cw; ok; fd, ok = <-s.cw { + s.AddFD(fd, 'w') + } + } else { + netfd := s.LookupFD(fd, mode); + if netfd == nil { + print("pollServer: unexpected wakeup for fd=", netfd, " mode=", string(mode), "\n"); + continue + } + s.WakeFD(netfd, mode); + } + } +} + +var wakeupbuf [1]byte; +func (s *pollServer) Wakeup() { + s.pw.Write(&wakeupbuf) +} + +func (s *pollServer) WaitRead(fd *netFD) { + s.cr <- fd; + s.Wakeup(); + <-fd.cr +} + +func (s *pollServer) WaitWrite(fd *netFD) { + s.cw <- fd; + s.Wakeup(); + <-fd.cw +} + + +// Network FD methods. +// All the network FDs use a single pollServer. + +var pollserver *pollServer + +func _StartServer() { + p, err := newPollServer(); + if err != nil { + print("Start pollServer: ", err.String(), "\n") + } + pollserver = p +} + +func newFD(fd int, net, laddr, raddr string) (f *netFD, err os.Error) { + if pollserver == nil { + once.Do(_StartServer); + } + if e := syscall.SetNonblock(fd, true); e != 0 { + return nil, os.ErrnoToError(e); + } + f = new(netFD); + f.fd = fd; + f.net = net; + f.laddr = laddr; + f.raddr = raddr; + f.file = os.NewFile(fd, "net: " + net + " " + laddr + " " + raddr); + f.cr = make(chan *netFD, 1); + f.cw = make(chan *netFD, 1); + return f, nil +} + +func (fd *netFD) Close() os.Error { + if fd == nil || fd.file == nil { + return os.EINVAL + } + + // 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.file.Fd(), false); + + e := fd.file.Close(); + fd.file = nil; + fd.fd = -1; + return e +} + +func (fd *netFD) Read(p []byte) (n int, err os.Error) { + if fd == nil || fd.file == nil { + return -1, os.EINVAL + } + fd.rio.Lock(); + defer fd.rio.Unlock(); + if fd.rdeadline_delta > 0 { + fd.rdeadline = pollserver.Now() + fd.rdeadline_delta; + } else { + fd.rdeadline = 0; + } + n, err = fd.file.Read(p); + for err == os.EAGAIN && fd.rdeadline >= 0 { + pollserver.WaitRead(fd); + n, err = fd.file.Read(p) + } + return n, err +} + +func (fd *netFD) Write(p []byte) (n int, err os.Error) { + if fd == nil || fd.file == nil { + return -1, os.EINVAL + } + fd.wio.Lock(); + defer fd.wio.Unlock(); + if fd.wdeadline_delta > 0 { + fd.wdeadline = pollserver.Now() + fd.wdeadline_delta; + } else { + fd.wdeadline = 0; + } + err = nil; + nn := 0; + for nn < len(p) { + n, err = fd.file.Write(p[nn:len(p)]); + if n > 0 { + nn += n + } + if nn == len(p) { + break; + } + if err == os.EAGAIN && fd.wdeadline >= 0 { + pollserver.WaitWrite(fd); + continue; + } + if n == 0 || err != nil { + break; + } + } + return nn, err +} + +func sockaddrToString(sa syscall.Sockaddr) (name string, err os.Error) + +func (fd *netFD) accept() (nfd *netFD, err os.Error) { + if fd == nil || fd.file == nil { + return nil, os.EINVAL + } + + // See ../syscall/exec.go for description of ForkLock. + // It is okay to hold the lock across syscall.Accept + // because we have put fd.fd into non-blocking mode. + syscall.ForkLock.RLock(); + var s, e int; + var sa syscall.Sockaddr; + for { + s, sa, e = syscall.Accept(fd.fd); + if e != syscall.EAGAIN { + break; + } + syscall.ForkLock.RUnlock(); + pollserver.WaitRead(fd); + syscall.ForkLock.RLock(); + } + if e != 0 { + syscall.ForkLock.RUnlock(); + return nil, os.ErrnoToError(e) + } + syscall.CloseOnExec(s); + syscall.ForkLock.RUnlock(); + + raddr, err1 := sockaddrToString(sa); + if err1 != nil { + raddr = "invalid-address"; + } + if nfd, err = newFD(s, fd.net, fd.laddr, raddr); err != nil { + syscall.Close(s); + return nil, err + } + return nfd, nil +} + diff --git a/src/pkg/net/fd_darwin.go b/src/pkg/net/fd_darwin.go new file mode 100644 index 000000000..42bf51221 --- /dev/null +++ b/src/pkg/net/fd_darwin.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. + +// Waiting for FDs via kqueue/kevent. + +package net + +import ( + "net"; + "os"; + "syscall"; +) + +var kqueuePhaseError = &Error{"kqueue phase error"} + +type pollster struct { + kq int; + eventbuf [10]syscall.Kevent_t; + events []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.ErrnoToError(e) + } + p.events = p.eventbuf[0:0]; + return p, nil +} + +func (p *pollster) AddFD(fd int, mode int, repeat bool) os.Error { + var kmode int; + if mode == 'r' { + kmode = syscall.EVFILT_READ + } else { + kmode = syscall.EVFILT_WRITE + } + var events [1]syscall.Kevent_t; + ev := &events[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, &events, &events, nil); + if e != 0 { + return os.ErrnoToError(e) + } + if n != 1 || (ev.Flags & syscall.EV_ERROR) == 0 || int(ev.Ident) != fd || int(ev.Filter) != kmode { + return kqueuePhaseError + } + if ev.Data != 0 { + return os.ErrnoToError(int(ev.Data)) + } + return nil +} + +func (p *pollster) DelFD(fd int, mode int) { + var kmode int; + if mode == 'r' { + kmode = syscall.EVFILT_READ + } else { + kmode = syscall.EVFILT_WRITE + } + var events [1]syscall.Kevent_t; + ev := &events[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, &events, &events, nil); +} + +func (p *pollster) WaitFD(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); + } + nn, e := syscall.Kevent(p.kq, nil, &p.eventbuf, t); + if e != 0 { + if e == syscall.EINTR { + continue + } + return -1, 0, os.ErrnoToError(e) + } + if nn == 0 { + return -1, 0, nil; + } + p.events = p.eventbuf[0:nn] + } + ev := &p.events[0]; + p.events = p.events[1:len(p.events)]; + 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.ErrnoToError(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..bd822589e --- /dev/null +++ b/src/pkg/net/fd_linux.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. + +// Waiting for FDs via epoll(7). + +package net + +import ( + "net"; + "os"; + "syscall"; +) + +const ( + readFlags = syscall.EPOLLIN | syscall.EPOLLRDHUP; + writeFlags = syscall.EPOLLOUT +) + +type pollster struct { + epfd int; + + // Events we're already waiting for + events map[int] uint32; +} + +func newpollster() (p *pollster, err os.Error) { + p = new(pollster); + var e int; + + // The arg to epoll_create is a hint to the kernel + // about the number of FDs we will care about. + // We don't know. + if p.epfd, e = syscall.EpollCreate(16); e != 0 { + return nil, os.ErrnoToError(e) + } + p.events = make(map[int] uint32); + return p, nil +} + +func (p *pollster) AddFD(fd int, mode int, repeat bool) os.Error { + var ev syscall.EpollEvent; + var already bool; + ev.Fd = int32(fd); + ev.Events, already = p.events[fd]; + if !repeat { + ev.Events |= syscall.EPOLLONESHOT; + } + if mode == 'r' { + ev.Events |= readFlags; + } else { + ev.Events |= writeFlags; + } + + var op int; + if already { + op = syscall.EPOLL_CTL_MOD; + } else { + op = syscall.EPOLL_CTL_ADD; + } + if e := syscall.EpollCtl(p.epfd, op, fd, &ev); e != 0 { + return os.ErrnoToError(e) + } + p.events[fd] = ev.Events; + return nil +} + +func (p *pollster) StopWaiting(fd int, bits uint) { + events, already := p.events[fd]; + if !already { + print("Epoll unexpected fd=", fd, "\n"); + return; + } + + // If syscall.EPOLLONESHOT is not set, the wait + // is a repeating wait, so don't change it. + if events & syscall.EPOLLONESHOT == 0 { + return; + } + + // Disable the given bits. + // If we're still waiting for other events, modify the fd + // event in the kernel. Otherwise, delete it. + events &= ^uint32(bits); + if int32(events) & ^syscall.EPOLLONESHOT != 0 { + var ev syscall.EpollEvent; + ev.Fd = int32(fd); + ev.Events = events; + if e := syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_MOD, fd, &ev); e != 0 { + print("Epoll modify fd=", fd, ": ", os.ErrnoToError(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.ErrnoToError(e).String(), "\n"); + } + p.events[fd] = 0, false; + } +} + +func (p *pollster) DelFD(fd int, mode int) { + if mode == 'r' { + p.StopWaiting(fd, readFlags); + } else { + p.StopWaiting(fd, writeFlags); + } +} + +func (p *pollster) WaitFD(nsec int64) (fd int, mode int, err os.Error) { + // Get an event. + var evarray [1]syscall.EpollEvent; + ev := &evarray[0]; + var msec int = -1; + if nsec > 0 { + msec = int((nsec + 1e6 - 1)/1e6); + } + n, e := syscall.EpollWait(p.epfd, &evarray, msec); + for e == syscall.EAGAIN || e == syscall.EINTR { + n, e = syscall.EpollWait(p.epfd, &evarray, msec); + } + if e != 0 { + return -1, 0, os.ErrnoToError(e); + } + if n == 0 { + return -1, 0, nil; + } + fd = int(ev.Fd); + + if ev.Events & writeFlags != 0 { + p.StopWaiting(fd, writeFlags); + return fd, 'w', nil; + } + if ev.Events & readFlags != 0 { + p.StopWaiting(fd, readFlags); + return fd, 'r', nil; + } + + // Other events are error conditions - wake whoever is waiting. + events, already := 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.ErrnoToError(syscall.Close(p.epfd)); +} diff --git a/src/pkg/net/ip.go b/src/pkg/net/ip.go new file mode 100644 index 000000000..774f048ca --- /dev/null +++ b/src/pkg/net/ip.go @@ -0,0 +1,421 @@ +// Copyright 2009 The Go 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 ( + "net" +) + +// IP address lengths (bytes). +const ( + IPv4len = 4; + IPv6len = 16 +) + +// An IP is a single IP address, an array of bytes. +// Functions in this package accept either 4-byte (IP v4) +// or 16-byte (IP v6) arrays as input. Unless otherwise +// specified, functions in this package always return +// IP addresses in 16-byte form using the canonical +// embedding. +// +// Note that in this documentation, referring to an +// IP address as an IPv4 address or an IPv6 address +// is a semantic property of the address, not just the +// length of the byte array: a 16-byte array can still +// be an IPv4 address. +type IP []byte; + +// An IP mask is an IP address. +type IPMask []byte; + +// IPv4 returns the IP address (in 16-byte form) of the +// IPv4 address a.b.c.d. +func IPv4(a, b, c, d byte) IP { + p := make(IP, IPv6len); + for i := 0; i < 10; i++ { + p[i] = 0 + } + p[10] = 0xff; + p[11] = 0xff; + p[12] = a; + p[13] = b; + p[14] = c; + p[15] = d; + return p +} + +// Well-known IPv4 addresses +var ( + IPv4bcast = IPv4(255, 255, 255, 255); // broadcast + IPv4allsys = IPv4(224, 0, 0, 1); // all systems + IPv4allrouter = IPv4(224, 0, 0, 2); // all routers + IPv4zero = IPv4(0, 0, 0, 0); // all zeros +) + +// Well-known IPv6 addresses +var ( + IPzero = make(IP, IPv6len); // all zeros +) + +// Is p all zeros? +func isZeros(p IP) bool { + for i := 0; i < len(p); i++ { + if p[i] != 0 { + return false + } + } + return true +} + +// To4 converts the IPv4 address ip to a 4-byte representation. +// If ip is not an IPv4 address, To4 returns nil. +func (ip IP) To4() IP { + if len(ip) == IPv4len { + return ip + } + if len(ip) == IPv6len + && isZeros(ip[0:10]) + && ip[10] == 0xff + && ip[11] == 0xff { + return ip[12:16] + } + return nil +} + +// To16 converts the IP address ip to a 16-byte representation. +// If ip is not an IP address (it is the wrong length), To16 returns nil. +func (ip IP) To16() IP { + if len(ip) == IPv4len { + return IPv4(ip[0], ip[1], ip[2], ip[3]) + } + if len(ip) == IPv6len { + return ip + } + return nil +} + +// Default route masks for IPv4. +var ( + classAMask = IPMask(IPv4(0xff, 0, 0, 0)); + classBMask = IPMask(IPv4(0xff, 0xff, 0, 0)); + classCMask = IPMask(IPv4(0xff, 0xff, 0xff, 0)); +) + +// DefaultMask returns the default IP mask for the IP address ip. +// Only IPv4 addresses have default masks; DefaultMask returns +// nil if ip is not a valid IPv4 address. +func (ip IP) DefaultMask() IPMask { + if ip = ip.To4(); ip == nil { + return nil + } + switch true { + case ip[0] < 0x80: + return classAMask; + case ip[0] < 0xC0: + return classBMask; + default: + return classCMask; + } + return nil; // not reached +} + +// Mask returns the result of masking the IP address ip with mask. +func (ip IP) Mask(mask IPMask) IP { + n := len(ip); + if n != len(mask) { + return nil + } + out := make(IP, n); + for i := 0; i < n; i++ { + out[i] = ip[i] & mask[i]; + } + return out +} + +// Convert i to decimal string. +func itod(i uint) string { + if i == 0 { + return "0" + } + + // Assemble decimal in reverse order. + var b [32]byte; + bp := len(b); + for ; i > 0; i /= 10 { + bp--; + b[bp] = byte(i%10) + '0' + } + + return string(b[bp:len(b)]) +} + +// 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:len(b)]) +} + +// 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 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 + } + } + + // Print with possible :: in place of run of zeros + var s string; + for i := 0; i < 16; i += 2 { + if i == e0 { + s += "::"; + i = e1; + if i >= 16 { + break + } + } else if i > 0 { + s += ":" + } + s += itox((uint(p[i])<<8) | uint(p[i+1])) + } + return s +} + +// If mask is a sequence of 1 bits followed by 0 bits, +// return the number of 1 bits. +func simpleMaskLength(mask IPMask) int { + var i int; + for i = 0; i < len(mask); i++ { + if mask[i] != 0xFF { + break + } + } + n := 8*i; + v := mask[i]; + for v & 0x80 != 0 { + n++; + v <<= 1 + } + if v != 0 { + return -1 + } + for i++; i < len(mask); i++ { + if mask[i] != 0 { + return -1 + } + } + 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 >= 0 { + return itod(uint(n)) + } + } + 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 j > 0 { + if s[i] != '.' { + return nil + } + i++; + } + var ( + n int; + ok bool + ) + n, i, ok = dtoi(s, i); + if !ok || n > 0xFF { + return nil + } + p[j] = byte(n) + } + if i != len(s) { + return nil + } + return IPv4(p[0], p[1], p[2], p[3]) +} + +// Parse IPv6 address. Many forms. +// The basic form is a sequence of eight colon-separated +// 16-bit hex numbers separated by colons, +// as in 0123:4567:89ab:cdef:0123:4567:89ab:cdef. +// Two exceptions: +// * A run of zeros can be replaced with "::". +// * The last 32 bits can be in IPv4 form. +// Thus, ::ffff:1.2.3.4 is the IPv4 address 1.2.3.4. +func parseIPv6(s string) IP { + p := make(IP, 16); + ellipsis := -1; // position of ellipsis in p + i := 0; // index in string s + + // Might have leading ellipsis + if len(s) >= 2 && s[0] == ':' && s[1] == ':' { + ellipsis = 0; + i = 2; + // Might be only ellipsis + if i == len(s) { + return p + } + } + + // Loop, parsing hex numbers followed by colon. + j := 0; +L: for j < IPv6len { + // Hex number. + n, i1, ok := xtoi(s, i); + if !ok || n > 0xFFFF { + return nil + } + + // If followed by dot, might be in trailing IPv4. + if i1 < len(s) && s[i1] == '.' { + if ellipsis < 0 && j != IPv6len - IPv4len { + // Not the right place. + return nil + } + if j+IPv4len > IPv6len { + // Not enough room. + return nil + } + p4 := parseIPv4(s[i:len(s)]); + if p4 == nil { + return nil + } + // BUG: p[j:j+4] = p4 + p[j] = p4[12]; + p[j+1] = p4[13]; + p[j+2] = p4[14]; + p[j+3] = p4[15]; + i = len(s); + j += 4; + break + } + + // Save this 16-bit chunk. + p[j] = byte(n>>8); + p[j+1] = byte(n); + j += 2; + + // Stop at end of string. + i = i1; + if i == len(s) { + break + } + + // Otherwise must be followed by colon and more. + if s[i] != ':' && i+1 == len(s) { + return nil + } + i++; + + // Look for ellipsis. + if s[i] == ':' { + if ellipsis >= 0 { // already have one + return nil + } + ellipsis = j; + if i++; i == len(s) { // can be at end + break + } + } + } + + // Must have used entire string. + if i != len(s) { + return nil + } + + // If didn't parse enough, expand ellipsis. + if j < IPv6len { + if ellipsis < 0 { + return nil + } + n := IPv6len - j; + for k := j-1; k >= ellipsis; k-- { + p[k+n] = p[k] + } + for k := ellipsis+n-1; k>=ellipsis; k-- { + p[k] = 0 + } + } + return p +} + +// ParseIP parses s as an IP address, returning the result. +// The string s can be in dotted decimal ("74.125.19.99") +// or IPv6 ("2001:4860:0:2001::68") form. +// If s is not a valid textual representation of an IP address, +// ParseIP returns nil. +func ParseIP(s string) IP { + p := parseIPv4(s); + if p != nil { + return p + } + return parseIPv6(s) +} + diff --git a/src/pkg/net/ip_test.go b/src/pkg/net/ip_test.go new file mode 100644 index 000000000..fb2ae8216 --- /dev/null +++ b/src/pkg/net/ip_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 ( + "net"; + "testing" +) + +func isEqual(a, b IP) bool { + if a == nil && b == nil { + return true + } + if a == nil || b == nil || len(a) != len(b) { + return false + } + for i := 0; i < len(a); i++ { + if a[i] != b[i] { + return false + } + } + return true +} + +type parseIPTest struct { + in string; + out IP; +} +var parseiptests = []parseIPTest{ + parseIPTest{"127.0.1.2", IPv4(127, 0, 1, 2)}, + parseIPTest{"127.0.0.1", IPv4(127, 0, 0, 1)}, + parseIPTest{"127.0.0.256", nil}, + parseIPTest{"abc", nil}, + parseIPTest{"::ffff:127.0.0.1", IPv4(127, 0, 0, 1)}, + parseIPTest{"2001:4860:0:2001::68", + IP{0x20,0x01, 0x48,0x60, 0,0, 0x20,0x01, + 0,0, 0,0, 0,0, 0x00,0x68}}, + parseIPTest{"::ffff:4a7d:1363", IPv4(74, 125, 19, 99)}, +} + +func TestParseIP(t *testing.T) { + for i := 0; i < len(parseiptests); i++ { + tt := parseiptests[i]; + if out := ParseIP(tt.in); !isEqual(out, tt.out) { + t.Errorf("ParseIP(%#q) = %v, want %v", tt.in, out, tt.out); + } + } +} diff --git a/src/pkg/net/net.go b/src/pkg/net/net.go new file mode 100644 index 000000000..5c442e6a4 --- /dev/null +++ b/src/pkg/net/net.go @@ -0,0 +1,862 @@ +// Copyright 2009 The Go Authors. 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 ( + "net"; + "os"; + "strconv"; + "syscall"; +) + +var ( + BadAddress os.Error = &Error{"malformed address"}; + MissingAddress os.Error = &Error{"missing address"}; + UnknownNetwork os.Error = &Error{"unknown network"}; + UnknownHost os.Error = &Error{"unknown host"}; + UnknownSocketFamily os.Error = &Error{"unknown socket family"}; +) + + +// Conn is a generic network connection. +type Conn interface { + // Read blocks until data is ready from the connection + // and then reads into b. It returns the number + // of bytes read, or 0 if the connection has been closed. + Read(b []byte) (n int, err os.Error); + + // Write writes the data in b to the connection. + Write(b []byte) (n int, err os.Error); + + // Close closes the connection. + Close() os.Error; + + // For packet-based protocols such as UDP, + // ReadFrom reads the next packet from the network, + // returning the number of bytes read and the remote + // address that sent them. + ReadFrom(b []byte) (n int, addr string, err os.Error); + + // For packet-based protocols such as UDP, + // WriteTo writes the byte buffer b to the network + // as a single payload, sending it to the target address. + WriteTo(addr string, b []byte) (n int, err os.Error); + + // SetReadBuffer sets the size of the operating system's + // receive buffer associated with the connection. + SetReadBuffer(bytes int) os.Error; + + // SetReadBuffer sets the size of the operating system's + // transmit buffer associated with the connection. + SetWriteBuffer(bytes int) os.Error; + + // 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 os.EAGAIN. + // 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 os.EAGAIN. + // 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; + + // 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. + SetLinger(sec int) os.Error; + + // SetReuseAddr sets whether it is okay to reuse addresses + // from recent connections that were not properly closed. + SetReuseAddr(reuseaddr bool) os.Error; + + // SetDontRoute sets whether outgoing messages should + // bypass the system routing tables. + SetDontRoute(dontroute bool) os.Error; + + // SetKeepAlive sets whether the operating system should send + // keepalive messages on the connection. + SetKeepAlive(keepalive bool) os.Error; + + // BindToDevice binds a connection to a particular network device. + BindToDevice(dev string) os.Error; +} + +// Should we try to use the IPv4 socket interface if we're +// only dealing with IPv4 sockets? As long as the host system +// understands IPv6, it's okay to pass IPv4 addresses to the IPv6 +// interface. That simplifies our code and is most general. +// Unfortunately, we need to run on kernels built without IPv6 support too. +// So probe the kernel to figure it out. +func kernelSupportsIPv6() bool { + fd, e := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP); + if fd >= 0 { + syscall.Close(fd) + } + return e == 0 +} + +var preferIPv4 = !kernelSupportsIPv6() + +// TODO(rsc): if syscall.OS == "linux", we're supposd to read +// /proc/sys/net/core/somaxconn, +// to take advantage of kernels that have raised the limit. +func listenBacklog() int { + return syscall.SOMAXCONN +} + +func LookupHost(name string) (cname string, addrs []string, err os.Error) + +// Split "host:port" into "host" and "port". +// Host cannot contain colons unless it is bracketed. +func splitHostPort(hostport string) (host, port string, err os.Error) { + // The port starts after the last colon. + var i int; + for i = len(hostport)-1; i >= 0; i-- { + if hostport[i] == ':' { + break + } + } + if i < 0 { + return "", "", BadAddress + } + + host = hostport[0:i]; + port = hostport[i+1:len(hostport)]; + + // 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 { + return "", "", BadAddress + } + } + return host, port, nil +} + +// Join "host" and "port" into "host:port". +// If host contains colons, will join into "[host]:port". +func joinHostPort(host, port string) string { + // If host has colons, have to bracket it. + if byteIndex(host, ':') >= 0 { + return "[" + host + "]:" + port + } + return host + ":" + port +} + +// Convert "host:port" into IP address and port. +// For now, host and port must be numeric literals. +// Eventually, we'll have name resolution. +func hostPortToIP(net, hostport, mode string) (ip IP, iport int, err os.Error) { + var host, port string; + host, port, err = splitHostPort(hostport); + if err != nil { + return nil, 0, err + } + + var addr IP; + if host == "" { + if mode == "listen" { + if preferIPv4 { + addr = IPv4zero; + } else { + addr = IPzero; // wildcard - listen to all + } + } else { + return nil, 0, MissingAddress; + } + } + + // Try as an IP address. + if addr == nil { + addr = ParseIP(host); + } + if addr == nil { + // Not an IP address. Try as a DNS name. + hostname, addrs, err := LookupHost(host); + if err != nil { + return nil, 0, err + } + if len(addrs) == 0 { + return nil, 0, UnknownHost + } + addr = ParseIP(addrs[0]); + if addr == nil { + // should not happen + return nil, 0, BadAddress + } + } + + p, i, ok := dtoi(port, 0); + if !ok || i != len(port) { + p, err = LookupPort(net, port); + if err != nil { + return nil, 0, err + } + } + if p < 0 || p > 0xFFFF { + return nil, 0, BadAddress + } + + return addr, p, nil +} + +func sockaddrToString(sa syscall.Sockaddr) (name string, err os.Error) { + switch a := sa.(type) { + case *syscall.SockaddrInet4: + return joinHostPort(IP(&a.Addr).String(), strconv.Itoa(a.Port)), nil; + case *syscall.SockaddrInet6: + return joinHostPort(IP(&a.Addr).String(), strconv.Itoa(a.Port)), nil; + case *syscall.SockaddrUnix: + return a.Name, nil; + } + return "", UnknownSocketFamily +} + +func ipToSockaddr(family int, ip IP, port int) (syscall.Sockaddr, os.Error) { + switch family { + case syscall.AF_INET: + if ip = ip.To4(); ip == nil { + return nil, os.EINVAL + } + 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: + // IPv4 callers use 0.0.0.0 to mean "announce on any available address". + // In IPv6 mode, Linux treats that as meaning "announce on 0.0.0.0", + // which it refuses to do. Rewrite to the IPv6 all zeros. + if p4 := ip.To4(); p4 != nil && p4[0] == 0 && p4[1] == 0 && p4[2] == 0 && p4[3] == 0 { + ip = IPzero; + } + if ip = ip.To16(); ip == nil { + return nil, os.EINVAL + } + s := new(syscall.SockaddrInet6); + for i := 0; i < IPv6len; i++ { + s.Addr[i] = ip[i]; + } + s.Port = port; + return s, nil; + } + return nil, os.EINVAL; +} + +// Boolean to int. +func boolint(b bool) int { + if b { + return 1 + } + return 0 +} + +// Generic socket creation. +func socket(net, laddr, raddr string, f, p, t int, la, ra syscall.Sockaddr) (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.ErrnoToError(e) + } + syscall.CloseOnExec(s); + syscall.ForkLock.RUnlock(); + + // Allow reuse of recently-used addresses. + syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); + + var r int64; + if la != nil { + e = syscall.Bind(s, la); + if e != 0 { + syscall.Close(s); + return nil, os.ErrnoToError(e) + } + } + + if ra != nil { + e = syscall.Connect(s, ra); + if e != 0 { + syscall.Close(s); + return nil, os.ErrnoToError(e) + } + } + + fd, err = newFD(s, net, laddr, raddr); + if err != nil { + syscall.Close(s); + return nil, err + } + + return fd, nil +} + + +// Generic implementation of Conn interface; not exported. +type connBase struct { + fd *netFD; + raddr string; +} + +func (c *connBase) File() *os.File { + if c == nil { + return nil + } + return c.fd.file; +} + +func (c *connBase) sysFD() int { + if c == nil || c.fd == nil { + return -1; + } + return c.fd.fd; +} + +func (c *connBase) Read(b []byte) (n int, err os.Error) { + n, err = c.fd.Read(b); + return n, err +} + +func (c *connBase) Write(b []byte) (n int, err os.Error) { + n, err = c.fd.Write(b); + return n, err +} + +func (c *connBase) ReadFrom(b []byte) (n int, raddr string, err os.Error) { + if c == nil { + return -1, "", os.EINVAL + } + n, err = c.Read(b); + return n, c.raddr, err +} + +func (c *connBase) WriteTo(raddr string, b []byte) (n int, err os.Error) { + if c == nil { + return -1, os.EINVAL + } + if raddr != c.raddr { + return -1, os.EINVAL + } + n, err = c.Write(b); + return n, err +} + +func (c *connBase) Close() os.Error { + if c == nil { + return os.EINVAL + } + return c.fd.Close() +} + + +func setsockoptInt(fd, level, opt int, value int) os.Error { + return os.ErrnoToError(syscall.SetsockoptInt(fd, level, opt, value)); +} + +func setsockoptNsec(fd, level, opt int, nsec int64) os.Error { + var tv = syscall.NsecToTimeval(nsec); + return os.ErrnoToError(syscall.SetsockoptTimeval(fd, level, opt, &tv)); +} + +func (c *connBase) SetReadBuffer(bytes int) os.Error { + return setsockoptInt(c.sysFD(), syscall.SOL_SOCKET, syscall.SO_RCVBUF, bytes); +} + +func (c *connBase) SetWriteBuffer(bytes int) os.Error { + return setsockoptInt(c.sysFD(), syscall.SOL_SOCKET, syscall.SO_SNDBUF, bytes); +} + +func (c *connBase) SetReadTimeout(nsec int64) os.Error { + c.fd.rdeadline_delta = nsec; + return nil; +} + +func (c *connBase) SetWriteTimeout(nsec int64) os.Error { + c.fd.wdeadline_delta = nsec; + return nil; +} + +func (c *connBase) SetTimeout(nsec int64) os.Error { + if e := c.SetReadTimeout(nsec); e != nil { + return e + } + return c.SetWriteTimeout(nsec) +} + +func (c *connBase) SetReuseAddr(reuse bool) os.Error { + return setsockoptInt(c.sysFD(), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, boolint(reuse)); +} + +func (c *connBase) BindToDevice(dev string) os.Error { + // TODO(rsc): call setsockopt with null-terminated string pointer + return os.EINVAL +} + +func (c *connBase) SetDontRoute(dontroute bool) os.Error { + return setsockoptInt(c.sysFD(), syscall.SOL_SOCKET, syscall.SO_DONTROUTE, boolint(dontroute)); +} + +func (c *connBase) SetKeepAlive(keepalive bool) os.Error { + return setsockoptInt(c.sysFD(), syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, boolint(keepalive)); +} + +func (c *connBase) SetLinger(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; + } + e := syscall.SetsockoptLinger(c.sysFD(), syscall.SOL_SOCKET, syscall.SO_LINGER, &l); + return os.ErrnoToError(e); +} + + +// Internet sockets (TCP, UDP) + +func internetSocket(net, laddr, raddr string, proto int, mode string) (fd *netFD, err os.Error) { + // Parse addresses (unless they are empty). + var lip, rip IP; + var lport, rport int; + var lerr, rerr os.Error; + + if laddr != "" { + lip, lport, lerr = hostPortToIP(net, laddr, mode); + if lerr != nil { + return nil, lerr + } + } + if raddr != "" { + rip, rport, rerr = hostPortToIP(net, raddr, mode); + if rerr != nil { + return nil, rerr + } + } + + // Figure out IP version. + // If network has a suffix like "tcp4", obey it. + vers := 0; + switch net[len(net)-1] { + case '4': + vers = 4; + case '6': + vers = 6; + default: + // Otherwise, guess. + // If the addresses are IPv4 and we prefer IPv4, use 4; else 6. + if preferIPv4 && (lip == nil || lip.To4() != nil) && (rip == nil || rip.To4() != nil) { + vers = 4 + } else { + vers = 6 + } + } + + var family int; + if vers == 4 { + family = syscall.AF_INET + } else { + family = syscall.AF_INET6 + } + + var la, ra syscall.Sockaddr; + if lip != nil { + la, lerr = ipToSockaddr(family, lip, lport); + if lerr != nil { + return nil, lerr + } + } + if rip != nil { + ra, rerr = ipToSockaddr(family, rip, rport); + if rerr != nil { + return nil, rerr + } + } + + fd, err = socket(net, laddr, raddr, family, proto, 0, la, ra); + return fd, err +} + + +// TCP connections. + +// ConnTCP is an implementation of the Conn interface +// for TCP network connections. +type ConnTCP struct { + connBase +} + +func (c *ConnTCP) SetNoDelay(nodelay bool) os.Error { + if c == nil { + return os.EINVAL + } + return setsockoptInt(c.sysFD(), syscall.IPPROTO_TCP, syscall.TCP_NODELAY, boolint(nodelay)) +} + +func newConnTCP(fd *netFD, raddr string) *ConnTCP { + c := new(ConnTCP); + c.fd = fd; + c.raddr = raddr; + c.SetNoDelay(true); + return c +} + +// DialTCP is like Dial but can only connect to TCP networks +// and returns a ConnTCP structure. +func DialTCP(net, laddr, raddr string) (c *ConnTCP, err os.Error) { + if raddr == "" { + return nil, MissingAddress + } + fd, e := internetSocket(net, laddr, raddr, syscall.SOCK_STREAM, "dial"); + if e != nil { + return nil, e + } + return newConnTCP(fd, raddr), nil +} + + +// UDP connections. + +// TODO(rsc): UDP headers mode + +// ConnUDP is an implementation of the Conn interface +// for UDP network connections. +type ConnUDP struct { + connBase +} + +func newConnUDP(fd *netFD, raddr string) *ConnUDP { + c := new(ConnUDP); + c.fd = fd; + c.raddr = raddr; + return c +} + +// DialUDP is like Dial but can only connect to UDP networks +// and returns a ConnUDP structure. +func DialUDP(net, laddr, raddr string) (c *ConnUDP, err os.Error) { + if raddr == "" { + return nil, MissingAddress + } + fd, e := internetSocket(net, laddr, raddr, syscall.SOCK_DGRAM, "dial"); + if e != nil { + return nil, e + } + return newConnUDP(fd, raddr), nil +} + + +// TODO: raw IP connections + +// TODO: raw ethernet connections + + +// Unix domain sockets + +func unixSocket(net, laddr, raddr string, mode string) (fd *netFD, err os.Error) { + var proto int; + switch net { + default: + return nil, UnknownNetwork; + case "unix": + proto = syscall.SOCK_STREAM; + case "unix-dgram": + proto = syscall.SOCK_DGRAM; + } + + var la, ra syscall.Sockaddr; + switch mode { + case "dial": + if laddr != "" { + return nil, BadAddress; + } + if raddr == "" { + return nil, MissingAddress; + } + ra = &syscall.SockaddrUnix{Name: raddr}; + + case "listen": + if laddr == "" { + return nil, MissingAddress; + } + la = &syscall.SockaddrUnix{Name: laddr}; + if raddr != "" { + return nil, BadAddress; + } + } + + fd, err = socket(net, laddr, raddr, syscall.AF_UNIX, proto, 0, la, ra); + return fd, err +} + +// ConnUnix is an implementation of the Conn interface +// for connections to Unix domain sockets. +type ConnUnix struct { + connBase +} + +func newConnUnix(fd *netFD, raddr string) *ConnUnix { + c := new(ConnUnix); + c.fd = fd; + c.raddr = raddr; + return c; +} + +// DialUnix is like Dial but can only connect to Unix domain sockets +// and returns a ConnUnix structure. The laddr argument must be +// the empty string; it is included only to match the signature of +// the other dial routines. +func DialUnix(net, laddr, raddr string) (c *ConnUnix, err os.Error) { + fd, e := unixSocket(net, laddr, raddr, "dial"); + if e != nil { + return nil, e + } + return newConnUnix(fd, raddr), nil; +} + +// ListenerUnix is a Unix domain socket listener. +// Clients should typically use variables of type Listener +// instead of assuming Unix domain sockets. +type ListenerUnix struct { + fd *netFD; + laddr string +} + +// ListenUnix announces on the Unix domain socket laddr and returns a Unix listener. +// Net can be either "unix" (stream sockets) or "unix-dgram" (datagram sockets). +func ListenUnix(net, laddr string) (l *ListenerUnix, err os.Error) { + fd, e := unixSocket(net, laddr, "", "listen"); + if e != nil { + // Check for socket ``in use'' but ``refusing connections,'' + // which means some program created it and exited + // without unlinking it from the file system. + // Clean up on that program's behalf and try again. + // Don't do this for Linux's ``abstract'' sockets, which begin with @. + if e != os.EADDRINUSE || laddr[0] == '@' { + return nil, e; + } + fd1, e1 := unixSocket(net, "", laddr, "dial"); + if e1 == nil { + fd1.Close(); + } + if e1 != os.ECONNREFUSED { + return nil, e; + } + syscall.Unlink(laddr); + fd1, e1 = unixSocket(net, laddr, "", "listen"); + if e1 != nil { + return nil, e; + } + fd = fd1; + } + e1 := syscall.Listen(fd.fd, 8); // listenBacklog()); + if e1 != 0 { + syscall.Close(fd.fd); + return nil, os.ErrnoToError(e1); + } + return &ListenerUnix{fd, laddr}, nil; +} + +// AcceptUnix accepts the next incoming call and returns the new connection +// and the remote address. +func (l *ListenerUnix) AcceptUnix() (c *ConnUnix, raddr string, err os.Error) { + if l == nil || l.fd == nil || l.fd.fd < 0 { + return nil, "", os.EINVAL + } + fd, e := l.fd.accept(); + if e != nil { + return nil, "", e + } + return newConnUnix(fd, fd.raddr), raddr, nil +} + +// Accept implements the Accept method in the Listener interface; +// it waits for the next call and returns a generic Conn. +func (l *ListenerUnix) Accept() (c Conn, raddr string, err os.Error) { + // TODO(rsc): 6g bug prevents saying + // c, raddr, err = l.AcceptUnix(); + // return; + c1, r1, e1 := l.AcceptUnix(); + return c1, r1, e1; +} + + +// Close stops listening on the Unix address. +// Already accepted connections are not closed. +func (l *ListenerUnix) 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.laddr[0] != '@' { + syscall.Unlink(l.laddr); + } + err := l.fd.Close(); + l.fd = nil; + return err; +} + +// Dial connects to the remote address raddr on the network net. +// If the string laddr is not empty, it is used as the local address +// for the connection. +// +// Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only), +// "udp", "udp4" (IPv4-only), and "udp6" (IPv6-only). +// +// For IP networks, addresses have the form host:port. If host is +// a literal IPv6 address, it must be enclosed in square brackets. +// +// Examples: +// Dial("tcp", "", "12.34.56.78:80") +// Dial("tcp", "", "google.com:80") +// Dial("tcp", "", "[de:ad:be:ef::ca:fe]:80") +// Dial("tcp", "127.0.0.1:123", "127.0.0.1:88") +func Dial(net, laddr, raddr string) (c Conn, err os.Error) { + switch net { + case "tcp", "tcp4", "tcp6": + c, err := DialTCP(net, laddr, raddr); + if err != nil { + return nil, err + } + return c, nil; + case "udp", "udp4", "upd6": + c, err := DialUDP(net, laddr, raddr); + return c, err; + case "unix", "unix-dgram": + c, err := DialUnix(net, laddr, raddr); + return c, err; +/* + case "ether": + c, err := DialEther(net, laddr, raddr); + return c, err; + case "ipv4": + c, err := DialIPv4(net, laddr, raddr); + return c, err; + case "ipv6": + c, err := DialIPv6(net, laddr, raddr); + return c, err +*/ + } + return nil, UnknownNetwork +} + +// A Listener is a generic network listener. +// Accept waits for the next connection and Close closes the connection. +type Listener interface { + Accept() (c Conn, raddr string, err os.Error); + Close() os.Error; +} + +// ListenerTCP is a TCP network listener. +// Clients should typically use variables of type Listener +// instead of assuming TCP. +type ListenerTCP struct { + fd *netFD; + laddr string +} + +// ListenTCP announces on the TCP address laddr and returns a TCP listener. +// Net must be "tcp", "tcp4", or "tcp6". +func ListenTCP(net, laddr string) (l *ListenerTCP, err os.Error) { + fd, e := internetSocket(net, laddr, "", syscall.SOCK_STREAM, "listen"); + if e != nil { + return nil, e + } + e1 := syscall.Listen(fd.fd, listenBacklog()); + if e1 != 0 { + syscall.Close(fd.fd); + return nil, os.ErrnoToError(e1) + } + l = new(ListenerTCP); + l.fd = fd; + return l, nil +} + +// AcceptTCP accepts the next incoming call and returns the new connection +// and the remote address. +func (l *ListenerTCP) AcceptTCP() (c *ConnTCP, raddr string, err os.Error) { + if l == nil || l.fd == nil || l.fd.fd < 0 { + return nil, "", os.EINVAL + } + fd, e := l.fd.accept(); + if e != nil { + return nil, "", e + } + return newConnTCP(fd, fd.raddr), fd.raddr, nil +} + +// Accept implements the Accept method in the Listener interface; +// it waits for the next call and returns a generic Conn. +func (l *ListenerTCP) Accept() (c Conn, raddr string, err os.Error) { + c1, r1, e1 := l.AcceptTCP(); + if e1 != nil { + return nil, "", e1 + } + return c1, r1, nil +} + +// Close stops listening on the TCP address. +// Already Accepted connections are not closed. +func (l *ListenerTCP) Close() os.Error { + if l == nil || l.fd == nil { + return os.EINVAL + } + return l.fd.Close() +} + +// Listen announces on the local network address laddr. +// The network string net must be "tcp", "tcp4", "tcp6", +// "unix", or "unix-dgram". +func Listen(net, laddr string) (l Listener, err os.Error) { + switch net { + case "tcp", "tcp4", "tcp6": + l, err := ListenTCP(net, laddr); + if err != nil { + return nil, err; + } + return l, nil; + case "unix", "unix-dgram": + l, err := ListenUnix(net, laddr); + if err != nil { + return nil, err; + } + return l, nil; +/* + more here +*/ + // BUG(rsc): Listen should support UDP. + } + return nil, UnknownNetwork +} + diff --git a/src/pkg/net/parse.go b/src/pkg/net/parse.go new file mode 100644 index 000000000..de47cb812 --- /dev/null +++ b/src/pkg/net/parse.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. + +// Simple file i/o and string manipulation, to avoid +// depending on strconv and bufio. + +package net + +import ( + "io"; + "os"; +) + +type Error struct { + os.ErrorString +} + +type file struct { + file *os.File; + data []byte; +} + +func (f *file) close() { + f.file.Close() +} + +func (f *file) getLineFromData() (s string, ok bool) { + data := f.data; + 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; + for j := 0; j < n; j++ { + data[j] = data[i+j]; + } + f.data = data[0:n]; + return + } + } + 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.FullRead(f.file, f.data[ln:cap(f.data)]); + if n >= 0 { + f.data = f.data[0:ln+n]; + } + } + s, ok = f.getLineFromData(); + return +} + +func open(name string) (*file, os.Error) { + fd, err := os.Open(name, os.O_RDONLY, 0); + if err != nil { + return nil, err; + } + return &file{fd, make([]byte, 1024)[0:0]}, 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:len(s)]); + 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 +} + diff --git a/src/pkg/net/parse_test.go b/src/pkg/net/parse_test.go new file mode 100644 index 000000000..ce0bb4709 --- /dev/null +++ b/src/pkg/net/parse_test.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 net + +import ( + "bufio"; + "net"; + "os"; + "testing"; +) + +func TestReadLine(t *testing.T) { + filename := "/etc/services"; // a nice big file + + fd, err := os.Open(filename, os.O_RDONLY, 0); + if err != nil { + t.Fatalf("open %s: %v", filename, err); + } + br := bufio.NewReader(fd); + + var file *file; + file, err = open(filename); + if file == nil { + t.Fatalf("net.open(%s) = nil", filename); + } + + lineno := 1; + byteno := 0; + for { + bline, berr := br.ReadLineString('\n', false); + 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/port.go b/src/pkg/net/port.go new file mode 100644 index 000000000..21e3b48aa --- /dev/null +++ b/src/pkg/net/port.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. + +// Read system port mappings from /etc/services + +package net + +import ( + "io"; + "net"; + "once"; + "os"; + "strconv"; +) + +// The error returned by LookupPort when a network service +// is not listed in the database. +var ErrNoService = &Error{"unknown network service"}; + +var services map[string] map[string] int +var servicesError os.Error + +func readServices() { + services = make(map[string] map[string] int); + var file *file; + file, servicesError = open("/etc/services"); + 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:len(portnet)]; // "tcp" + m, ok1 := services[netw]; + if !ok1 { + m = make(map[string] int); + services[netw] = m; + } + for i := 0; i < len(f); i++ { + if i != 1 { // f[1] was port/net + m[f[i]] = port; + } + } + } + file.close(); +} + +// LookupPort looks up the port for the given network and service. +func LookupPort(network, service string) (port int, err os.Error) { + once.Do(readServices); + + switch network { + case "tcp4", "tcp6": + network = "tcp"; + case "udp4", "udp6": + network = "udp"; + } + + m, ok := services[network]; + if !ok { + return 0, ErrNoService; + } + port, ok = m[service]; + if !ok { + return 0, ErrNoService; + } + return port, nil; +} diff --git a/src/pkg/net/port_test.go b/src/pkg/net/port_test.go new file mode 100644 index 000000000..c535d4caa --- /dev/null +++ b/src/pkg/net/port_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 net + +import ( + "net"; + "testing"; +) + +type portTest struct { + netw string; + name string; + port int; + ok bool; +} + +var porttests = []portTest { + portTest{ "tcp", "echo", 7, true }, + portTest{ "tcp", "discard", 9, true }, + portTest{ "tcp", "systat", 11, true }, + portTest{ "tcp", "daytime", 13, true }, + portTest{ "tcp", "chargen", 19, true }, + portTest{ "tcp", "ftp-data", 20, true }, + portTest{ "tcp", "ftp", 21, true }, + portTest{ "tcp", "ssh", 22, true }, + portTest{ "tcp", "telnet", 23, true }, + portTest{ "tcp", "smtp", 25, true }, + portTest{ "tcp", "time", 37, true }, + portTest{ "tcp", "domain", 53, true }, + portTest{ "tcp", "gopher", 70, true }, + portTest{ "tcp", "finger", 79, true }, + portTest{ "tcp", "http", 80, true }, + + portTest{ "udp", "echo", 7, true }, + portTest{ "udp", "tacacs", 49, true }, + portTest{ "udp", "tftp", 69, true }, + portTest{ "udp", "bootpc", 68, true }, + portTest{ "udp", "bootps", 67, true }, + portTest{ "udp", "domain", 53, true }, + portTest{ "udp", "ntp", 123, true }, + portTest{ "udp", "snmp", 161, true }, + portTest{ "udp", "syslog", 514, true }, + portTest{ "udp", "nfs", 2049, true }, + + portTest{ "--badnet--", "zzz", 0, false }, + portTest{ "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/server_test.go b/src/pkg/net/server_test.go new file mode 100644 index 000000000..586b55365 --- /dev/null +++ b/src/pkg/net/server_test.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 net + +import ( + "io"; + "net"; + "os"; + "syscall"; + "testing"; +) + +func runEcho(fd io.ReadWriter, done chan<- int) { + var buf [1024]byte; + + for { + n, err := fd.Read(&buf); + if err != nil || n == 0 { + break; + } + fd.Write(buf[0:n]) + } + done <- 1 +} + +func runServe(t *testing.T, network, addr string, listening, done chan<- int) { + l, err := net.Listen(network, addr); + if err != nil { + t.Fatalf("net.Listen(%q, %q) = _, %v", network, addr, err); + } + listening <- 1; + + for { + fd, addr, 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) { + fd, err := net.Dial(network, "", addr); + if err != nil { + t.Fatalf("net.Dial(%q, %q, %q) = _, %v", network, "", addr, err); + } + + b := io.StringBytes("hello, world\n"); + var b1 [100]byte; + + n, errno := fd.Write(b); + if n != len(b) { + t.Fatalf("fd.Write(%q) = %d, %v", b, n, errno); + } + + n, errno = fd.Read(&b1); + if n != len(b) { + t.Fatalf("fd.Read() = %d, %v", n, errno); + } + fd.Close(); +} + +func doTest(t *testing.T, network, listenaddr, dialaddr string) { + t.Logf("Test %s %s %s\n", network, listenaddr, dialaddr); + listening := make(chan int); + done := make(chan int); + go runServe(t, network, listenaddr, listening, done); + <-listening; // wait for server to start + connect(t, network, dialaddr); + <-done; // make sure server stopped +} + +func TestTcpServer(t *testing.T) { + doTest(t, "tcp", "0.0.0.0:9997", "127.0.0.1:9997"); + doTest(t, "tcp", "[::]:9997", "[::ffff:127.0.0.1]:9997"); + doTest(t, "tcp", "[::]:9997", "127.0.0.1:9997"); + doTest(t, "tcp", ":9997", "127.0.0.1:9997"); + doTest(t, "tcp", "0.0.0.0:9997", "[::ffff:127.0.0.1]:9997"); +} + +func TestUnixServer(t *testing.T) { + doTest(t, "unix", "/tmp/gotest.net", "/tmp/gotest.net"); + if syscall.OS == "linux" { + // Test abstract unix domain socket, a Linux-ism + doTest(t, "unix", "@gotest/net", "@gotest/net"); + } +} diff --git a/src/pkg/net/timeout_test.go b/src/pkg/net/timeout_test.go new file mode 100644 index 000000000..e08ce88ce --- /dev/null +++ b/src/pkg/net/timeout_test.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 net + +import ( + "net"; + "os"; + "testing"; + "time"; +) + +func testTimeout(t *testing.T, network, addr string) { + fd, err := net.Dial(network, "", addr); + defer fd.Close(); + if err != nil { + t.Errorf("dial %s %s failed: %v", network, addr, err); + } + t0 := time.Nanoseconds(); + fd.SetReadTimeout(1e8); // 100ms + var b [100]byte; + n, err1 := fd.Read(&b); + t1 := time.Nanoseconds(); + if n != 0 || err1 != os.EAGAIN { + t.Errorf("fd.Read on %s %s did not return 0, EAGAIN: %v, %v", network, addr, n, err1); + } + if t1 - t0 < 0.5e8 || t1 - t0 > 1.5e8 { + t.Errorf("fd.Read on %s %s took %f seconds, expected 0.1", network, addr, float64(t1 - t0) / 1e9); + } +} + +func TestTimeoutUDP(t *testing.T) { + testTimeout(t, "udp", "127.0.0.1:53"); +} + +func TestTimeoutTCP(t *testing.T) { + // 74.125.19.99 is www.google.com. + // could use dns, but dns depends on + // timeouts and this is the timeout test. + testTimeout(t, "tcp", "74.125.19.99:80"); +} diff --git a/src/pkg/once/Makefile b/src/pkg/once/Makefile new file mode 100644 index 000000000..6350402c2 --- /dev/null +++ b/src/pkg/once/Makefile @@ -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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D= + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + once.$O\ + + +phases: a1 +_obj$D/once.a: phases + +a1: $(O1) + $(AR) grc _obj$D/once.a once.$O + rm -f $(O1) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/once.a + +$(O1): newpkg +$(O2): a1 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/once.a + +packages: _obj$D/once.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/once.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/once.a diff --git a/src/pkg/once/once.go b/src/pkg/once/once.go new file mode 100644 index 000000000..6047df236 --- /dev/null +++ b/src/pkg/once/once.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. + +// This package provides a single function, Do, to run a function +// exactly once, usually used as part of initialization. +package once + +import "sync" + +type job struct { + done bool; + sync.Mutex; // should probably be sync.Notification or some such +} + +var jobs = make(map[func()]*job) +var joblock sync.Mutex; + +// Do is the the only exported piece of the package. +// For one-time initialization that is not done during init, +// wrap the initialization in a niladic function f() and call +// Do(f) +// If multiple processes call Do(f) simultaneously +// with the same f argument, only one will call f, and the +// others will block until f finishes running. +func Do(f func()) { + joblock.Lock(); + j, present := jobs[f]; + if !present { + // run it + j = new(job); + j.Lock(); + jobs[f] = j; + joblock.Unlock(); + f(); + j.done = true; + j.Unlock(); + } else { + // wait for it + joblock.Unlock(); + if j.done != true { + j.Lock(); + j.Unlock(); + } + } +} diff --git a/src/pkg/once/once_test.go b/src/pkg/once/once_test.go new file mode 100644 index 000000000..9506ff3d7 --- /dev/null +++ b/src/pkg/once/once_test.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 once + +import ( + "once"; + "testing"; +) + +var ncall int; +func call() { + ncall++ +} + +func TestOnce(t *testing.T) { + ncall = 0; + once.Do(call); + if ncall != 1 { + t.Fatalf("once.Do(call) didn't call(): ncall=%d", ncall); + } + once.Do(call); + if ncall != 1 { + t.Fatalf("second once.Do(call) did call(): ncall=%d", ncall); + } + once.Do(call); + if ncall != 1 { + t.Fatalf("third once.Do(call) did call(): ncall=%d", ncall); + } +} diff --git a/src/pkg/os/Makefile b/src/pkg/os/Makefile new file mode 100644 index 000000000..c5f790f15 --- /dev/null +++ b/src/pkg/os/Makefile @@ -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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m dir_${GOOS}_${GOARCH}.go env.go error.go file.go path.go stat_${GOOS}_${GOARCH}.go time.go types.go exec.go proc.go getwd.go >Makefile + +D= + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + error.$O\ + types.$O\ + +O2=\ + proc.$O\ + stat_$(GOOS)_$(GOARCH).$O\ + time.$O\ + +O3=\ + env.$O\ + file.$O\ + +O4=\ + dir_$(GOOS)_$(GOARCH).$O\ + exec.$O\ + getwd.$O\ + path.$O\ + + +phases: a1 a2 a3 a4 +_obj$D/os.a: phases + +a1: $(O1) + $(AR) grc _obj$D/os.a error.$O types.$O + rm -f $(O1) + +a2: $(O2) + $(AR) grc _obj$D/os.a proc.$O stat_$(GOOS)_$(GOARCH).$O time.$O + rm -f $(O2) + +a3: $(O3) + $(AR) grc _obj$D/os.a env.$O file.$O + rm -f $(O3) + +a4: $(O4) + $(AR) grc _obj$D/os.a dir_$(GOOS)_$(GOARCH).$O exec.$O getwd.$O path.$O + rm -f $(O4) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/os.a + +$(O1): newpkg +$(O2): a1 +$(O3): a2 +$(O4): a3 +$(O5): a4 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/os.a + +packages: _obj$D/os.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/os.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/os.a diff --git a/src/pkg/os/dir_darwin_386.go b/src/pkg/os/dir_darwin_386.go new file mode 100644 index 000000000..2803ecee2 --- /dev/null +++ b/src/pkg/os/dir_darwin_386.go @@ -0,0 +1,76 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package os + +import ( + "os"; + "syscall"; + "unsafe"; +) + +const ( + blockSize = 4096 // TODO(r): use statfs +) + +// Negative count means read until EOF. +func readdirnames(file *File, count int) (names []string, err Error) { + // If this file has no dirinfo, create one. + if file.dirinfo == nil { + file.dirinfo = new(dirInfo); + // The buffer must be at least a block long. + // TODO(r): use fstatfs to find fs block size. + file.dirinfo.buf = make([]byte, blockSize); + } + d := file.dirinfo; + size := count; + if size < 0 { + size = 100 + } + names = make([]string, 0, size); // Empty with room to grow. + for count != 0 { + // Refill the buffer if necessary + if d.bufp >= d.nbuf { + var errno int; + d.bufp = 0; + // Final argument is (basep *uintptr) and the syscall doesn't take nil. + d.nbuf, errno = syscall.Getdirentries(file.fd, d.buf, new(uintptr)); + if errno != 0 { + d.nbuf = 0; + return names, ErrnoToError(errno) + } + if d.nbuf == 0 { + break // EOF + } + } + // Drain the buffer + for count != 0 && d.bufp < d.nbuf { + dirent := (*syscall.Dirent)(unsafe.Pointer(&d.buf[d.bufp])); + if dirent.Reclen == 0 { + d.bufp = d.nbuf; + break + } + d.bufp += int(dirent.Reclen); + if dirent.Ino == 0 { // File absent in directory. + continue + } + bytes := (*[len(dirent.Name)]byte)(unsafe.Pointer(&dirent.Name[0])); + var name = string(bytes[0:dirent.Namlen]); + if name == "." || name == ".." { // Useless names + continue + } + count--; + if len(names) == cap(names) { + nnames := make([]string, len(names), 2*len(names)); + for i := 0; i < len(names); i++ { + nnames[i] = names[i] + } + names = nnames; + } + names = names[0:len(names)+1]; + names[len(names)-1] = name; + } + } + return names, nil +} diff --git a/src/pkg/os/dir_darwin_amd64.go b/src/pkg/os/dir_darwin_amd64.go new file mode 100644 index 000000000..2803ecee2 --- /dev/null +++ b/src/pkg/os/dir_darwin_amd64.go @@ -0,0 +1,76 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package os + +import ( + "os"; + "syscall"; + "unsafe"; +) + +const ( + blockSize = 4096 // TODO(r): use statfs +) + +// Negative count means read until EOF. +func readdirnames(file *File, count int) (names []string, err Error) { + // If this file has no dirinfo, create one. + if file.dirinfo == nil { + file.dirinfo = new(dirInfo); + // The buffer must be at least a block long. + // TODO(r): use fstatfs to find fs block size. + file.dirinfo.buf = make([]byte, blockSize); + } + d := file.dirinfo; + size := count; + if size < 0 { + size = 100 + } + names = make([]string, 0, size); // Empty with room to grow. + for count != 0 { + // Refill the buffer if necessary + if d.bufp >= d.nbuf { + var errno int; + d.bufp = 0; + // Final argument is (basep *uintptr) and the syscall doesn't take nil. + d.nbuf, errno = syscall.Getdirentries(file.fd, d.buf, new(uintptr)); + if errno != 0 { + d.nbuf = 0; + return names, ErrnoToError(errno) + } + if d.nbuf == 0 { + break // EOF + } + } + // Drain the buffer + for count != 0 && d.bufp < d.nbuf { + dirent := (*syscall.Dirent)(unsafe.Pointer(&d.buf[d.bufp])); + if dirent.Reclen == 0 { + d.bufp = d.nbuf; + break + } + d.bufp += int(dirent.Reclen); + if dirent.Ino == 0 { // File absent in directory. + continue + } + bytes := (*[len(dirent.Name)]byte)(unsafe.Pointer(&dirent.Name[0])); + var name = string(bytes[0:dirent.Namlen]); + if name == "." || name == ".." { // Useless names + continue + } + count--; + if len(names) == cap(names) { + nnames := make([]string, len(names), 2*len(names)); + for i := 0; i < len(names); i++ { + nnames[i] = names[i] + } + names = nnames; + } + names = names[0:len(names)+1]; + names[len(names)-1] = name; + } + } + return names, nil +} diff --git a/src/pkg/os/dir_linux_386.go b/src/pkg/os/dir_linux_386.go new file mode 100644 index 000000000..c4594a52d --- /dev/null +++ b/src/pkg/os/dir_linux_386.go @@ -0,0 +1,83 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// TODO(rsc): Once the porting dust settles, consider +// whether this file should be dir_linux.go (and similarly +// dir_darwin.go) instead of having one copy per architecture. + +package os + +import ( + "os"; + "syscall"; + "unsafe"; +) + +const ( + blockSize = 4096 // TODO(r): use statfs +) + +func clen(n []byte) int { + for i := 0; i < len(n); i++ { + if n[i] == 0 { + return i + } + } + return len(n) +} + +// Negative count means read until EOF. +func readdirnames(file *File, count int) (names []string, err Error) { + // If this file has no dirinfo, create one. + if file.dirinfo == nil { + file.dirinfo = new(dirInfo); + // The buffer must be at least a block long. + // TODO(r): use fstatfs to find fs block size. + file.dirinfo.buf = make([]byte, blockSize); + } + d := file.dirinfo; + size := count; + if size < 0 { + size = 100 + } + names = make([]string, 0, size); // Empty with room to grow. + for count != 0 { + // Refill the buffer if necessary + if d.bufp >= d.nbuf { + var errno int; + d.nbuf, errno = syscall.Getdents(file.fd, d.buf); + if d.nbuf < 0 { + return names, ErrnoToError(errno) + } + if d.nbuf == 0 { + break // EOF + } + d.bufp = 0; + } + // Drain the buffer + for count != 0 && d.bufp < d.nbuf { + dirent := (*syscall.Dirent)(unsafe.Pointer(&d.buf[d.bufp])); + d.bufp += int(dirent.Reclen); + if dirent.Ino == 0 { // File absent in directory. + continue + } + bytes := (*[len(dirent.Name)]byte)(unsafe.Pointer(&dirent.Name[0])); + var name = string(bytes[0:clen(bytes)]); + if name == "." || name == ".." { // Useless names + continue + } + count--; + if len(names) == cap(names) { + nnames := make([]string, len(names), 2*len(names)); + for i := 0; i < len(names); i++ { + nnames[i] = names[i] + } + names = nnames; + } + names = names[0:len(names)+1]; + names[len(names)-1] = name; + } + } + return names, nil; +} diff --git a/src/pkg/os/dir_linux_amd64.go b/src/pkg/os/dir_linux_amd64.go new file mode 100644 index 000000000..05b3d4c65 --- /dev/null +++ b/src/pkg/os/dir_linux_amd64.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 os + +import ( + "os"; + "syscall"; + "unsafe"; +) + +const ( + blockSize = 4096 // TODO(r): use statfs +) + +func clen(n []byte) int { + for i := 0; i < len(n); i++ { + if n[i] == 0 { + return i + } + } + return len(n) +} + +// Negative count means read until EOF. +func readdirnames(file *File, count int) (names []string, err Error) { + // If this file has no dirinfo, create one. + if file.dirinfo == nil { + file.dirinfo = new(dirInfo); + // The buffer must be at least a block long. + // TODO(r): use fstatfs to find fs block size. + file.dirinfo.buf = make([]byte, blockSize); + } + d := file.dirinfo; + size := count; + if size < 0 { + size = 100 + } + names = make([]string, 0, size); // Empty with room to grow. + for count != 0 { + // Refill the buffer if necessary + if d.bufp >= d.nbuf { + var errno int; + d.nbuf, errno = syscall.Getdents(file.fd, d.buf); + if d.nbuf < 0 { + return names, ErrnoToError(errno) + } + if d.nbuf == 0 { + break // EOF + } + d.bufp = 0; + } + // Drain the buffer + for count != 0 && d.bufp < d.nbuf { + dirent := (*syscall.Dirent)(unsafe.Pointer(&d.buf[d.bufp])); + d.bufp += int(dirent.Reclen); + if dirent.Ino == 0 { // File absent in directory. + continue + } + bytes := (*[len(dirent.Name)]byte)(unsafe.Pointer(&dirent.Name[0])); + var name = string(bytes[0:clen(bytes)]); + if name == "." || name == ".." { // Useless names + continue + } + count--; + if len(names) == cap(names) { + nnames := make([]string, len(names), 2*len(names)); + for i := 0; i < len(names); i++ { + nnames[i] = names[i] + } + names = nnames; + } + names = names[0:len(names)+1]; + names[len(names)-1] = name; + } + } + return names, nil; +} diff --git a/src/pkg/os/env.go b/src/pkg/os/env.go new file mode 100644 index 000000000..748750413 --- /dev/null +++ b/src/pkg/os/env.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. + +// Environment variables. + +package os + +import ( + "once"; + "os"; +) + +// ENOENV is the Error indicating that an environment variable does not exist. +var ENOENV = NewError("no such environment variable"); + +var env map[string] string; + + +func copyenv() { + env = make(map[string] string); + for i, s := range os.Envs { + for j := 0; j < len(s); j++ { + if s[j] == '=' { + env[s[0:j]] = s[j+1:len(s)]; + break; + } + } + } +} + +// Getenv retrieves the value of the environment variable named by the key. +// It returns the value and an error, if any. +func Getenv(key string) (value string, err Error) { + once.Do(copyenv); + + if len(key) == 0 { + return "", EINVAL; + } + v, ok := env[key]; + if !ok { + return "", ENOENV; + } + return v, nil; +} + +// Setenv sets the value of the environment variable named by the key. +// It returns an Error, if any. +func Setenv(key, value string) Error { + once.Do(copyenv); + + if len(key) == 0 { + return EINVAL; + } + env[key] = value; + return nil; +} + +// Clearenv deletes all environment variables. +func Clearenv() { + once.Do(copyenv); // prevent copyenv in Getenv/Setenv + env = make(map[string] string); +} + +// Environ returns an array of strings representing the environment, +// in the form "key=value". +func Environ() []string { + once.Do(copyenv); + a := make([]string, len(env)); + i := 0; + for k, v := range(env) { + // check i < len(a) for safety, + // in case env is changing underfoot. + if i < len(a) { + a[i] = k + "=" + v; + i++; + } + } + return a[0:i]; +} diff --git a/src/pkg/os/error.go b/src/pkg/os/error.go new file mode 100644 index 000000000..718499b21 --- /dev/null +++ b/src/pkg/os/error.go @@ -0,0 +1,83 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package os + +import syscall "syscall" + +// An Error can represent any printable error condition. +type Error interface { + String() string +} + +// A helper type that can be embedded or wrapped to simplify satisfying +// Error. +type ErrorString string +func (e ErrorString) String() string { + return string(e) +} + +// NewError converts s to an ErrorString, which satisfies the Error interface. +func NewError(s string) Error { + return ErrorString(s) +} + +// Errno is the Unix error number. Names such as EINVAL are simple +// wrappers to convert the error number into an Error. +type Errno int64 +func (e Errno) String() string { + return syscall.Errstr(int(e)) +} + +// ErrnoToError converts errno to an Error (underneath, an Errno). +// It returns nil for the "no error" errno. +func ErrnoToError(errno int) Error { + if errno == 0 { + return nil + } + return Errno(errno) +} + +// 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); + ENOTBLK Error = Errno(syscall.ENOTBLK); + 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); + ETXTBSY Error = Errno(syscall.ETXTBSY); + 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); +) + diff --git a/src/pkg/os/exec.go b/src/pkg/os/exec.go new file mode 100644 index 000000000..d283c7267 --- /dev/null +++ b/src/pkg/os/exec.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. + +package os + +import ( + "os"; + "syscall"; +) + +// ForkExec forks the current process and invokes Exec with the file, arguments, +// and environment specified by argv0, argv, and envv. It returns the process +// id of the forked process and an Error, if any. The fd array specifies the +// file descriptors to be set up in the new process: fd[0] will be Unix file +// descriptor 0 (standard input), fd[1] descriptor 1, and so on. A nil entry +// will cause the child to have no open file descriptor with that index. +// If dir is not empty, the child chdirs into the directory before execing the program. +func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []*File) + (pid int, err Error) +{ + // Create array of integer (system) fds. + intfd := make([]int, len(fd)); + for i, f := range(fd) { + if f == nil { + intfd[i] = -1; + } else { + intfd[i] = f.Fd(); + } + } + + p, e := syscall.ForkExec(argv0, argv, envv, dir, intfd); + return int(p), ErrnoToError(e); +} + +// Exec replaces the current process with an execution of the program +// named by argv0, with arguments argv and environment envv. +// If successful, Exec never returns. If it fails, it returns an Error. +// ForkExec is almost always a better way to execute a program. +func Exec(argv0 string, argv []string, envv []string) Error { + if envv == nil { + envv = Environ(); + } + e := syscall.Exec(argv0, argv, envv); + return ErrnoToError(e); +} + +// 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 os.Rusage struct, +// since syscall one might have different field types across +// different OS. + +// Waitmsg stores the information about an exited process as reported by Wait. +type Waitmsg struct { + Pid int; // The process's id. + syscall.WaitStatus; // System-dependent status info. + Rusage *syscall.Rusage; // System-dependent resource usage info. +} + +// Options for Wait. +const ( + WNOHANG = syscall.WNOHANG; // Don't wait if no process has exited. + WSTOPPED = syscall.WSTOPPED; // If set, status of stopped subprocesses is also reported. + WUNTRACED = WSTOPPED; + WRUSAGE = 1<<30; // Record resource usage. +) + +// Wait waits for process pid to exit or stop, and then returns a +// Waitmsg describing its status and an Error, if any. The options +// (WNOHANG etc.) affect the behavior of the Wait call. +func Wait(pid int, options int) (w *Waitmsg, err Error) { + var status syscall.WaitStatus; + var rusage *syscall.Rusage; + if options & WRUSAGE != 0 { + rusage = new(syscall.Rusage); + options ^= WRUSAGE; + } + pid1, e := syscall.Wait4(pid, &status, options, rusage); + if e != 0 { + return nil, ErrnoToError(e); + } + w = new(Waitmsg); + w.Pid = pid; + w.WaitStatus = status; + w.Rusage = rusage; + return w, nil; +} + +// Getpid returns the process id of the caller. +func Getpid() int { + p, r2, e := syscall.Syscall(syscall.SYS_GETPID, 0, 0, 0); + return int(p) +} + +// Getppid returns the process id of the caller's parent. +func Getppid() int { + p, r2, e := syscall.Syscall(syscall.SYS_GETPPID, 0, 0, 0); + return int(p) +} diff --git a/src/pkg/os/file.go b/src/pkg/os/file.go new file mode 100644 index 000000000..1562b1b0e --- /dev/null +++ b/src/pkg/os/file.go @@ -0,0 +1,383 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// The os package provides a platform-independent interface to operating +// system functionality. The design is Unix-like. +package os + +import ( + "os"; + "syscall"; +) + +// 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. +} + +// File represents an open file descriptor. +type File struct { + fd int; + name string; + dirinfo *dirInfo; // nil unless directory being read + nepipe int; // number of consecutive EPIPE in Write +} + +// Fd returns the integer Unix file descriptor referencing the open file. +func (file *File) Fd() int { + return file.fd +} + +// Name returns the name of the file as presented to Open. +func (file *File) Name() string { + return file.name +} + +// NewFile returns a new File with the given file descriptor and name. +func NewFile(file int, name string) *File { + if file < 0 { + return nil + } + return &File{file, name, nil, 0} +} + +// Stdin, Stdout, and Stderr are open Files pointing to the standard input, +// standard output, and standard error file descriptors. +var ( + Stdin = NewFile(0, "/dev/stdin"); + Stdout = NewFile(1, "/dev/stdout"); + Stderr = NewFile(2, "/dev/stderr"); +) + +// Flags to Open wrapping those of the underlying system. Not all flags +// may be implemented on a given system. +const ( + O_RDONLY = syscall.O_RDONLY; // open the file read-only. + O_WRONLY = syscall.O_WRONLY; // open the file write-only. + O_RDWR = syscall.O_RDWR; // open the file read-write. + O_APPEND = syscall.O_APPEND; // open the file append-only. + O_ASYNC = syscall.O_ASYNC; // generate a signal when I/O is available. + O_CREAT = syscall.O_CREAT; // create a new file if none exists. + O_NOCTTY = syscall.O_NOCTTY; // do not make file the controlling tty. + O_NONBLOCK = syscall.O_NONBLOCK; // open in non-blocking mode. + O_NDELAY = O_NONBLOCK; // synonym for O_NONBLOCK + O_SYNC = syscall.O_SYNC; // open for synchronous I/O. + O_TRUNC = syscall.O_TRUNC; // if possible, truncate file when opened. +) + +// Open opens the named file with specified flag (O_RDONLY etc.) and perm, (0666 etc.) +// if applicable. If successful, methods on the returned File can be used for I/O. +// It returns the File and an Error, if any. +func Open(name string, flag int, perm int) (file *File, err Error) { + r, e := syscall.Open(name, flag | syscall.O_CLOEXEC, perm); + if e != 0 { + return nil, ErrnoToError(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), ErrnoToError(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 { + return EINVAL + } + err := ErrnoToError(syscall.Close(file.fd)); + file.fd = -1; // so it can't be closed again + return err; +} + +// 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 a nil Error. +// TODO(r): Add Pread, Pwrite (maybe ReadAt, WriteAt). +func (file *File) Read(b []byte) (ret int, err Error) { + if file == nil { + return 0, EINVAL + } + n, e := syscall.Read(file.fd, b); + if n < 0 { + n = 0; + } + return n, ErrnoToError(e); +} + +// Write writes len(b) bytes to the File. +// It returns the number of bytes written and an Error, if any. +// If the byte count differs from len(b), it usually implies an error occurred. +func (file *File) Write(b []byte) (ret int, err Error) { + if file == nil { + return 0, EINVAL + } + n, e := syscall.Write(file.fd, b); + if n < 0 { + n = 0 + } + if e == syscall.EPIPE { + file.nepipe++; + if file.nepipe >= 10 { + os.Exit(syscall.EPIPE); + } + } else { + file.nepipe = 0; + } + return n, ErrnoToError(e) +} + +// Seek sets the offset for the next Read or Write on file to offset, interpreted +// according to whence: 0 means relative to the origin of the file, 1 means +// relative to the current offset, and 2 means relative to the end. +// It returns the new offset and an Error, if any. +func (file *File) Seek(offset int64, whence int) (ret int64, err Error) { + r, e := syscall.Seek(file.fd, offset, whence); + if e != 0 { + return -1, ErrnoToError(e) + } + if file.dirinfo != nil && r != 0 { + return -1, ErrnoToError(syscall.EISDIR) + } + return r, nil +} + +// WriteString is like Write, but writes the contents of string s rather than +// an array of bytes. +func (file *File) WriteString(s string) (ret int, err Error) { + if file == nil { + return 0, EINVAL + } + b := syscall.StringByteSlice(s); + b = b[0:len(b)-1]; + r, e := syscall.Write(file.fd, b); + if r < 0 { + r = 0 + } + return int(r), ErrnoToError(e) +} + +// Pipe returns a connected pair of Files; reads from r return bytes written to w. +// It returns the files and an Error, if any. +func Pipe() (r *File, w *File, err Error) { + var p [2]int; + + // See ../syscall/exec.go for description of lock. + syscall.ForkLock.RLock(); + e := syscall.Pipe(&p); + if e != 0 { + syscall.ForkLock.RUnlock(); + return nil, nil, ErrnoToError(e) + } + syscall.CloseOnExec(p[0]); + syscall.CloseOnExec(p[1]); + syscall.ForkLock.RUnlock(); + + return NewFile(p[0], "|0"), NewFile(p[1], "|1"), nil +} + +// Mkdir creates a new directory with the specified name and permission bits. +// It returns an error, if any. +func Mkdir(name string, perm int) Error { + return ErrnoToError(syscall.Mkdir(name, perm)); +} + +// Stat returns a Dir structure describing the named file and an error, if any. +// If name names a valid symbolic link, the returned Dir describes +// the file pointed at by the link and has dir.FollowedSymlink set to true. +// If name names an invalid symbolic link, the returned Dir describes +// the link itself and has dir.FollowedSymlink set to false. +func Stat(name string) (dir *Dir, err Error) { + var lstat, stat syscall.Stat_t; + e := syscall.Lstat(name, &lstat); + if e != 0 { + return nil, ErrnoToError(e); + } + statp := &lstat; + if lstat.Mode & syscall.S_IFMT == syscall.S_IFLNK { + e := syscall.Stat(name, &stat); + if e == 0 { + statp = &stat; + } + } + return dirFromStat(name, new(Dir), &lstat, statp), nil +} + +// Stat returns the Dir structure describing file. +// It returns the Dir and an error, if any. +func (file *File) Stat() (dir *Dir, err Error) { + var stat syscall.Stat_t; + e := syscall.Fstat(file.fd, &stat); + if e != 0 { + return nil, ErrnoToError(e) + } + return dirFromStat(file.name, new(Dir), &stat, &stat), nil +} + +// Lstat returns the Dir structure describing the named file and an error, if any. +// If the file is a symbolic link, the returned Dir describes the +// symbolic link. Lstat makes no attempt to follow the link. +func Lstat(name string) (dir *Dir, err Error) { + var stat syscall.Stat_t; + e := syscall.Lstat(name, &stat); + if e != 0 { + return nil, ErrnoToError(e) + } + return dirFromStat(name, new(Dir), &stat, &stat), nil +} + +// Readdirnames has a non-portable implemenation so its code is separated into an +// operating-system-dependent file. +func readdirnames(file *File, count int) (names []string, err Error) + +// Readdirnames reads the contents of the directory associated with file and +// returns an array of up to count names, in directory order. Subsequent +// calls on the same file will yield further names. +// A negative count means to read until EOF. +// Readdirnames returns the array and an Error, if any. +func (file *File) Readdirnames(count int) (names []string, err Error) { + return readdirnames(file, count); +} + +// Readdir reads the contents of the directory associated with file and +// returns an array of up to count Dir structures, as would be returned +// by Stat, in directory order. Subsequent calls on the same file will yield further Dirs. +// A negative count means to read until EOF. +// Readdir returns the array and an Error, if any. +func (file *File) Readdir(count int) (dirs []Dir, err Error) { + dirname := file.name; + if dirname == "" { + dirname = "."; + } + dirname += "/"; + names, err1 := file.Readdirnames(count); + if err1 != nil { + return nil, err1 + } + dirs = make([]Dir, len(names)); + for i, filename := range names { + dirp, err := Stat(dirname + filename); + if dirp == nil || err != nil { + dirs[i].Name = filename // rest is already zeroed out + } else { + dirs[i] = *dirp + } + } + return +} + +// Chdir changes the current working directory to the named directory. +func Chdir(dir string) Error { + return ErrnoToError(syscall.Chdir(dir)); +} + +// Chdir changes the current working directory to the file, +// which must be a directory. +func (f *File) Chdir() Error { + return ErrnoToError(syscall.Fchdir(f.fd)); +} + +// Remove removes the named file or directory. +func Remove(name string) Error { + // System call interface forces us to know + // whether name is a file or directory. + // Try both: it is cheaper on average than + // doing a Stat plus the right one. + e := syscall.Unlink(name); + if e == 0 { + return nil; + } + e1 := syscall.Rmdir(name); + if e1 == 0 { + return nil; + } + + // Both failed: figure out which error to return. + // OS X and Linux differ on whether unlink(dir) + // returns EISDIR, so can't use that. However, + // both agree that rmdir(file) returns ENOTDIR, + // so we can use that to decide which error is real. + // Rmdir might also return ENOTDIR if given a bad + // file path, like /etc/passwd/foo, but in that case, + // both errors will be ENOTDIR, so it's okay to + // use the error from unlink. + if e1 != syscall.ENOTDIR { + e = e1; + } + return ErrnoToError(e); +} + +// Link creates a hard link. +func Link(oldname, newname string) Error { + return ErrnoToError(syscall.Link(oldname, newname)); +} + +// Symlink creates a symbolic link. +func Symlink(oldname, newname string) Error { + return ErrnoToError(syscall.Symlink(oldname, newname)); +} + +// Readlink reads the contents of a symbolic link: the destination of +// the link. It returns the contents and an Error, if any. +func Readlink(name string) (string, Error) { + for len := 128; ; len *= 2 { + b := make([]byte, len); + n, e := syscall.Readlink(name, b); + if e != 0 { + return "", ErrnoToError(e); + } + if n < len { + return string(b[0:n]), nil; + } + } + // Silence 6g. + return "", nil; +} + +// Chmod changes the mode of the named file to mode. +// If the file is a symbolic link, it changes the uid and gid of the link's target. +func Chmod(name string, mode int) Error { + return ErrnoToError(syscall.Chmod(name, mode)); +} + +// Chmod changes the mode of the file to mode. +func (f *File) Chmod(mode int) Error { + return ErrnoToError(syscall.Fchmod(f.fd, mode)); +} + +// 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 { + return ErrnoToError(syscall.Chown(name, uid, gid)); +} + +// 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 { + return ErrnoToError(syscall.Lchown(name, uid, gid)); +} + +// Chown changes the numeric uid and gid of the named file. +func (f *File) Chown(uid, gid int) Error { + return ErrnoToError(syscall.Fchown(f.fd, uid, gid)); +} + +// 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 { + return ErrnoToError(syscall.Truncate(name, size)); +} + +// Truncate changes the size of the file. +// It does not change the I/O offset. +func (f *File) Truncate(size int64) Error { + return ErrnoToError(syscall.Ftruncate(f.fd, size)); +} + diff --git a/src/pkg/os/getwd.go b/src/pkg/os/getwd.go new file mode 100644 index 000000000..2d7b754b5 --- /dev/null +++ b/src/pkg/os/getwd.go @@ -0,0 +1,94 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package os + +import ( + "os"; + "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, ErrnoToError(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. + elem := make([]string, 0, 16); + pwd = ""; + for parent := "..";; parent = "../" + parent { + if len(parent) >= 1024 { // Sanity check + return "", ENAMETOOLONG; + } + fd, err := Open(parent, O_RDONLY, 0); + if err != nil { + return "", err; + } + + for { + names, err := fd.Readdirnames(100); + if err != nil { + fd.Close(); + return "", err; + } + for i, name := range names { + d, err := 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/os_test.go b/src/pkg/os/os_test.go new file mode 100644 index 000000000..9f3e833f3 --- /dev/null +++ b/src/pkg/os/os_test.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 os + +import ( + "fmt"; + "io"; + "os"; + "testing"; +) + +var dot = []string{ + "dir_darwin_amd64.go", + "dir_linux_amd64.go", + "env.go", + "error.go", + "file.go", + "os_test.go", + "time.go", + "types.go", + "stat_darwin_amd64.go", + "stat_linux_amd64.go" +} + +var etc = []string{ + "group", + "hosts", + "passwd", +} + +func size(name string, t *testing.T) uint64 { + file, err := Open(name, O_RDONLY, 0); + defer file.Close(); + if err != nil { + t.Fatal("open failed:", err); + } + var buf [100]byte; + len := 0; + for { + n, e := file.Read(&buf); + if n < 0 || e != nil { + t.Fatal("read failed:", err); + } + if n == 0 { + break + } + len += n; + } + return uint64(len) +} + +func TestStat(t *testing.T) { + dir, err := Stat("/etc/passwd"); + if err != nil { + t.Fatal("stat failed:", err); + } + if dir.Name != "passwd" { + t.Error("name should be passwd; is", dir.Name); + } + filesize := size("/etc/passwd", t); + if dir.Size != filesize { + t.Error("size should be ", filesize, "; is", dir.Size); + } +} + +func TestFstat(t *testing.T) { + file, err1 := Open("/etc/passwd", O_RDONLY, 0); + defer file.Close(); + if err1 != nil { + t.Fatal("open failed:", err1); + } + dir, err2 := file.Stat(); + if err2 != nil { + t.Fatal("fstat failed:", err2); + } + if dir.Name != "passwd" { + t.Error("name should be passwd; is", dir.Name); + } + filesize := size("/etc/passwd", t); + if dir.Size != filesize { + t.Error("size should be ", filesize, "; is", dir.Size); + } +} + +func TestLstat(t *testing.T) { + dir, err := Lstat("/etc/passwd"); + if err != nil { + t.Fatal("lstat failed:", err); + } + if dir.Name != "passwd" { + t.Error("name should be passwd; is", dir.Name); + } + filesize := size("/etc/passwd", t); + if dir.Size != filesize { + t.Error("size should be ", filesize, "; is", dir.Size); + } +} + +func testReaddirnames(dir string, contents []string, t *testing.T) { + file, err := Open(dir, O_RDONLY, 0); + defer file.Close(); + if err != nil { + t.Fatalf("open %q failed: %v", dir, err); + } + s, err2 := file.Readdirnames(-1); + if err2 != nil { + t.Fatalf("readdirnames %q failed: %v", err2); + } + for i, m := range contents { + found := false; + for j, n := range s { + if n == "." || n == ".." { + t.Errorf("got %s in directory", n); + } + if m == n { + if found { + t.Error("present twice:", m); + } + found = true + } + } + if !found { + t.Error("could not find", m); + } + } +} + +func testReaddir(dir string, contents []string, t *testing.T) { + file, err := Open(dir, O_RDONLY, 0); + defer file.Close(); + if err != nil { + t.Fatalf("open %q failed: %v", dir, err); + } + s, err2 := file.Readdir(-1); + if err2 != nil { + t.Fatalf("readdir %q failed: %v", dir, err2); + } + for i, m := range contents { + found := false; + for j, n := range s { + if 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("/etc", etc, t); +} + +func TestReaddir(t *testing.T) { + testReaddir(".", dot, t); + testReaddir("/etc", etc, t); +} + +// Read the directory one entry at a time. +func smallReaddirnames(file *File, length int, t *testing.T) []string { + names := make([]string, length); + count := 0; + for { + d, err := file.Readdirnames(1); + if err != nil { + t.Fatalf("readdir %q failed: %v", file.Name(), err); + } + if len(d) == 0 { + break + } + names[count] = d[0]; + count++; + } + return names[0:count] +} + +// Check that reading a directory one entry at a time gives the same result +// as reading it all at once. +func TestReaddirnamesOneAtATime(t *testing.T) { + dir := "/usr/bin"; // big directory that doesn't change often. + file, err := Open(dir, O_RDONLY, 0); + defer file.Close(); + if err != nil { + t.Fatalf("open %q failed: %v", dir, err); + } + all, err1 := file.Readdirnames(-1); + if err1 != nil { + t.Fatalf("readdirnames %q failed: %v", dir, err1); + } + file1, err2 := Open(dir, O_RDONLY, 0); + if err2 != nil { + t.Fatalf("open %q failed: %v", dir, err2); + } + small := smallReaddirnames(file1, len(all)+100, t); // +100 in case we screw up + for i, n := range all { + if small[i] != n { + t.Errorf("small read %q %q mismatch: %v", small[i], n); + } + } +} + +func TestHardLink(t *testing.T) { + from, to := "hardlinktestfrom", "hardlinktestto"; + Remove(from); // Just in case. + file, err := Open(to, O_CREAT | O_WRONLY, 0666); + if err != nil { + t.Fatalf("open %q failed: %v", to, err); + } + defer Remove(to); + if err = file.Close(); err != nil { + t.Errorf("close %q failed: %v", to, err); + } + err = Link(to, from); + if err != nil { + t.Fatalf("link %q, %q failed: %v", to, from, err); + } + defer Remove(from); + tostat, err := Stat(to); + if err != nil { + t.Fatalf("stat %q failed: %v", to, err); + } + fromstat, err := Stat(from); + if err != nil { + t.Fatalf("stat %q failed: %v", from, err); + } + if tostat.Dev != fromstat.Dev || tostat.Ino != fromstat.Ino { + t.Errorf("link %q, %q did not create hard link", to, from); + } +} + +func TestSymLink(t *testing.T) { + from, to := "symlinktestfrom", "symlinktestto"; + Remove(from); // Just in case. + file, err := Open(to, O_CREAT | O_WRONLY, 0666); + if err != nil { + t.Fatalf("open %q failed: %v", to, err); + } + defer Remove(to); + if err = file.Close(); err != nil { + t.Errorf("close %q failed: %v", to, err); + } + err = Symlink(to, from); + if err != nil { + t.Fatalf("symlink %q, %q failed: %v", to, from, err); + } + defer Remove(from); + tostat, err := Stat(to); + if err != nil { + t.Fatalf("stat %q failed: %v", to, err); + } + if tostat.FollowedSymlink { + t.Fatalf("stat %q claims to have followed a symlink", to); + } + fromstat, err := Stat(from); + if err != nil { + t.Fatalf("stat %q failed: %v", from, err); + } + if tostat.Dev != fromstat.Dev || tostat.Ino != fromstat.Ino { + t.Errorf("symlink %q, %q did not create symlink", to, from); + } + fromstat, err = Lstat(from); + if err != nil { + t.Fatalf("lstat %q failed: %v", from, err); + } + if !fromstat.IsSymlink() { + t.Fatalf("symlink %q, %q did not create symlink", to, from); + } + fromstat, err = Stat(from); + if err != nil { + t.Fatalf("stat %q failed: %v", from, err); + } + if !fromstat.FollowedSymlink { + t.Fatalf("stat %q did not follow symlink"); + } + s, err := Readlink(from); + if err != nil { + t.Fatalf("readlink %q failed: %v", from, err); + } + if s != to { + t.Fatalf("after symlink %q != %q", s, to); + } + file, err = Open(from, O_RDONLY, 0); + if err != nil { + t.Fatalf("open %q failed: %v", from, err); + } + file.Close(); +} + +func TestLongSymlink(t *testing.T) { + s := "0123456789abcdef"; + s = s + s + s + s + s + s + s + s + s + s + s + s + s + s + s + s + s; + from := "longsymlinktestfrom"; + 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 TestForkExec(t *testing.T) { + r, w, err := Pipe(); + if err != nil { + t.Fatalf("Pipe: %v", err); + } + pid, err := ForkExec("/bin/pwd", []string{"pwd"}, nil, "/", []*File{nil, w, Stderr}); + if err != nil { + t.Fatalf("ForkExec: %v", err); + } + w.Close(); + + var b io.ByteBuffer; + io.Copy(r, &b); + output := string(b.Data()); + expect := "/\n"; + if output != expect { + t.Errorf("exec /bin/pwd returned %q wanted %q", output, expect); + } + Wait(pid, 0); +} + +func checkMode(t *testing.T, path string, mode uint32) { + dir, err := Stat(path); + if err != nil { + t.Fatalf("Stat %q (looking for mode %#o): %s", path, mode, err); + } + if dir.Mode & 0777 != mode { + t.Errorf("Stat %q: mode %#o want %#o", path, dir.Mode, 0777); + } +} + +func TestChmod(t *testing.T) { + MkdirAll("_obj", 0777); + const Path = "_obj/_TestChmod_"; + fd, err := Open(Path, O_WRONLY | O_CREAT, 0666); + if err != nil { + t.Fatalf("create %s: %s", Path, err); + } + + if err = Chmod(Path, 0456); err != nil { + t.Fatalf("chmod %s 0456: %s", Path, err); + } + checkMode(t, Path, 0456); + + if err = fd.Chmod(0123); err != nil { + t.Fatalf("fchmod %s 0123: %s", Path, err); + } + checkMode(t, Path, 0123); + + fd.Close(); + Remove(Path); +} + +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 %#o/%#o): %s", path, uid, gid, err); + } + if dir.Uid != uint32(uid) { + t.Errorf("Stat %q: uid %#o want %#o", path, dir.Uid, uid); + } + if dir.Gid != uint32(gid) { + t.Errorf("Stat %q: gid %#o want %#o", path, dir.Gid, uid); + } +} + +func TestChown(t *testing.T) { + // Use /tmp, not _obj, to make sure we're on a local file system, + // so that the group ids returned by Getgroups will be allowed + // on the file. If _obj is on NFS, the Getgroups groups are + // basically useless. + + const Path = "/tmp/_TestChown_"; + fd, err := Open(Path, O_WRONLY | O_CREAT, 0666); + if err != nil { + t.Fatalf("create %s: %s", Path, err); + } + dir, err := fd.Stat(); + if err != nil { + t.Fatalf("fstat %s: %s", Path, err); + } + defer fd.Close(); + defer Remove(Path); + + // Can't change uid unless root, but can try + // changing the group id. First try our current group. + gid := Getgid(); + if err = Chown(Path, -1, gid); err != nil { + t.Fatalf("chown %s -1 %d: %s", Path, gid, err); + } + checkUidGid(t, Path, int(dir.Uid), gid); + + // Then try all the auxiliary groups. + groups, err := Getgroups(); + if err != nil { + t.Fatalf("getgroups: %s", err); + } + for i, g := range groups { + if err = Chown(Path, -1, g); err != nil { + t.Fatalf("chown %s -1 %d: %s", Path, g, err); + } + checkUidGid(t, Path, int(dir.Uid), g); + + // change back to gid to test fd.Chown + if err = fd.Chown(-1, gid); err != nil { + t.Fatalf("fchown %s -1 %d: %s", Path, gid, err); + } + checkUidGid(t, Path, int(dir.Uid), gid); + } +} + +func checkSize(t *testing.T, path string, size uint64) { + dir, err := 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 TestTruncate(t *testing.T) { + MkdirAll("_obj", 0777); + const Path = "_obj/_TestTruncate_"; + fd, err := Open(Path, O_WRONLY | O_CREAT, 0666); + if err != nil { + t.Fatalf("create %s: %s", Path, err); + } + + checkSize(t, Path, 0); + fd.Write(io.StringBytes("hello, world\n")); + checkSize(t, Path, 13); + fd.Truncate(10); + checkSize(t, Path, 10); + fd.Truncate(1024); + checkSize(t, Path, 1024); + fd.Truncate(0); + checkSize(t, Path, 0); + fd.Write(io.StringBytes("surprise!")); + checkSize(t, Path, 13 + 9); // wrote at offset past where hello, world was. + fd.Close(); + Remove(Path); +} + +func TestChdirAndGetwd(t *testing.T) { + fd, err := Open(".", O_RDONLY, 0); + if err != nil { + t.Fatalf("Open .: %s", err); + } + // These are chosen carefully not to be symlinks on a Mac + // (unlike, say, /var, /etc, and /tmp). + dirs := []string{ "/bin", "/", "/usr/local/bin" }; + for mode := 0; mode < 2; mode++ { + for i, d := range dirs { + if mode == 0 { + err = Chdir(d); + } else { + fd1, err := Open(d, O_RDONLY, 0); + if err != nil { + t.Errorf("Open %s: %s", d, err); + continue; + } + err = fd1.Chdir(); + fd1.Close(); + } + pwd, err1 := Getwd(); + err2 := fd.Chdir(); + if err2 != nil { + // We changed the current directory and cannot go back. + // Don't let the tests continue; they'll scribble + // all over some other directory. + fmt.Fprintf(Stderr, "fchdir back to dot failed: %s\n", err2); + Exit(1); + } + if err != nil { + fd.Close(); + t.Fatalf("Chdir %s: %s", d, err); + } + if err1 != nil { + fd.Close(); + t.Fatalf("Getwd in %s: %s", d, err1); + } + if pwd != d { + fd.Close(); + t.Fatalf("Getwd returned %q want %q", pwd, d); + } + } + } + fd.Close(); +} + +func TestTime(t *testing.T) { + // Just want to check that Time() is getting something. + // A common failure mode on Darwin is to get 0, 0, + // because it returns the time in registers instead of + // filling in the structure passed to the system call. + // TODO(rsc): 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, err := Open("_obj/seektest", O_CREAT|O_RDWR|O_TRUNC, 0666); + if err != nil { + t.Fatalf("open _obj/seektest: %s", err); + } + + const data = "hello, world\n"; + io.WriteString(f, data); + + type test struct { + in int64; + whence int; + out int64; + } + var tests = []test { + test{ 0, 1, int64(len(data)) }, + test{ 0, 0, 0 }, + test{ 5, 0, 5 }, + test{ 0, 2, int64(len(data)) }, + test{ 0, 0, 0 }, + test{ -1, 2, int64(len(data)) - 1 }, + test{ 1<<40, 0, 1<<40 }, + test{ 1<<40, 2, 1<<40 + int64(len(data)) } + }; + for i, tt := range tests { + off, err := f.Seek(tt.in, tt.whence); + if off != tt.out || err != nil { + t.Errorf("#%d: Seek(%v, %v) = %v, %v want %v, nil", i, tt.in, tt.whence, off, err, tt.out); + } + } + f.Close(); +} diff --git a/src/pkg/os/path.go b/src/pkg/os/path.go new file mode 100644 index 000000000..0b86b8f8b --- /dev/null +++ b/src/pkg/os/path.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 os + +import "os" + +// PathError reports an error and the file path where it occurred. +type PathError struct { + Path string; + Error Error; +} + +func (p *PathError) String() string { + return p.Path + ": " + p.Error.String(); +} + +// 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 int) Error { + // If path exists, stop with success or error. + dir, err := os.Lstat(path); + if err == nil { + if dir.IsDirectory() { + return nil; + } + return &PathError{path, ENOTDIR}; + } + + // Doesn't already exist; make sure parent does. + i := len(path); + for i > 0 && path[i-1] == '/' { // Skip trailing slashes. + i--; + } + + j := i; + for j > 0 && path[j-1] != '/' { // Scan backward over element. + j--; + } + + if j > 0 { + // Create parent + err = MkdirAll(path[0:j-1], perm); + if err != nil { + return err; + } + } + + // Now parent exists, try to create. + err = Mkdir(path, perm); + if err != nil { + // Handle arguments like "foo/." by + // double-checking that directory doesn't exist. + dir, err1 := os.Lstat(path); + if err1 == nil && dir.IsDirectory() { + return nil; + } + return &PathError{path, err}; + } + return nil; +} + +// RemoveAll removes path and any children it contains. +// It removes everything it can but returns the first error +// it encounters. +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, err1 := os.Lstat(path); + if err1 != nil { + return &PathError{path, err1}; + } + if !dir.IsDirectory() { + // Not a directory; return the error from Remove. + return &PathError{path, err}; + } + + // Directory. + fd, err := Open(path, os.O_RDONLY, 0); + if err != nil { + return &PathError{path, err}; + } + defer fd.Close(); + + // Remove contents & return first error. + err = nil; + for { + names, err1 := fd.Readdirnames(100); + for i, name := range names { + err1 := RemoveAll(path + "/" + name); + if err1 != nil && err == nil { + err = err1; + } + } + // If Readdirnames returned an error, use it. + if err1 != nil && err == nil { + err = &PathError{path, err1}; + } + if len(names) == 0 { + break; + } + } + + // Remove directory. + err1 = Remove(path); + if err1 != nil && err == nil { + err = &PathError{path, err1}; + } + return err; +} diff --git a/src/pkg/os/path_test.go b/src/pkg/os/path_test.go new file mode 100644 index 000000000..bb6148920 --- /dev/null +++ b/src/pkg/os/path_test.go @@ -0,0 +1,152 @@ +// Copyright 2009 The Go Authors. 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 ( + "os"; + "testing"; +) + +func TestMkdirAll(t *testing.T) { + // Create new dir, in _obj so it will get + // cleaned up by make if not by us. + path := "_obj/_TestMkdirAll_/dir/./dir2"; + err := MkdirAll(path, 0777); + if err != nil { + t.Fatalf("MkdirAll %q: %s", path, err); + } + + // 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"; + fd, err := os.Open(fpath, os.O_WRONLY | os.O_CREAT, 0666); + if err != nil { + t.Fatalf("create %q: %s", fpath, err); + } + + // Can't make directory named after file. + err = MkdirAll(fpath, 0777); + if err == nil { + t.Fatalf("MkdirAll %q: no error"); + } + perr, ok := err.(*PathError); + if !ok { + t.Fatalf("MkdirAll %q returned %T, not *PathError", fpath, err); + } + if perr.Path != fpath { + t.Fatalf("MkdirAll %q returned wrong error path: %q not %q", fpath, perr.Path, fpath); + } + + // Can't make subdirectory of file. + ffpath := fpath + "/subdir"; + err = MkdirAll(ffpath, 0777); + if err == nil { + t.Fatalf("MkdirAll %q: no error"); + } + perr, ok = err.(*PathError); + if !ok { + t.Fatalf("MkdirAll %q returned %T, not *PathError", ffpath, err); + } + if perr.Path != fpath { + t.Fatalf("MkdirAll %q returned wrong error path: %q not %q", ffpath, perr.Path, fpath); + } + + RemoveAll("_obj/_TestMkdirAll_"); +} + +func TestRemoveAll(t *testing.T) { + // Work directory. + path := "_obj/_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 := os.Open(fpath, os.O_WRONLY | os.O_CREAT, 0666); + if err != nil { + t.Fatalf("create %q: %s", fpath, err); + } + fd.Close(); + if err = RemoveAll(path); err != nil { + t.Fatalf("RemoveAll %q (first): %s", path, err); + } + if dir, err := os.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 = os.Open(fpath, os.O_WRONLY | os.O_CREAT, 0666); + if err != nil { + t.Fatalf("create %q: %s", fpath, err); + } + fd.Close(); + fd, err = os.Open(dpath+"/file", os.O_WRONLY | os.O_CREAT, 0666); + if err != nil { + t.Fatalf("create %q: %s", fpath, err); + } + fd.Close(); + if err = RemoveAll(path); err != nil { + t.Fatalf("RemoveAll %q (second): %s", path, err); + } + if dir, err := os.Lstat(path); err == nil { + t.Fatalf("Lstat %q succeeded after RemoveAll (second)", path); + } + + // Make directory with file and subdirectory and trigger error. + if err = MkdirAll(dpath, 0777); err != nil { + t.Fatalf("MkdirAll %q: %s", dpath, err); + } + + // TODO(rsc): toss tmp once bug152 is fixed + tmp := []string{fpath, dpath+"/file1", path+"/zzz"}; + for i, s := range tmp { + fd, err = os.Open(s, os.O_WRONLY | os.O_CREAT, 0666); + if err != nil { + t.Fatalf("create %q: %s", s, err); + } + fd.Close(); + } + if err = os.Chmod(dpath, 0); err != nil { + t.Fatalf("Chmod %q 0: %s", dpath, err); + } + if err = RemoveAll(path); err == nil { + dir, err := Lstat(path); + if err == nil { + t.Errorf("Can lstat %q after supposed RemoveAll", path); + } + t.Fatalf("RemoveAll %q succeeded with chmod 0 subdirectory", path, err); + } + perr, ok := err.(*PathError); + if !ok { + t.Fatalf("RemoveAll %q returned %T not *PathError", path, err); + } + if perr.Path != dpath { + t.Fatalf("RemoveAll %q failed at %q not %q", path, perr.Path, dpath); + } + if err = os.Chmod(dpath, 0777); err != nil { + t.Fatalf("Chmod %q 0777: %s", dpath, err); + } + for i, s := range []string{fpath, path+"/zzz"} { + if dir, err := os.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 dir, err := os.Lstat(path); err == nil { + t.Fatalf("Lstat %q succeeded after RemoveAll (final)", path); + } +} diff --git a/src/pkg/os/proc.go b/src/pkg/os/proc.go new file mode 100644 index 000000000..d2fd6493e --- /dev/null +++ b/src/pkg/os/proc.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. + +// Process etc. + +package os + +import ( + "syscall"; + "os"; + "unsafe"; +) + +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, os.Error) { + gids, errno := syscall.Getgroups(); + return gids, ErrnoToError(errno); +} + +// Exit causes the current program to exit with the given status code. +// Conventionally, code zero indicates success, non-zero an error. +func Exit(code int) { + syscall.Exit(code); +} + diff --git a/src/pkg/os/proc_linux.go b/src/pkg/os/proc_linux.go new file mode 100644 index 000000000..a802284f3 --- /dev/null +++ b/src/pkg/os/proc_linux.go @@ -0,0 +1,20 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package os + +import ( + "os"; + "syscall"; +) + +var Args []string; // provided by runtime +var Envs []string; // provided by runtime + +// 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.Syscall(syscall.SYS_EXIT_GROUP, int64(code), 0, 0) +} + diff --git a/src/pkg/os/stat_darwin_386.go b/src/pkg/os/stat_darwin_386.go new file mode 100644 index 000000000..a6d7b78d1 --- /dev/null +++ b/src/pkg/os/stat_darwin_386.go @@ -0,0 +1,41 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// 386, Darwin + +package os + +import syscall "syscall" +import os "os" + +func isSymlink(stat *syscall.Stat_t) bool { + return stat.Mode & syscall.S_IFMT == syscall.S_IFLNK +} + +func dirFromStat(name string, dir *Dir, lstat, stat *syscall.Stat_t) *Dir { + dir.Dev = uint64(stat.Dev); + dir.Ino = stat.Ino; + dir.Nlink = uint64(stat.Nlink); + dir.Mode = uint32(stat.Mode); + dir.Uid = stat.Uid; + dir.Gid = stat.Gid; + dir.Rdev = uint64(stat.Rdev); + dir.Size = uint64(stat.Size); + dir.Blksize = uint64(stat.Blksize); + dir.Blocks = uint64(stat.Blocks); + dir.Atime_ns = uint64(syscall.TimespecToNsec(stat.Atimespec)); + dir.Mtime_ns = uint64(syscall.TimespecToNsec(stat.Mtimespec)); + dir.Ctime_ns = uint64(syscall.TimespecToNsec(stat.Ctimespec)); + for i := len(name) - 1; i >= 0; i-- { + if name[i] == '/' { + name = name[i+1:len(name)]; + break; + } + } + dir.Name = name; + if isSymlink(lstat) && !isSymlink(stat) { + dir.FollowedSymlink = true; + } + return dir; +} diff --git a/src/pkg/os/stat_darwin_amd64.go b/src/pkg/os/stat_darwin_amd64.go new file mode 100644 index 000000000..1771ca160 --- /dev/null +++ b/src/pkg/os/stat_darwin_amd64.go @@ -0,0 +1,41 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// AMD64, Darwin + +package os + +import syscall "syscall" +import os "os" + +func isSymlink(stat *syscall.Stat_t) bool { + return stat.Mode & syscall.S_IFMT == syscall.S_IFLNK +} + +func dirFromStat(name string, dir *Dir, lstat, stat *syscall.Stat_t) *Dir { + dir.Dev = uint64(stat.Dev); + dir.Ino = stat.Ino; + dir.Nlink = uint64(stat.Nlink); + dir.Mode = uint32(stat.Mode); + dir.Uid = stat.Uid; + dir.Gid = stat.Gid; + dir.Rdev = uint64(stat.Rdev); + dir.Size = uint64(stat.Size); + dir.Blksize = uint64(stat.Blksize); + dir.Blocks = uint64(stat.Blocks); + dir.Atime_ns = uint64(syscall.TimespecToNsec(stat.Atimespec)); + dir.Mtime_ns = uint64(syscall.TimespecToNsec(stat.Mtimespec)); + dir.Ctime_ns = uint64(syscall.TimespecToNsec(stat.Ctimespec)); + for i := len(name) - 1; i >= 0; i-- { + if name[i] == '/' { + name = name[i+1:len(name)]; + break; + } + } + dir.Name = name; + if isSymlink(lstat) && !isSymlink(stat) { + dir.FollowedSymlink = true; + } + return dir; +} diff --git a/src/pkg/os/stat_linux_386.go b/src/pkg/os/stat_linux_386.go new file mode 100644 index 000000000..13ee942c9 --- /dev/null +++ b/src/pkg/os/stat_linux_386.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. + +// TODO(rsc): Once the porting dust settles, consider +// whether this file should be stat_linux.go (and similarly +// stat_darwin.go) instead of having one copy per architecture. + +// 386, Linux + +package os + +import ( + "os"; + "syscall"; +) + +func isSymlink(stat *syscall.Stat_t) bool { + return stat.Mode & syscall.S_IFMT == syscall.S_IFLNK +} + +func dirFromStat(name string, dir *Dir, lstat, stat *syscall.Stat_t) *Dir { + dir.Dev = stat.Dev; + dir.Ino = uint64(stat.Ino); + dir.Nlink = uint64(stat.Nlink); + dir.Mode = stat.Mode; + dir.Uid = stat.Uid; + dir.Gid = stat.Gid; + dir.Rdev = stat.Rdev; + dir.Size = uint64(stat.Size); + dir.Blksize = uint64(stat.Blksize); + dir.Blocks = uint64(stat.Blocks); + dir.Atime_ns = uint64(syscall.TimespecToNsec(stat.Atim)); + dir.Mtime_ns = uint64(syscall.TimespecToNsec(stat.Mtim)); + dir.Ctime_ns = uint64(syscall.TimespecToNsec(stat.Ctim)); + for i := len(name) - 1; i >= 0; i-- { + if name[i] == '/' { + name = name[i+1:len(name)]; + break; + } + } + dir.Name = name; + if isSymlink(lstat) && !isSymlink(stat) { + dir.FollowedSymlink = true; + } + return dir; +} diff --git a/src/pkg/os/stat_linux_amd64.go b/src/pkg/os/stat_linux_amd64.go new file mode 100644 index 000000000..9b3018178 --- /dev/null +++ b/src/pkg/os/stat_linux_amd64.go @@ -0,0 +1,41 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// AMD64, Linux + +package os + +import syscall "syscall" +import os "os" + +func isSymlink(stat *syscall.Stat_t) bool { + return stat.Mode & syscall.S_IFMT == syscall.S_IFLNK +} + +func dirFromStat(name string, dir *Dir, lstat, stat *syscall.Stat_t) *Dir { + dir.Dev = stat.Dev; + dir.Ino = stat.Ino; + dir.Nlink = stat.Nlink; + dir.Mode = stat.Mode; + dir.Uid = stat.Uid; + dir.Gid = stat.Gid; + dir.Rdev = stat.Rdev; + dir.Size = uint64(stat.Size); + dir.Blksize = uint64(stat.Blksize); + dir.Blocks = uint64(stat.Blocks); + dir.Atime_ns = uint64(syscall.TimespecToNsec(stat.Atim)); + dir.Mtime_ns = uint64(syscall.TimespecToNsec(stat.Mtim)); + dir.Ctime_ns = uint64(syscall.TimespecToNsec(stat.Ctim)); + for i := len(name) - 1; i >= 0; i-- { + if name[i] == '/' { + name = name[i+1:len(name)]; + break; + } + } + dir.Name = name; + if isSymlink(lstat) && !isSymlink(stat) { + dir.FollowedSymlink = true; + } + return dir; +} diff --git a/src/pkg/os/time.go b/src/pkg/os/time.go new file mode 100644 index 000000000..3eee243cc --- /dev/null +++ b/src/pkg/os/time.go @@ -0,0 +1,24 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package os + +import ( + "os"; + "syscall" +) + + +// Time returns the current time, in whole seconds and +// fractional nanoseconds, plus an Error if any. The current +// time is thus 1e9*sec+nsec, in nanoseconds. The zero of +// time is the Unix epoch. +func Time() (sec int64, nsec int64, err Error) { + var tv syscall.Timeval; + if errno := syscall.Gettimeofday(&tv); errno != 0 { + return 0, 0, ErrnoToError(errno) + } + 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..b5db86660 --- /dev/null +++ b/src/pkg/os/types.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 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 Dir describes a file and is returned by Stat, Fstat, and Lstat +type Dir 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 uint32; // user id of owner. + Gid uint32; // group id of owner. + Rdev uint64; // device type for special file. + Size uint64; // length in bytes. + Blksize uint64; // size of blocks, in bytes. + Blocks uint64; // number of blocks allocated for file. + Atime_ns uint64; // access time; nanoseconds since epoch. + Mtime_ns uint64; // modified time; nanoseconds since epoch. + Ctime_ns uint64; // status change time; nanoseconds since epoch. + Name string; // name of file as presented to Open. + FollowedSymlink bool; // followed a symlink to get this information +} + +// IsFifo reports whether the Dir describes a FIFO file. +func (dir *Dir) IsFifo() bool { + return (dir.Mode & syscall.S_IFMT) == syscall.S_IFIFO +} + +// IsChar reports whether the Dir describes a character special file. +func (dir *Dir) IsChar() bool { + return (dir.Mode & syscall.S_IFMT) == syscall.S_IFCHR +} + +// IsDirectory reports whether the Dir describes a directory. +func (dir *Dir) IsDirectory() bool { + return (dir.Mode & syscall.S_IFMT) == syscall.S_IFDIR +} + +// IsBlock reports whether the Dir describes a block special file. +func (dir *Dir) IsBlock() bool { + return (dir.Mode & syscall.S_IFMT) == syscall.S_IFBLK +} + +// IsRegular reports whether the Dir describes a regular file. +func (dir *Dir) IsRegular() bool { + return (dir.Mode & syscall.S_IFMT) == syscall.S_IFREG +} + +// IsSymlink reports whether the Dir describes a symbolic link. +func (dir *Dir) IsSymlink() bool { + return (dir.Mode & syscall.S_IFMT) == syscall.S_IFLNK +} + +// IsSocket reports whether the Dir describes a socket. +func (dir *Dir) IsSocket() bool { + return (dir.Mode & syscall.S_IFMT) == syscall.S_IFSOCK +} + +// Permission returns the file permission bits. +func (dir *Dir) Permission() int { + return int(dir.Mode & 0777) +} + diff --git a/src/pkg/path/Makefile b/src/pkg/path/Makefile new file mode 100644 index 000000000..d9f9fd562 --- /dev/null +++ b/src/pkg/path/Makefile @@ -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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D= + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + path.$O\ + + +phases: a1 +_obj$D/path.a: phases + +a1: $(O1) + $(AR) grc _obj$D/path.a path.$O + rm -f $(O1) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/path.a + +$(O1): newpkg +$(O2): a1 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/path.a + +packages: _obj$D/path.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/path.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/path.a diff --git a/src/pkg/path/path.go b/src/pkg/path/path.go new file mode 100644 index 000000000..a7e2c26c3 --- /dev/null +++ b/src/pkg/path/path.go @@ -0,0 +1,136 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// The path package implements utility routines for manipulating +// slash-separated filename paths. +package path + +import "io" + +// 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 := io.StringBytes(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 slash, +// separating it into a directory and file name component. +// If there is no slash in path, DirFile returns an empty dir and +// file set to path. +func Split(path string) (dir, file string) { + for i := len(path)-1; i >= 0; i-- { + if path[i] == '/' { + return path[0:i+1], path[i+1:len(path)]; + } + } + return "", path +} + +// Join joins dir and file into a single path, adding a separating +// slash if necessary. If dir is empty, it returns file. +func Join(dir, file string) string { + if dir == "" { + return file; + } + return Clean(dir + "/" + file); +} + +// 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 { + dot := -1; + for i := len(path)-1; i >= 0 && path[i] != '/'; i-- { + if path[i] == '.' { + return path[i:len(path)]; + } + } + return "" +} + diff --git a/src/pkg/path/path_test.go b/src/pkg/path/path_test.go new file mode 100644 index 000000000..1238ac1cd --- /dev/null +++ b/src/pkg/path/path_test.go @@ -0,0 +1,136 @@ +// Copyright 2009 The Go Authors. 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 ( + "path"; + "testing" +) + +type CleanTest struct { + path, clean string +} + +var cleantests = []CleanTest { + // Already clean + CleanTest{"", "."}, + CleanTest{"abc", "abc"}, + CleanTest{"abc/def", "abc/def"}, + CleanTest{"a/b/c", "a/b/c"}, + CleanTest{".", "."}, + CleanTest{"..", ".."}, + CleanTest{"../..", "../.."}, + CleanTest{"../../abc", "../../abc"}, + CleanTest{"/abc", "/abc"}, + CleanTest{"/", "/"}, + + // Remove trailing slash + CleanTest{"abc/", "abc"}, + CleanTest{"abc/def/", "abc/def"}, + CleanTest{"a/b/c/", "a/b/c"}, + CleanTest{"./", "."}, + CleanTest{"../", ".."}, + CleanTest{"../../", "../.."}, + CleanTest{"/abc/", "/abc"}, + + // Remove doubled slash + CleanTest{"abc//def//ghi", "abc/def/ghi"}, + CleanTest{"//abc", "/abc"}, + CleanTest{"///abc", "/abc"}, + CleanTest{"//abc//", "/abc"}, + CleanTest{"abc//", "abc"}, + + // Remove . elements + CleanTest{"abc/./def", "abc/def"}, + CleanTest{"/./abc/def", "/abc/def"}, + CleanTest{"abc/.", "abc"}, + + // Remove .. elements + CleanTest{"abc/def/ghi/../jkl", "abc/def/jkl"}, + CleanTest{"abc/def/../ghi/../jkl", "abc/jkl"}, + CleanTest{"abc/def/..", "abc"}, + CleanTest{"abc/def/../..", "."}, + CleanTest{"/abc/def/../..", "/"}, + CleanTest{"abc/def/../../..", ".."}, + CleanTest{"/abc/def/../../..", "/"}, + CleanTest{"abc/def/../../../ghi/jkl/../../../mno", "../../mno"}, + + // Combinations + CleanTest{"abc/./../def", "def"}, + CleanTest{"abc//./../def", "def"}, + CleanTest{"abc/../../././../def", "../../def"}, +} + +func TestClean(t *testing.T) { + for i, 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 { + SplitTest{"a/b", "a/", "b"}, + SplitTest{"a/b/", "a/b/", ""}, + SplitTest{"a/", "a/", ""}, + SplitTest{"a", "", "a"}, + SplitTest{"/", "/", ""}, +} + +func TestSplit(t *testing.T) { + for i, 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 { + dir, file, path string +} + +var jointests = []JoinTest { + JoinTest{"a", "b", "a/b"}, + JoinTest{"a", "", "a"}, + JoinTest{"", "b", "b"}, + JoinTest{"/", "a", "/a"}, + JoinTest{"/", "", "/"}, + JoinTest{"a/", "b", "a/b"}, + JoinTest{"a/", "", "a"}, +} + +func TestJoin(t *testing.T) { + for i, test := range jointests { + if p := Join(test.dir, test.file); p != test.path { + t.Errorf("Join(%q, %q) = %q, want %q", test.dir, test.file, p, test.path); + } + } +} + +type ExtTest struct { + path, ext string +} + +var exttests = []ExtTest { + ExtTest{"path.go", ".go"}, + ExtTest{"path.pb.go", ".go"}, + ExtTest{"path", ""}, + ExtTest{"a.dir/b", ""}, + ExtTest{"a.dir/b.go", ".go"}, + ExtTest{"a.dir/", ""}, +} + +func TestExt(t *testing.T) { + for i, test := range exttests { + if x := Ext(test.path); x != test.ext { + t.Errorf("Ext(%q) = %q, want %q", test.path, x, test.ext); + } + } +} + diff --git a/src/pkg/rand/Makefile b/src/pkg/rand/Makefile new file mode 100644 index 000000000..63d26ac99 --- /dev/null +++ b/src/pkg/rand/Makefile @@ -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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D= + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + rand.$O\ + + +phases: a1 +_obj$D/rand.a: phases + +a1: $(O1) + $(AR) grc _obj$D/rand.a rand.$O + rm -f $(O1) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/rand.a + +$(O1): newpkg +$(O2): a1 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/rand.a + +packages: _obj$D/rand.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/rand.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/rand.a diff --git a/src/pkg/rand/rand.go b/src/pkg/rand/rand.go new file mode 100644 index 000000000..bc986cbcf --- /dev/null +++ b/src/pkg/rand/rand.go @@ -0,0 +1,318 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Uniformly distributed pseudo-random numbers. +package rand + +/* + * 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 ( + rng_tap int; // index into vector + rng_feed int; // index into vector + rng_vec [_LEN]int64; // current feedback register + + // 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 }; +) + +// 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 Seed(seed int32) { + rng_tap = 0; + rng_feed = _LEN-_TAP; + + seed = seed%_M; + if seed < 0 { + seed += _M; + } + if seed == 0 { + seed = 89482311; + } + + x := 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 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; +} + +// Uint32 returns a pseudo-random 32-bit value as a uint32. +func Uint32() uint32 { + return uint32(Int63() >> 31); +} + +// Int31 returns a non-negative pseudo-random 31-bit integer as an int32. +func Int31() int32 { + return int32(Int63() >> 32); +} + +// Int returns a non-negative pseudo-random int. All bits but the top bit are random. +func Int() int { + u := uint(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 Int63n(n int64) int64 { + if n <= 0 { + return 0 + } + max := int64((1<<63)-1 - (1<<63) % uint64(n)); + v := Int63(); + for v > max { + v = Int63() + } + return v % n +} + +// Int31n returns, as an int32, a non-negative pseudo-random number in [0,n). +func Int31n(n int32) int32 { + return int32(Int63n(int64(n))) +} + +// Intn returns, as an int, a non-negative pseudo-random number in [0,n). +func Intn(n int) int { + return int(Int63n(int64(n))) +} + +// Float64 returns, as a float64, a pseudo-random number in [0.0,1.0). +func Float64() float64 { + x := float64(Int63()) / float64(_MAX); + for x >= 1 { + x = float64(Int63()) / float64(_MAX); + } + return x; +} + +// Float32 returns, as a float32, a pseudo-random number in [0.0,1.0). +func Float32() float32 { + return float32(Float64()) +} + +// Float returns, as a float, a pseudo-random number in [0.0,1.0). +func Float() float +{ + return float(Float64()) +} + +// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers [0,n). +func Perm(n int) []int { + m := make([]int, n); + for i:=0; iMakefile + +D= + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + type.$O\ + typestring.$O\ + +O2=\ + value.$O\ + +O3=\ + deepequal.$O\ + tostring.$O\ + + +phases: a1 a2 a3 +_obj$D/reflect.a: phases + +a1: $(O1) + $(AR) grc _obj$D/reflect.a type.$O typestring.$O + rm -f $(O1) + +a2: $(O2) + $(AR) grc _obj$D/reflect.a value.$O + rm -f $(O2) + +a3: $(O3) + $(AR) grc _obj$D/reflect.a deepequal.$O tostring.$O + rm -f $(O3) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/reflect.a + +$(O1): newpkg +$(O2): a1 +$(O3): a2 +$(O4): a3 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/reflect.a + +packages: _obj$D/reflect.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/reflect.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/reflect.a diff --git a/src/pkg/reflect/all_test.go b/src/pkg/reflect/all_test.go new file mode 100644 index 000000000..903b0f526 --- /dev/null +++ b/src/pkg/reflect/all_test.go @@ -0,0 +1,613 @@ +// Copyright 2009 The Go Authors. 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 ( + "io"; + "os"; + "reflect"; + "testing"; + "unsafe"; +) + +var doprint bool = false + +func is_digit(c uint8) bool { + return '0' <= c && c <= '9' +} + +// streq, but '@' in t matches a string of digits +func match(s, t string) bool { + for i, j := 0, 0; i < len(s) && j < len(t); i, j = i+1, j+1 { + if s[i] == t[j] { + continue + } + if is_digit(s[i]) && t[j] == '@' { + for is_digit(s[i+1]) { + i++ + } + } else { + return false + } + } + return true; +} + +func assert(s, t string) { + if doprint { + println(t) + } + if !match(s, t) { + panicln(s, t) + } +} + +func typedump(s, t string) { + typ := ParseTypeString("", s); + assert(typeToString(typ, true), t); +} + +func valuedump(s, t string) { + typ := ParseTypeString("", s); + v := NewZeroValue(typ); + if v == nil { + panicln("valuedump", s); + } + switch v.Kind() { + case IntKind: + v.(IntValue).Set(132); + case Int8Kind: + v.(Int8Value).Set(8); + case Int16Kind: + v.(Int16Value).Set(16); + case Int32Kind: + v.(Int32Value).Set(32); + case Int64Kind: + v.(Int64Value).Set(64); + case UintKind: + v.(UintValue).Set(132); + case Uint8Kind: + v.(Uint8Value).Set(8); + case Uint16Kind: + v.(Uint16Value).Set(16); + case Uint32Kind: + v.(Uint32Value).Set(32); + case Uint64Kind: + v.(Uint64Value).Set(64); + case FloatKind: + v.(FloatValue).Set(3200.0); + case Float32Kind: + v.(Float32Value).Set(32.1); + case Float64Kind: + v.(Float64Value).Set(64.2); + case StringKind: + v.(StringValue).Set("stringy cheese"); + case BoolKind: + v.(BoolValue).Set(true); + } + assert(valueToString(v), t); +} + +type T struct { a int; b float64; c string; d *int } + +func TestAll(tt *testing.T) { // TODO(r): wrap up better + var s string; + var t Type; + + // Types + typedump("missing", "$missing$"); + typedump("int", "int"); + typedump("int8", "int8"); + typedump("int16", "int16"); + typedump("int32", "int32"); + typedump("int64", "int64"); + typedump("uint", "uint"); + typedump("uint8", "uint8"); + typedump("uint16", "uint16"); + typedump("uint32", "uint32"); + typedump("uint64", "uint64"); + typedump("float", "float"); + typedump("float32", "float32"); + typedump("float64", "float64"); + typedump("int8", "int8"); + typedump("whoknows.whatsthis", "$missing$"); + typedump("**int8", "**int8"); + typedump("**P.integer", "**P.integer"); + typedump("[32]int32", "[32]int32"); + typedump("[]int8", "[]int8"); + typedump("map[string]int32", "map[string]int32"); + typedump("chan<-string", "chan<-string"); + typedump("struct {c chan *int32; d float32}", "struct{c chan*int32; d float32}"); + typedump("func(a int8, b int32)", "func(a int8, b int32)"); + typedump("struct {c func(? chan *P.integer, ? *int8)}", "struct{c func(chan*P.integer, *int8)}"); + typedump("struct {a int8; b int32}", "struct{a int8; b int32}"); + typedump("struct {a int8; b int8; b int32}", "struct{a int8; b int8; b int32}"); + typedump("struct {a int8; b int8; c int8; b int32}", "struct{a int8; b int8; c int8; b int32}"); + typedump("struct {a int8; b int8; c int8; d int8; b int32}", "struct{a int8; b int8; c int8; d int8; b int32}"); + typedump("struct {a int8; b int8; c int8; d int8; e int8; b int32}", "struct{a int8; b int8; c int8; d int8; e int8; b int32}"); + typedump("struct {a int8 \"hi there\"; }", "struct{a int8 \"hi there\"}"); + typedump("struct {a int8 \"hi \\x00there\\t\\n\\\"\\\\\"; }", "struct{a int8 \"hi \\x00there\\t\\n\\\"\\\\\"}"); + typedump("struct {f func(args ...)}", "struct{f func(args ...)}"); + typedump("interface { a(? func(? func(? int) int) func(? func(? int)) int); b() }", "interface{a (func(func(int)(int))(func(func(int))(int))); b ()}"); + + // Values + valuedump("int8", "8"); + valuedump("int16", "16"); + valuedump("int32", "32"); + valuedump("int64", "64"); + valuedump("uint8", "8"); + valuedump("uint16", "16"); + valuedump("uint32", "32"); + valuedump("uint64", "64"); + valuedump("float32", "32.1"); + valuedump("float64", "64.2"); + valuedump("string", "stringy cheese"); + valuedump("bool", "true"); + valuedump("*int8", "*int8(0)"); + valuedump("**int8", "**int8(0)"); + valuedump("[5]int32", "[5]int32{0, 0, 0, 0, 0}"); + valuedump("**P.integer", "**P.integer(0)"); + valuedump("map[string]int32", "map[string]int32{}"); + valuedump("chan<-string", "chan<-string"); + valuedump("struct {c chan *int32; d float32}", "struct{c chan*int32; d float32}{chan*int32, 0}"); + valuedump("func(a int8, b int32)", "func(a int8, b int32)(0)"); + valuedump("struct {c func(? chan *P.integer, ? *int8)}", "struct{c func(chan*P.integer, *int8)}{func(chan*P.integer, *int8)(0)}"); + valuedump("struct {a int8; b int32}", "struct{a int8; b int32}{0, 0}"); + valuedump("struct {a int8; b int8; b int32}", "struct{a int8; b int8; b int32}{0, 0, 0}"); + + { var tmp = 123; + value := NewValue(tmp); + assert(valueToString(value), "123"); + } + { var tmp = 123.4; + value := NewValue(tmp); + assert(valueToString(value), "123.4"); + } + { + var tmp = byte(123); + value := NewValue(tmp); + assert(valueToString(value), "123"); + assert(typeToString(value.Type(), false), "uint8"); + } + { var tmp = "abc"; + value := NewValue(tmp); + assert(valueToString(value), "abc"); + } + { + var i int = 7; + var tmp = &T{123, 456.75, "hello", &i}; + value := NewValue(tmp); + assert(valueToString(value.(PtrValue).Sub()), "reflect.T{123, 456.75, hello, *int(@)}"); + } + { + type C chan *T; // TODO: should not be necessary + var tmp = new(C); + value := NewValue(tmp); + assert(valueToString(value), "*reflect.C·all_test(@)"); + } +// { +// type A [10]int; +// var tmp A = A{1,2,3,4,5,6,7,8,9,10}; +// value := NewValue(&tmp); +// assert(valueToString(value.(PtrValue).Sub()), "reflect.A·all_test{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}"); +// value.(PtrValue).Sub().(ArrayValue).Elem(4).(IntValue).Set(123); +// assert(valueToString(value.(PtrValue).Sub()), "reflect.A·all_test{1, 2, 3, 4, 123, 6, 7, 8, 9, 10}"); +// } + { + type AA []int; + var tmp = AA{1,2,3,4,5,6,7,8,9,10}; + value := NewValue(&tmp); // TODO: NewValue(tmp) too + assert(valueToString(value.(PtrValue).Sub()), "reflect.AA·all_test{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}"); + value.(PtrValue).Sub().(ArrayValue).Elem(4).(IntValue).Set(123); + assert(valueToString(value.(PtrValue).Sub()), "reflect.AA·all_test{1, 2, 3, 4, 123, 6, 7, 8, 9, 10}"); + } + + { + var ip *int32; + var i int32 = 1234; + vip := NewValue(&ip); + vi := NewValue(i); + vip.(PtrValue).Sub().(PtrValue).SetSub(vi); + if *ip != 1234 { + panicln("SetSub failure", *ip); + } + } + + var pt PtrType; + var st StructType; + var mt MapType; + var at ArrayType; + var ct ChanType; + var name string; + var typ Type; + var tag string; + var offset int; + + // Type strings + t = ParseTypeString("", "int8"); + assert(t.String(), "int8"); + + t = ParseTypeString("", "*int8"); + assert(t.String(), "*int8"); + pt = t.(PtrType); + assert(pt.Sub().String(), "int8"); + + t = ParseTypeString("", "*struct {c chan *int32; d float32}"); + assert(t.String(), "*struct {c chan *int32; d float32}"); + pt = t.(PtrType); + assert(pt.Sub().String(), "struct {c chan *int32; d float32}"); + st = pt.Sub().(StructType); + name, typ, tag, offset = st.Field(0); + assert(typ.String(), "chan *int32"); + name, typ, tag, offset = st.Field(1); + assert(typ.String(), "float32"); + + t = ParseTypeString("", "interface {a() *int}"); + assert(t.String(), "interface {a() *int}"); + + t = ParseTypeString("", "func(a int8, b int32)"); + assert(t.String(), "func(a int8, b int32)"); + + t = ParseTypeString("", "func(a int8, b int32) float"); + assert(t.String(), "func(a int8, b int32) float"); + + t = ParseTypeString("", "func(a int8, b int32) (a float, b float)"); + assert(t.String(), "func(a int8, b int32) (a float, b float)"); + + t = ParseTypeString("", "[32]int32"); + assert(t.String(), "[32]int32"); + at = t.(ArrayType); + assert(at.Elem().String(), "int32"); + + t = ParseTypeString("", "map[string]*int32"); + assert(t.String(), "map[string]*int32"); + mt = t.(MapType); + assert(mt.Key().String(), "string"); + assert(mt.Elem().String(), "*int32"); + + t = ParseTypeString("", "chan<-string"); + assert(t.String(), "chan<-string"); + ct = t.(ChanType); + assert(ct.Elem().String(), "string"); + + // make sure tag strings are not part of element type + t = ParseTypeString("", "struct{d []uint32 \"TAG\"}"); + st = t.(StructType); + name, typ, tag, offset = st.Field(0); + assert(typ.String(), "[]uint32"); + + t = ParseTypeString("", "[]int32"); + v := NewSliceValue(t.(ArrayType), 5, 10); + t1 := ParseTypeString("", "*[]int32"); + v1 := NewZeroValue(t1); + if v1 == nil { panic("V1 is nil"); } + v1.(PtrValue).SetSub(v); + a := v1.Interface().(*[]int32); + println(&a, len(a), cap(a)); + for i := 0; i < len(a); i++ { + v.Elem(i).(Int32Value).Set(int32(i)); + } + for i := 0; i < len(a); i++ { + println(a[i]); + } +} + +func TestInterfaceGet(t *testing.T) { + var inter struct { e interface{ } }; + inter.e = 123.456; + v1 := NewValue(&inter); + v2 := v1.(PtrValue).Sub().(StructValue).Field(0); + assert(v2.Type().String(), "interface { }"); + i2 := v2.(InterfaceValue).Get(); + v3 := NewValue(i2); + assert(v3.Type().String(), "float"); +} + +func TestInterfaceValue(t *testing.T) { + var inter struct { e interface{ } }; + inter.e = 123.456; + v1 := NewValue(&inter); + v2 := v1.(PtrValue).Sub().(StructValue).Field(0); + assert(v2.Type().String(), "interface { }"); + v3 := v2.(InterfaceValue).Value(); + assert(v3.Type().String(), "float"); + + i3 := v2.Interface(); + if f, ok := i3.(float); !ok { + a, typ, c := unsafe.Reflect(i3); + t.Error("v2.Interface() did not return float, got ", typ); + } +} + +func TestFunctionValue(t *testing.T) { + v := NewValue(func() {}); + if v.Interface() != v.Interface() { + t.Fatalf("TestFunction != itself"); + } + assert(v.Type().String(), "func()"); +} + +func TestCopyArray(t *testing.T) { + a := []int{ 1, 2, 3, 4, 10, 9, 8, 7 }; + b := []int{ 11, 22, 33, 44, 1010, 99, 88, 77, 66, 55, 44 }; + c := []int{ 11, 22, 33, 44, 1010, 99, 88, 77, 66, 55, 44 }; + va := NewValue(&a); + vb := NewValue(&b); + for i := 0; i < len(b); i++ { + if b[i] != c[i] { + t.Fatalf("b != c before test"); + } + } + for tocopy := 1; tocopy <= 7; tocopy++ { + vb.(PtrValue).Sub().(ArrayValue).CopyFrom(va.(PtrValue).Sub().(ArrayValue), tocopy); + for i := 0; i < tocopy; i++ { + if a[i] != b[i] { + t.Errorf("1 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("2 tocopy=%d a[%d]=%d, b[%d]=%d, c[%d]=%d", + tocopy, i, a[i], i, b[i], i, c[i]); + } else { + t.Errorf("3 tocopy=%d b[%d]=%d, c[%d]=%d", + tocopy, i, b[i], i, c[i]); + } + } else { + t.Logf("tocopy=%d elem %d is okay\n", tocopy, i); + } + } + } +} + +func TestBigUnnamedStruct(t *testing.T) { + b := struct{a,b,c,d int64}{1, 2, 3, 4}; + v := NewValue(b); + b1 := v.Interface().(struct{a,b,c,d int64}); + if b1.a != b.a || b1.b != b.b || b1.c != b.c || b1.d != b.d { + t.Errorf("NewValue(%v).Interface().(Big) = %v", b, b1); + } +} + +type big struct { + a, b, c, d, e int64 +} +func TestBigStruct(t *testing.T) { + b := big{1, 2, 3, 4, 5}; + v := NewValue(b); + b1 := v.Interface().(big); + if b1.a != b.a || b1.b != b.b || b1.c != b.c || b1.d != b.d || b1.e != b.e { + t.Errorf("NewValue(%v).Interface().(big) = %v", b, b1); + } +} + +type Basic struct { + x int; + y float32 +} + +type NotBasic Basic + +type Recursive struct { + x int; + r *Recursive +} + +type Complex struct { + a int; + b [3]*Complex; + c *string; + d map[float]float +} + +type DeepEqualTest struct { + a, b interface{}; + eq bool; +} + +var deepEqualTests = []DeepEqualTest { + // Equalities + DeepEqualTest{ 1, 1, true }, + DeepEqualTest{ int32(1), int32(1), true }, + DeepEqualTest{ 0.5, 0.5, true }, + DeepEqualTest{ float32(0.5), float32(0.5), true }, + DeepEqualTest{ "hello", "hello", true }, + DeepEqualTest{ make([]int, 10), make([]int, 10), true }, + DeepEqualTest{ &[3]int{ 1, 2, 3 }, &[3]int{ 1, 2, 3 }, true }, + DeepEqualTest{ Basic{ 1, 0.5 }, Basic{ 1, 0.5 }, true }, + // Inequalities + DeepEqualTest{ 1, 2, false }, + DeepEqualTest{ int32(1), int32(2), false }, + DeepEqualTest{ 0.5, 0.6, false }, + DeepEqualTest{ float32(0.5), float32(0.6), false }, + DeepEqualTest{ "hello", "hey", false }, + DeepEqualTest{ make([]int, 10), make([]int, 11), false }, + DeepEqualTest{ &[3]int{ 1, 2, 3 }, &[3]int{ 1, 2, 4 }, false }, + DeepEqualTest{ Basic{ 1, 0.5 }, Basic{ 1, 0.6 }, false }, + // Mismatched types + DeepEqualTest{ 1, 1.0, false }, + DeepEqualTest{ int32(1), int64(1), false }, + DeepEqualTest{ 0.5, "hello", false }, + DeepEqualTest{ []int{ 1, 2, 3 }, [3]int{ 1, 2, 3 }, false }, + DeepEqualTest{ &[3]interface{} { 1, 2, 4 }, &[3]interface{} { 1, 2, "s" }, false }, + DeepEqualTest{ Basic{ 1, 0.5 }, NotBasic{ 1, 0.5 }, false }, +} + +func TestDeepEqual(t *testing.T) { + for i, 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 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"); + } +} + +func TestDeepEqualComplexStruct(t *testing.T) { + m := make(map[float]float); + 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[float]float); + stra, strb := "hello", "helloo"; // Difference is here + a, b := new(Complex), new(Complex); + *a = Complex{5, [3]*Complex{a, b, a}, &stra, m}; + *b = Complex{5, [3]*Complex{b, a, a}, &strb, m}; + if DeepEqual(a, b) { + t.Error("DeepEqual(complex different) = true, want false"); + } +} + + +func check2ndField(x interface{}, offs uintptr, t *testing.T) { + s := NewValue(x).(StructValue); + name, ftype, tag, reflect_offset := s.Type().(StructType).Field(1); + if uintptr(reflect_offset) != offs { + t.Error("mismatched offsets in structure alignment:", reflect_offset, offs); + } +} + +// Check that structure alignment & offsets viewed through reflect agree with those +// from the compiler itself. +func TestAlignment(t *testing.T) { + type T1inner struct { + a int + } + type T1 struct { + T1inner; + f int; + } + type T2inner struct { + a, b int + } + type T2 struct { + T2inner; + f int; + } + + x := T1{T1inner{2}, 17}; + check2ndField(x, uintptr(unsafe.Pointer(&x.f)) - uintptr(unsafe.Pointer(&x)), t); + + x1 := T2{T2inner{2, 3}, 17}; + check2ndField(x1, uintptr(unsafe.Pointer(&x1.f)) - uintptr(unsafe.Pointer(&x1)), t); +} + +type Nillable interface { + IsNil() bool +} + +func Nil(a interface{}, t *testing.T) { + n := NewValue(a).(Nillable); + if !n.IsNil() { + t.Errorf("%v should be nil", a) + } +} + +func NotNil(a interface{}, t *testing.T) { + n := NewValue(a).(Nillable); + if n.IsNil() { + t.Errorf("value of type %v should not be nil", NewValue(a).Type().String()) + } +} + +func TestIsNil(t *testing.T) { + // These do not implement IsNil + doNotNil := []string{"int", "float32", "struct { a int }"}; + // These do implement IsNil + doNil := []string{"*int", "interface{}", "map[string]int", "func() bool", "chan int", "[]string"}; + for i, ts := range doNotNil { + ty := ParseTypeString("", ts); + v := NewZeroValue(ty); + if nilable, ok := v.(Nillable); ok { + t.Errorf("%s is nilable; should not be", ts) + } + } + + for i, ts := range doNil { + ty := ParseTypeString("", ts); + v := NewZeroValue(ty); + if nilable, ok := v.(Nillable); !ok { + t.Errorf("%s %T is not nilable; should be", ts, v) + } + } + // Check the implementations + var pi *int; + Nil(pi, t); + pi = new(int); + NotNil(pi, t); + + var si []int; + Nil(si, t); + si = make([]int, 10); + NotNil(si, t); + + // TODO: map and chan don't work yet + + var ii interface {}; + Nil(ii, t); + ii = pi; + NotNil(ii, t); + + var fi func(t *testing.T); + Nil(fi, t); + fi = TestIsNil; + NotNil(fi, t); +} + +func TestInterfaceExtraction(t *testing.T) { + var s struct { + w io.Writer; + } + + s.w = os.Stdout; + v := Indirect(NewValue(&s)).(StructValue).Field(0).Interface(); + if v != s.w.(interface{}) { + t.Errorf("Interface() on interface: ", v, s.w); + } +} + +func TestInterfaceEditing(t *testing.T) { + // strings are bigger than one word, + // so the interface conversion allocates + // memory to hold a string and puts that + // pointer in the interface. + var i interface{} = "hello"; + + // if i pass the interface value by value + // to NewValue, i should get a fresh copy + // of the value. + v := NewValue(i); + + // and setting that copy to "bye" should + // not change the value stored in i. + v.(StringValue).Set("bye"); + if i.(string) != "hello" { + t.Errorf(`Set("bye") changed i to %s`, i.(string)); + } + + // the same should be true of smaller items. + i = 123; + v = NewValue(i); + v.(IntValue).Set(234); + if i.(int) != 123 { + t.Errorf("Set(234) changed i to %d", i.(int)); + } +} diff --git a/src/pkg/reflect/deepequal.go b/src/pkg/reflect/deepequal.go new file mode 100644 index 000000000..57b52485f --- /dev/null +++ b/src/pkg/reflect/deepequal.go @@ -0,0 +1,83 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Deep equality test via reflection + +package reflect + +import "reflect" + +// 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[Addr]Addr) bool { + if v1.Kind() != v2.Kind() { + return false; + } + + // Short circuit if references are identical or already seen + addr1 := v1.Addr(); + addr2 := v2.Addr(); + + if addr1 == addr2 { + return true; + } + if vaddr, ok := visited[addr1]; ok && vaddr == addr2 { + return true; + } + visited[addr1] = addr2; + + switch v1.Kind() { + case ArrayKind: + arr1 := v1.(ArrayValue); + arr2 := v2.(ArrayValue); + if arr1.IsSlice() != arr2.IsSlice() || arr1.Len() != arr2.Len() { + return false; + } + for i := 0; i < arr1.Len(); i++ { + if !deepValueEqual(arr1.Elem(i), arr2.Elem(i), visited) { + return false; + } + } + return true; + case InterfaceKind: + return deepValueEqual(NewValue(v1.(InterfaceValue).Get()), + NewValue(v2.(InterfaceValue).Get()), visited); + case MapKind: + // TODO(dnadasi): Implement this fully once MapValue is implemented + return v1.Interface() == v2.Interface(); + case PtrKind: + return deepValueEqual(v1.(PtrValue).Sub(), v2.(PtrValue).Sub(), visited); + case StructKind: + struct1 := v1.(StructValue); + struct2 := v2.(StructValue); + if struct1.Len() != struct2.Len() { + return false; + } + for i := 0; i < struct1.Len(); i++ { + if !deepValueEqual(struct1.Field(i), struct2.Field(i), visited) { + 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. Until reflection supports maps, maps are equal iff +// they are identical. +func DeepEqual(a1, a2 interface{}) bool { + v1 := NewValue(a1); + v2 := NewValue(a2); + if !equalType(v1.Type(), v2.Type()) { + return false; + } + return deepValueEqual(v1, v2, make(map[Addr]Addr)); +} diff --git a/src/pkg/reflect/tostring.go b/src/pkg/reflect/tostring.go new file mode 100644 index 000000000..43be4b9e8 --- /dev/null +++ b/src/pkg/reflect/tostring.go @@ -0,0 +1,234 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Reflection library. +// 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 + +import ( + "reflect"; + "strconv"; +) + +func typeToString(typ Type, expand bool) string +func valueToString(val Value) string + +func doubleQuote(s string) string { + out := "\""; + for i := 0; i < len(s); i++ { + c := s[i]; + switch c { + case '\n': + out += `\n`; + case '\t': + out += `\t`; + case '\x00': + out += `\x00`; + case '"': + out += `\"`; + case '\\': + out += `\\`; + default: + out += string(c); + } + } + out += "\""; + return out; +} + +type hasFields interface { + Field(i int) (name string, typ Type, tag string, offset int); + Len() int; +} + +func typeFieldsToString(t hasFields, sep string, iface bool) string { + var str string; + for i := 0; i < t.Len(); i++ { + str1, typ, tag, offset := t.Field(i); + if str1 != "" { + str1 += " " + } + str2 := typeToString(typ, false); + if iface && str2[0:4] == "func" { + str2 = str2[4:len(str2)] + } + str1 += str2; + if tag != "" { + str1 += " " + doubleQuote(tag); + } + if i < t.Len() - 1 { + str1 += sep + " "; + } + str += str1; + } + return str; +} + +// typeToString returns a textual representation of typ. The expand +// flag specifies whether to expand the contents of type names; if false, +// the name itself is used as the representation. +// Meant for debugging only; typ.String() serves for most purposes. +func typeToString(typ Type, expand bool) string { + var str string; + if name := typ.Name(); !expand && name != "" { + return name + } + switch(typ.Kind()) { + case MissingKind: + return "$missing$"; + case IntKind, Int8Kind, Int16Kind, Int32Kind, Int64Kind, + UintKind, Uint8Kind, Uint16Kind, Uint32Kind, Uint64Kind, + FloatKind, Float32Kind, Float64Kind, + StringKind, + DotDotDotKind: + return typ.Name(); + case PtrKind: + p := typ.(PtrType); + return "*" + typeToString(p.Sub(), false); + case ArrayKind: + a := typ.(ArrayType); + if a.IsSlice() { + str = "[]" + } else { + str = "[" + strconv.Itoa64(int64(a.Len())) + "]" + } + return str + typeToString(a.Elem(), false); + case MapKind: + m := typ.(MapType); + str = "map[" + typeToString(m.Key(), false) + "]"; + return str + typeToString(m.Elem(), false); + case ChanKind: + c := typ.(ChanType); + switch c.Dir() { + case RecvDir: + str = "<-chan"; + case SendDir: + str = "chan<-"; + case BothDir: + str = "chan"; + default: + panicln("reflect.typeToString: unknown chan direction"); + } + return str + typeToString(c.Elem(), false); + case StructKind: + return "struct{" + typeFieldsToString(typ.(StructType), ";", false) + "}"; + case InterfaceKind: + return "interface{" + typeFieldsToString(typ.(InterfaceType), ";", true) + "}"; + case FuncKind: + f := typ.(FuncType); + str = "func(" + typeFieldsToString(f.In(), ",", false) + ")"; + if f.Out() != nil { + str += "(" + typeFieldsToString(f.Out(), ",", false) + ")"; + } + return str; + default: + panicln("reflect.typeToString: can't print type ", typ.Kind()); + } + return "reflect.typeToString: can't happen"; +} + +// TODO: want an unsigned one too +func integer(v int64) string { + return strconv.Itoa64(v); +} + +// valueToString returns a textual representation of the reflection value val. +// For debugging only. +func valueToString(val Value) string { + var str string; + typ := val.Type(); + switch(val.Kind()) { + case MissingKind: + return "missing"; + case IntKind: + return integer(int64(val.(IntValue).Get())); + case Int8Kind: + return integer(int64(val.(Int8Value).Get())); + case Int16Kind: + return integer(int64(val.(Int16Value).Get())); + case Int32Kind: + return integer(int64(val.(Int32Value).Get())); + case Int64Kind: + return integer(int64(val.(Int64Value).Get())); + case UintKind: + return integer(int64(val.(UintValue).Get())); + case Uint8Kind: + return integer(int64(val.(Uint8Value).Get())); + case Uint16Kind: + return integer(int64(val.(Uint16Value).Get())); + case Uint32Kind: + return integer(int64(val.(Uint32Value).Get())); + case Uint64Kind: + return integer(int64(val.(Uint64Value).Get())); + case FloatKind: + if strconv.FloatSize == 32 { + return strconv.Ftoa32(float32(val.(FloatValue).Get()), 'g', -1); + } else { + return strconv.Ftoa64(float64(val.(FloatValue).Get()), 'g', -1); + } + case Float32Kind: + return strconv.Ftoa32(val.(Float32Value).Get(), 'g', -1); + case Float64Kind: + return strconv.Ftoa64(val.(Float64Value).Get(), 'g', -1); + case StringKind: + return val.(StringValue).Get(); + case BoolKind: + if val.(BoolValue).Get() { + return "true" + } else { + return "false" + } + case PtrKind: + v := val.(PtrValue); + return typeToString(typ, false) + "(" + integer(int64(uintptr(v.Get()))) + ")"; + case ArrayKind: + t := typ.(ArrayType); + v := val.(ArrayValue); + str += typeToString(t, false); + str += "{"; + for i := 0; i < v.Len(); i++ { + if i > 0 { + str += ", " + } + str += valueToString(v.Elem(i)); + } + str += "}"; + return str; + case MapKind: + t := typ.(MapType); + v := val.(MapValue); + str = typeToString(t, false); + str += "{"; + str += ""; + str += "}"; + return str; + case ChanKind: + str = typeToString(typ, false); + return str; + case StructKind: + t := typ.(StructType); + v := val.(StructValue); + str += typeToString(t, false); + str += "{"; + for i := 0; i < v.Len(); i++ { + if i > 0 { + str += ", " + } + str += valueToString(v.Field(i)); + } + str += "}"; + return str; + case InterfaceKind: + return "can't print interfaces yet"; + case FuncKind: + v := val.(FuncValue); + return typeToString(typ, false) + "(" + integer(int64(uintptr(v.Get()))) + ")"; + default: + panicln("reflect.valueToString: can't print type ", val.Kind()); + } + return "reflect.valueToString: can't happen"; +} diff --git a/src/pkg/reflect/type.go b/src/pkg/reflect/type.go new file mode 100644 index 000000000..c8542183a --- /dev/null +++ b/src/pkg/reflect/type.go @@ -0,0 +1,1047 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Reflection library. +// Types and parsing of type strings. + +// This package implements data ``reflection''. A program can use it to analyze types +// and values it does not know at compile time, such as the values passed in a call +// to a function with a ... parameter. This is achieved by extracting the dynamic +// contents of an interface value. +package reflect + +import ( + "sync"; + "unsafe"; + "utf8"; +) + +type Type interface + +func ExpandType(name string) Type + +func typestrings() string // implemented in C; declared here + +// These constants identify what kind of thing a Type represents: an int, struct, etc. +const ( + MissingKind = iota; + ArrayKind; + BoolKind; + ChanKind; + DotDotDotKind; + FloatKind; + Float32Kind; + Float64Kind; + FuncKind; + IntKind; + Int16Kind; + Int32Kind; + Int64Kind; + Int8Kind; + InterfaceKind; + MapKind; + PtrKind; + StringKind; + StructKind; + UintKind; + Uint16Kind; + Uint32Kind; + Uint64Kind; + Uint8Kind; + UintptrKind; +) + +// For sizes and alignments. + +type allTypes struct { + xarray []byte; + xbool bool; + xchan chan byte; + xfloat float; + xfloat32 float32; + xfloat64 float64; + xfunc func(); + xint int; + xint16 int16; + xint32 int32; + xint64 int64; + xint8 int8; + xinterface interface {}; + xmap map[byte]byte; + xptr *byte; + xslice []byte; + xstring string; + xuint uint; + xuint16 uint16; + xuint32 uint32; + xuint64 uint64; + xuint8 uint8; + xuintptr uintptr; +} + +var ( + x allTypes; + minStruct struct { uint8 }; +) + +const ( + minStructAlignMask = unsafe.Sizeof(minStruct) - 1; + ptrsize = unsafe.Sizeof(&x); + interfacesize = unsafe.Sizeof(x.xinterface); +) + +const missingString = "$missing$" // syntactic name for undefined type names +const dotDotDotString = "..." + +// Type is the generic interface to reflection types. Once its Kind is known, +// such as ArrayKind, the Type can be narrowed to the appropriate, more +// specific interface, such as ArrayType. Such narrowed types still implement +// the Type interface. +type Type interface { + // The kind of thing described: ArrayKind, BoolKind, etc. + Kind() int; + // The name declared for the type ("int", "BoolArray", etc.). + Name() string; + // For a named type, same as Name(); otherwise a representation of the type such as "[]int". + String() string; + // The number of bytes needed to store a value; analogous to unsafe.Sizeof(). + Size() int; + // The alignment of a value of this type when used as a field in a struct. + FieldAlign() int; +} + +// Fields and methods common to all types +type commonType struct { + kind int; + str string; + name string; + size int; +} + +func (c *commonType) Kind() int { + return c.kind +} + +func (c *commonType) Name() string { + return c.name +} + +func (c *commonType) String() string { + // If there is a name, show that instead of its expansion. + // This is important for reflection: a named type + // might have methods that the unnamed type does not. + if c.name != "" { + return c.name + } + return c.str +} + +func (c *commonType) Size() int { + return c.size +} + +// -- Basic + +type basicType struct { + commonType; + fieldAlign int; +} + +func newBasicType(name string, kind int, size int, fieldAlign int) Type { + return &basicType{ commonType{kind, name, name, size}, fieldAlign } +} + +func (t *basicType) FieldAlign() int { + return t.fieldAlign +} + +// Prebuilt basic Type objects representing the predeclared basic types. +// Most are self-evident except: +// Missing represents types whose representation cannot be discovered; usually an error. +// DotDotDot represents the pseudo-type of a ... parameter. +var ( + Missing = newBasicType(missingString, MissingKind, 1, 1); + DotDotDot = newBasicType(dotDotDotString, DotDotDotKind, unsafe.Sizeof(x.xinterface), unsafe.Alignof(x.xinterface)); + Bool = newBasicType("bool", BoolKind, unsafe.Sizeof(x.xbool), unsafe.Alignof(x.xbool)); + Int = newBasicType("int", IntKind, unsafe.Sizeof(x.xint), unsafe.Alignof(x.xint)); + Int8 = newBasicType("int8", Int8Kind, unsafe.Sizeof(x.xint8), unsafe.Alignof(x.xint8)); + Int16 = newBasicType("int16", Int16Kind, unsafe.Sizeof(x.xint16), unsafe.Alignof(x.xint16)); + Int32 = newBasicType("int32", Int32Kind, unsafe.Sizeof(x.xint32), unsafe.Alignof(x.xint32)); + Int64 = newBasicType("int64", Int64Kind, unsafe.Sizeof(x.xint64), unsafe.Alignof(x.xint64)); + Uint = newBasicType("uint", UintKind, unsafe.Sizeof(x.xuint), unsafe.Alignof(x.xuint)); + Uint8 = newBasicType("uint8", Uint8Kind, unsafe.Sizeof(x.xuint8), unsafe.Alignof(x.xuint8)); + Uint16 = newBasicType("uint16", Uint16Kind, unsafe.Sizeof(x.xuint16), unsafe.Alignof(x.xuint16)); + Uint32 = newBasicType("uint32", Uint32Kind, unsafe.Sizeof(x.xuint32), unsafe.Alignof(x.xuint32)); + Uint64 = newBasicType("uint64", Uint64Kind, unsafe.Sizeof(x.xuint64), unsafe.Alignof(x.xuint64)); + Uintptr = newBasicType("uintptr", UintptrKind, unsafe.Sizeof(x.xuintptr), unsafe.Alignof(x.xuintptr)); + Float = newBasicType("float", FloatKind, unsafe.Sizeof(x.xfloat), unsafe.Alignof(x.xfloat)); + Float32 = newBasicType("float32", Float32Kind, unsafe.Sizeof(x.xfloat32), unsafe.Alignof(x.xfloat32)); + Float64 = newBasicType("float64", Float64Kind, unsafe.Sizeof(x.xfloat64), unsafe.Alignof(x.xfloat64)); + String = newBasicType("string", StringKind, unsafe.Sizeof(x.xstring), unsafe.Alignof(x.xstring)); +) + +// Stub types allow us to defer evaluating type names until needed. +// If the name is empty, the type must be non-nil. + +type stubType struct { + name string; + typ Type; +} + +func newStubType(name string, typ Type) *stubType { + return &stubType{name, typ} +} + +func (t *stubType) Get() Type { + if t.typ == nil { + t.typ = ExpandType(t.name) + } + return t.typ +} + +// -- Pointer + +// PtrType represents a pointer. +type PtrType interface { + Type; + Sub() Type // The type of the pointed-to item; for "*int", it will be "int". +} + +type ptrTypeStruct struct { + commonType; + sub *stubType; +} + +func newPtrTypeStruct(name, typestring string, sub *stubType) *ptrTypeStruct { + return &ptrTypeStruct{ commonType{PtrKind, typestring, name, ptrsize}, sub} +} + +func (t *ptrTypeStruct) FieldAlign() int { + return unsafe.Alignof(x.xptr); +} + +func (t *ptrTypeStruct) Sub() Type { + return t.sub.Get() +} + +// -- Array + +// ArrayType represents an array or slice type. +type ArrayType interface { + Type; + IsSlice() bool; // True for slices, false for arrays. + Len() int; // 0 for slices, the length for array types. + Elem() Type; // The type of the elements. +} + +type arrayTypeStruct struct { + commonType; + elem *stubType; + isslice bool; // otherwise fixed array + len int; +} + +func newArrayTypeStruct(name, typestring string, open bool, len int, elem *stubType) *arrayTypeStruct { + return &arrayTypeStruct{ commonType{ArrayKind, typestring, name, 0 }, elem, open, len} +} + +func (t *arrayTypeStruct) Size() int { + if t.isslice { + return unsafe.Sizeof(x.xslice); + } + return t.len * t.elem.Get().Size(); +} + +func (t *arrayTypeStruct) FieldAlign() int { + if t.isslice { + return unsafe.Alignof(x.xslice); + } + return t.elem.Get().FieldAlign(); +} + +func (t *arrayTypeStruct) IsSlice() bool { + return t.isslice +} + +func (t *arrayTypeStruct) Len() int { + if t.isslice { + return 0 + } + return t.len +} + +func (t *arrayTypeStruct) Elem() Type { + return t.elem.Get() +} + +// -- Map + +// MapType represents a map type. +type MapType interface { + Type; + Key() Type; // The type of the keys. + Elem() Type; // The type of the elements/values. +} + +type mapTypeStruct struct { + commonType; + key *stubType; + elem *stubType; +} + +func newMapTypeStruct(name, typestring string, key, elem *stubType) *mapTypeStruct { + return &mapTypeStruct{ commonType{MapKind, typestring, name, ptrsize}, key, elem} +} + +func (t *mapTypeStruct) FieldAlign() int { + return unsafe.Alignof(x.xmap); +} + +func (t *mapTypeStruct) Key() Type { + return t.key.Get() +} + +func (t *mapTypeStruct) Elem() Type { + return t.elem.Get() +} + +// -- Chan + +// ChanType represents a chan type. +type ChanType interface { + Type; + Dir() int; // The direction of the channel. + Elem() Type; // The type of the elements. +} + +// Channel direction. +const ( + SendDir = 1 << iota; + RecvDir; + BothDir = SendDir | RecvDir; +) + +type chanTypeStruct struct { + commonType; + elem *stubType; + dir int; +} + +func newChanTypeStruct(name, typestring string, dir int, elem *stubType) *chanTypeStruct { + return &chanTypeStruct{ commonType{ChanKind, typestring, name, ptrsize}, elem, dir} +} + +func (t *chanTypeStruct) FieldAlign() int { + return unsafe.Alignof(x.xchan); +} + +func (t *chanTypeStruct) Dir() int { + return t.dir +} + +func (t *chanTypeStruct) Elem() Type { + return t.elem.Get() +} + +// -- Struct + +// StructType represents a struct type. +type StructType interface { + Type; + // Field returns, for field i, its name, Type, tag information, and byte offset. + // The indices are in declaration order starting at 0. + Field(i int) (name string, typ Type, tag string, offset int); + // Len is the number of fields. + Len() int; +} + +type structField struct { + name string; + typ *stubType; + tag string; + offset int; +} + +type structTypeStruct struct { + commonType; + field []structField; + fieldAlign int; +} + +func newStructTypeStruct(name, typestring string, field []structField) *structTypeStruct { + return &structTypeStruct{ commonType{StructKind, typestring, name, 0}, field, 0} +} + +func (t *structTypeStruct) FieldAlign() int { + t.Size(); // Compute size and alignment. + return t.fieldAlign +} + +func (t *structTypeStruct) Size() int { + if t.size > 0 { + return t.size + } + size := 0; + structAlignMask := 0; + for i := 0; i < len(t.field); i++ { + typ := t.field[i].typ.Get(); + elemsize := typ.Size(); + alignMask := typ.FieldAlign() - 1; + if alignMask > structAlignMask { + structAlignMask = alignMask + } + if alignMask > 0 { + size = (size + alignMask) &^ alignMask; + } + t.field[i].offset = size; + size += elemsize; + } + if (structAlignMask > 0) { + // 6g etc. always aligns structs to a minimum size, typically int64 + if structAlignMask < minStructAlignMask { + structAlignMask = minStructAlignMask + } + // TODO: In the PPC64 ELF ABI, floating point fields + // in a struct are aligned to a 4-byte boundary, but + // if the first field in the struct is a 64-bit float, + // the whole struct is aligned to an 8-byte boundary. + size = (size + structAlignMask) &^ structAlignMask; + t.fieldAlign = structAlignMask + 1; + } + t.size = size; + return size; +} + +func (t *structTypeStruct) Field(i int) (name string, typ Type, tag string, offset int) { + if t.field[i].offset == 0 { + t.Size(); // will compute offsets + } + return t.field[i].name, t.field[i].typ.Get(), t.field[i].tag, t.field[i].offset +} + +func (t *structTypeStruct) Len() int { + return len(t.field) +} + +// -- Interface + +// InterfaceType represents an interface type. +// It behaves much like a StructType, treating the methods as fields. +type InterfaceType interface { + Type; + // Field returns, for method i, its name, Type, the empty string, and 0. + // The indices are in declaration order starting at 0. TODO: is this true? + Field(int) (name string, typ Type, tag string, offset int); + Len() int; +} + +type interfaceTypeStruct struct { + commonType; + field []structField; +} + +func newInterfaceTypeStruct(name, typestring string, field []structField) *interfaceTypeStruct { + return &interfaceTypeStruct{ commonType{InterfaceKind, typestring, name, interfacesize}, field } +} + +func (t *interfaceTypeStruct) FieldAlign() int { + return unsafe.Alignof(x.xinterface); +} + +func (t *interfaceTypeStruct) Field(i int) (name string, typ Type, tag string, offset int) { + return t.field[i].name, t.field[i].typ.Get(), "", 0 +} + +func (t *interfaceTypeStruct) Len() int { + return len(t.field) +} + +var nilInterface = newInterfaceTypeStruct("nil", "", make([]structField, 0)); + +// -- Func + +// FuncType represents a function type. +type FuncType interface { + Type; + In() StructType; // The parameters in the form of a StructType. + Out() StructType; // The results in the form of a StructType. +} + +type funcTypeStruct struct { + commonType; + in *structTypeStruct; + out *structTypeStruct; +} + +func newFuncTypeStruct(name, typestring string, in, out *structTypeStruct) *funcTypeStruct { + return &funcTypeStruct{ commonType{FuncKind, typestring, name, ptrsize}, in, out } +} + +func (t *funcTypeStruct) FieldAlign() int { + return unsafe.Alignof(x.xfunc); +} + +func (t *funcTypeStruct) In() StructType { + return t.in +} + +func (t *funcTypeStruct) Out() StructType { + if t.out == nil { // nil.(StructType) != nil so make sure caller sees real nil + return nil + } + return t.out +} + +// Cache of expanded types keyed by type name. +var types map[string] Type + +// List of typename, typestring pairs +var typestring map[string] string +var initialized bool = false + +// Map of basic types to prebuilt stubTypes +var basicstub map[string] *stubType + +var missingStub *stubType; +var dotDotDotStub *stubType; + +// The database stored in the maps is global; use locking to guarantee safety. +var typestringlock sync.Mutex + +func lock() { + typestringlock.Lock() +} + +func unlock() { + typestringlock.Unlock() +} + +func init() { + lock(); // not necessary because of init ordering but be safe. + + types = make(map[string] Type); + typestring = make(map[string] string); + basicstub = make(map[string] *stubType); + + // Basics go into types table + types[missingString] = Missing; + types[dotDotDotString] = DotDotDot; + types["int"] = Int; + types["int8"] = Int8; + types["int16"] = Int16; + types["int32"] = Int32; + types["int64"] = Int64; + types["uint"] = Uint; + types["uint8"] = Uint8; + types["uint16"] = Uint16; + types["uint32"] = Uint32; + types["uint64"] = Uint64; + types["uintptr"] = Uintptr; + types["float"] = Float; + types["float32"] = Float32; + types["float64"] = Float64; + types["string"] = String; + types["bool"] = Bool; + + // Basics get prebuilt stubs + missingStub = newStubType(missingString, Missing); + dotDotDotStub = newStubType(dotDotDotString, DotDotDot); + basicstub[missingString] = missingStub; + basicstub[dotDotDotString] = dotDotDotStub; + basicstub["int"] = newStubType("int", Int); + basicstub["int8"] = newStubType("int8", Int8); + basicstub["int16"] = newStubType("int16", Int16); + basicstub["int32"] = newStubType("int32", Int32); + basicstub["int64"] = newStubType("int64", Int64); + basicstub["uint"] = newStubType("uint", Uint); + basicstub["uint8"] = newStubType("uint8", Uint8); + basicstub["uint16"] = newStubType("uint16", Uint16); + basicstub["uint32"] = newStubType("uint32", Uint32); + basicstub["uint64"] = newStubType("uint64", Uint64); + basicstub["uintptr"] = newStubType("uintptr", Uintptr); + basicstub["float"] = newStubType("float", Float); + basicstub["float32"] = newStubType("float32", Float32); + basicstub["float64"] = newStubType("float64", Float64); + basicstub["string"] = newStubType("string", String); + basicstub["bool"] = newStubType("bool", Bool); + + unlock(); +} + +/* + Parsing of type strings. These strings are how the run-time recovers type + information dynamically. + + Grammar + + stubtype = - represent as StubType when possible + type + identifier = + name + '?' + type = + basictypename - int8, string, etc. + typename + arraytype + structtype + interfacetype + chantype + maptype + pointertype + functiontype + typename = + name '.' name + doublequotedstring = + string in " "; escapes are \x00 (NUL) \n \t \" \\ + fieldlist = + [ field { [ ',' | ';' ] field } ] + field = + identifier stubtype [ doublequotedstring ] + arraytype = + '[' [ number ] ']' stubtype + structtype = + 'struct' '{' fieldlist '}' + interfacetype = + 'interface' '{' fieldlist '}' + chantype = + '<-' 'chan' stubtype + 'chan' '<-' stubtype + 'chan' stubtype + maptype = + 'map' '[' stubtype ']' stubtype + pointertype = + '*' stubtype + functiontype = + [ 'func' ] '(' fieldlist ')' [ '(' fieldlist ')' | stubtype ] + + In functiontype 'func' is optional because it is omitted in + the reflection string for interface types. + +*/ + +// Helper functions for token scanning +func isdigit(c uint8) bool { + return '0' <= c && c <= '9' +} + +func special(c uint8) bool { + s := "*[](){}<;,"; // Note: '.' is not in this list. "P.T" is an identifer, as is "?". + for i := 0; i < len(s); i++ { + if c == s[i] { + return true + } + } + return false; +} + +func hex00(s string, i int) bool { + return i + 2 < len(s) && s[i] == '0' && s[i+1] == '0' +} + +// Process backslashes. String known to be well-formed. +// Initial double-quote is left in, as an indication this token is a string. +func unescape(s string, backslash bool) string { + if !backslash { + return s + } + out := "\""; + for i := 1; i < len(s); i++ { + c := s[i]; + if c == '\\' { + i++; + c = s[i]; + switch c { + case 'n': + c = '\n'; + case 't': + c = '\t'; + case 'x': + if hex00(s, i+1) { + i += 2; + c = 0; + break; + } + // otherwise just put an 'x'; erroneous but safe. + // default is correct already; \\ is \; \" is " + } + } + out += string(c); + } + return out; +} + +// Simple parser for type strings +type typeParser struct { + str string; // string being parsed + token string; // the token being parsed now + tokstart int; // starting position of token + prevend int; // (one after) ending position of previous token + index int; // next character position in str +} + +// Return typestring starting at position i. It will finish at the +// end of the previous token (before trailing white space). +func (p *typeParser) TypeString(i int) string { + return p.str[i:p.prevend]; +} + +// Load next token into p.token +func (p *typeParser) Next() { + p.prevend = p.index; + token := ""; + for ; p.index < len(p.str) && p.str[p.index] == ' '; p.index++ { + } + p.tokstart = p.index; + if p.index >= len(p.str) { + p.token = ""; + return; + } + start := p.index; + c, w := utf8.DecodeRuneInString(p.str[p.index:len(p.str)]); + p.index += w; + switch { + case c == '<': + if p.index < len(p.str) && p.str[p.index] == '-' { + p.index++; + p.token = "<-"; + return; + } + fallthrough; // shouldn't happen but let the parser figure it out + case c == '.': + if p.index < len(p.str)+2 && p.str[p.index-1:p.index+2] == dotDotDotString { + p.index += 2; + p.token = dotDotDotString; + return; + } + fallthrough; // shouldn't happen but let the parser figure it out + case special(uint8(c)): + p.token = string(c); + return; + case isdigit(uint8(c)): + for p.index < len(p.str) && isdigit(p.str[p.index]) { + p.index++ + } + p.token = p.str[start : p.index]; + return; + case c == '"': // double-quoted string for struct field annotation + backslash := false; + for p.index < len(p.str) && p.str[p.index] != '"' { + if p.str[p.index] == '\\' { + if p.index+1 == len(p.str) { // bad final backslash + break; + } + p.index++; // skip (and accept) backslash + backslash = true; + } + p.index++ + } + p.token = unescape(p.str[start : p.index], backslash); + if p.index < len(p.str) { // properly terminated string + p.index++; // skip the terminating double-quote + } + return; + } + for p.index < len(p.str) && p.str[p.index] != ' ' && !special(p.str[p.index]) { + p.index++ + } + p.token = p.str[start : p.index]; +} + +func (p *typeParser) Type(name string) *stubType + +func (p *typeParser) Array(name string, tokstart int) *stubType { + size := 0; + open := true; + if p.token != "]" { + if len(p.token) == 0 || !isdigit(p.token[0]) { + return missingStub + } + // write our own (trivial and simpleminded) atoi to avoid dependency + size = 0; + for i := 0; i < len(p.token); i++ { + size = size * 10 + int(p.token[i]) - '0' + } + p.Next(); + open = false; + } + if p.token != "]" { + return missingStub + } + p.Next(); + elemtype := p.Type(""); + return newStubType(name, newArrayTypeStruct(name, p.TypeString(tokstart), open, size, elemtype)); +} + +func (p *typeParser) Map(name string, tokstart int) *stubType { + if p.token != "[" { + return missingStub + } + p.Next(); + keytype := p.Type(""); + if p.token != "]" { + return missingStub + } + p.Next(); + elemtype := p.Type(""); + return newStubType(name, newMapTypeStruct(name, p.TypeString(tokstart), keytype, elemtype)); +} + +func (p *typeParser) Chan(name string, tokstart, dir int) *stubType { + if p.token == "<-" { + if dir != BothDir { + return missingStub + } + p.Next(); + dir = SendDir; + } + elemtype := p.Type(""); + return newStubType(name, newChanTypeStruct(name, p.TypeString(tokstart), dir, elemtype)); +} + +// Parse array of fields for struct, interface, and func arguments +func (p *typeParser) Fields(sep, term string) []structField { + a := make([]structField, 10); + nf := 0; + for p.token != "" && p.token != term { + if nf == len(a) { + a1 := make([]structField, 2*nf); + for i := 0; i < nf; i++ { + a1[i] = a[i]; + } + a = a1; + } + name := p.token; + if name == "?" { // used to represent a missing name + name = "" + } + a[nf].name = name; + p.Next(); + a[nf].typ = p.Type(""); + if p.token != "" && p.token[0] == '"' { + a[nf].tag = p.token[1:len(p.token)]; + p.Next(); + } + nf++; + if p.token != sep { + break; + } + p.Next(); // skip separator + } + return a[0:nf]; +} + +// A single type packaged as a field for a function return +func (p *typeParser) OneField() []structField { + a := make([]structField, 1); + a[0].name = ""; + a[0].typ = p.Type(""); + return a; +} + +func (p *typeParser) Struct(name string, tokstart int) *stubType { + f := p.Fields(";", "}"); + if p.token != "}" { + return missingStub; + } + p.Next(); + return newStubType(name, newStructTypeStruct(name, p.TypeString(tokstart), f)); +} + +func (p *typeParser) Interface(name string, tokstart int) *stubType { + f := p.Fields(";", "}"); + if p.token != "}" { + return missingStub; + } + p.Next(); + return newStubType(name, newInterfaceTypeStruct(name, p.TypeString(tokstart), f)); +} + +func (p *typeParser) Func(name string, tokstart int) *stubType { + // may be 1 or 2 parenthesized lists + f1 := newStructTypeStruct("", "", p.Fields(",", ")")); + if p.token != ")" { + return missingStub; + } + p.Next(); + if p.token != "(" { + // 1 list: the in parameters are a list. Is there a single out parameter? + switch p.token { + case "", "}", ")", ",", ";": + return newStubType(name, newFuncTypeStruct(name, p.TypeString(tokstart), f1, nil)); + } + // A single out parameter. + f2 := newStructTypeStruct("", "", p.OneField()); + return newStubType(name, newFuncTypeStruct(name, p.TypeString(tokstart), f1, f2)); + } else { + p.Next(); + } + f2 := newStructTypeStruct("", "", p.Fields(",", ")")); + if p.token != ")" { + return missingStub; + } + p.Next(); + // 2 lists: the in and out parameters are present + return newStubType(name, newFuncTypeStruct(name, p.TypeString(tokstart), f1, f2)); +} + +func (p *typeParser) Type(name string) *stubType { + dir := BothDir; + tokstart := p.tokstart; + switch { + case p.token == "": + return nil; + case p.token == "*": + p.Next(); + sub := p.Type(""); + return newStubType(name, newPtrTypeStruct(name, p.TypeString(tokstart), sub)); + case p.token == "[": + p.Next(); + return p.Array(name, tokstart); + case p.token == "map": + p.Next(); + return p.Map(name, tokstart); + case p.token == "<-": + p.Next(); + dir = RecvDir; + if p.token != "chan" { + return missingStub; + } + fallthrough; + case p.token == "chan": + p.Next(); + return p.Chan(name, tokstart, dir); + case p.token == "struct": + p.Next(); + if p.token != "{" { + return missingStub + } + p.Next(); + return p.Struct(name, tokstart); + case p.token == "interface": + p.Next(); + if p.token != "{" { + return missingStub + } + p.Next(); + return p.Interface(name, tokstart); + case p.token == "func": + p.Next(); + if p.token != "(" { + return missingStub + } + p.Next(); + return p.Func(name, tokstart); + case p.token == "(": + p.Next(); + return p.Func(name, tokstart); + case isdigit(p.token[0]): + p.Next(); + return missingStub; + case special(p.token[0]): + p.Next(); + return missingStub; + } + // must be an identifier. is it basic? if so, we have a stub + if s, ok := basicstub[p.token]; ok { + p.Next(); + if name != "" { + // Need to make a copy because we are renaming a basic type + b := s.Get(); + s = newStubType(name, newBasicType(name, b.Kind(), b.Size(), b.FieldAlign())); + } + return s + } + // not a basic - must be of the form "P.T" + ndot := 0; + for i := 0; i < len(p.token); i++ { + if p.token[i] == '.' { + ndot++ + } + } + if ndot != 1 { + p.Next(); + return missingStub; + } + s := newStubType(p.token, nil); + p.Next(); + return s; +} + +// ParseTypeString takes a type name and type string (such as "[]int") and +// returns the Type structure representing a type name specifying the corresponding +// type. An empty typestring represents (the type of) a nil interface value. +func ParseTypeString(name, typestring string) Type { + if typestring == "" { + // If the typestring is empty, it represents (the type of) a nil interface value + return nilInterface + } + p := new(typeParser); + p.str = typestring; + p.Next(); + return p.Type(name).Get(); +} + +// Create typestring map from reflect.typestrings() data. Lock is held. +func initializeTypeStrings() { + if initialized { + return + } + initialized = true; + s := typestrings(); + slen := len(s); + for i := 0; i < slen; { + // "reflect.PtrType interface { Sub () (? reflect.Type) }\n" + // find the identifier + idstart := i; + for ; i < slen && s[i] != ' '; i++ { + } + if i == slen { + print("reflect.InitializeTypeStrings: bad identifier\n"); + return; + } + idend := i; + i++; + // find the end of the line, terminating the type + typestart := i; + for ; i < slen && s[i] != '\n'; i++ { + } + if i == slen { + print("reflect.InitializeTypeStrings: bad type string\n"); + return; + } + typeend := i; + i++; //skip newline + typestring[s[idstart:idend]] = s[typestart:typeend]; + } +} + +// Look up type string associated with name. Lock is held. +func typeNameToTypeString(name string) string { + s, ok := typestring[name]; + if !ok { + initializeTypeStrings(); + s, ok = typestring[name]; + if !ok { + s = missingString; + typestring[name] = s; + } + } + return s +} + +// ExpandType takes the name of a type and returns its Type structure, +// unpacking the associated type string if necessary. +func ExpandType(name string) Type { + lock(); + t, ok := types[name]; + if ok { + unlock(); + return t + } + types[name] = Missing; // prevent recursion; will overwrite + t1 := ParseTypeString(name, typeNameToTypeString(name)); + types[name] = t1; + unlock(); + return t1; +} diff --git a/src/pkg/reflect/typestring.c b/src/pkg/reflect/typestring.c new file mode 100644 index 000000000..667037bb1 --- /dev/null +++ b/src/pkg/reflect/typestring.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. + + +extern char gotypestrings[]; // 4-byte count followed by byte[count] + +void FLUSH(void*); + +typedef struct String String; +struct String +{ + char* str; + char len[4]; + char cap[4]; +}; + +void +reflect·typestrings(String str) +{ + char *s; + int i; + + s = gotypestrings; + + // repeat the count twice + // once for len, once for cap + for(i=0; i<4; i++) { + str.len[i] = s[i]; + str.cap[i] = s[i]; + } + + // and the pointer + str.str = s+4; + + FLUSH(&str); +} diff --git a/src/pkg/reflect/value.go b/src/pkg/reflect/value.go new file mode 100644 index 000000000..d4783d546 --- /dev/null +++ b/src/pkg/reflect/value.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. + +// Reflection library. +// Handling values. + +package reflect + +import ( + "reflect"; + "unsafe"; +) + +// Addr is shorthand for unsafe.Pointer and is used to represent the address of Values. +type Addr unsafe.Pointer + +func equalType(a, b Type) bool { + return a.String() == b.String() +} + +// Value is the generic interface to reflection values. Once its Kind is known, +// such as BoolKind, the Value can be narrowed to the appropriate, more +// specific interface, such as BoolValue. Such narrowed values still implement +// the Value interface. +type Value interface { + // The kind of thing described: ArrayKind, BoolKind, etc. + Kind() int; + // The reflection Type of the value. + Type() Type; + // The address of the value. + Addr() Addr; + // The value itself is the dynamic value of an empty interface. + Interface() interface {}; +} + +func NewValue(e interface{}) Value; + +// commonValue fields and functionality for all values + +type commonValue struct { + kind int; + typ Type; + addr Addr; +} + +func (c *commonValue) Kind() int { + return c.kind +} + +func (c *commonValue) Type() Type { + return c.typ +} + +func (c *commonValue) Addr() Addr { + return c.addr +} + +func (c *commonValue) Interface() interface {} { + var i interface {}; + switch { + case c.typ.Kind() == InterfaceKind: + panic("not reached"); // InterfaceValue overrides this method + case c.typ.Size() > unsafe.Sizeof(uintptr(0)): + i = unsafe.Unreflect(uint64(uintptr(c.addr)), c.typ.String(), true); + default: + if uintptr(c.addr) == 0 { + panicln("reflect: address 0 for", c.typ.String()); + } + i = unsafe.Unreflect(uint64(uintptr(*(*Addr)(c.addr))), c.typ.String(), false); + } + return i; +} + +func newValueAddr(typ Type, addr Addr) Value + +type creatorFn func(typ Type, addr Addr) Value + + +// -- Missing + +// MissingValue represents a value whose type is not known. It usually +// indicates an error. +type MissingValue interface { + Value; +} + +type missingValueStruct struct { + commonValue +} + +func missingCreator(typ Type, addr Addr) Value { + return &missingValueStruct{ commonValue{MissingKind, typ, addr} } +} + +// -- Int + +// IntValue represents an int value. +type IntValue interface { + Value; + Get() int; // Get the underlying int. + Set(int); // Set the underlying int. +} + +type intValueStruct struct { + commonValue +} + +func intCreator(typ Type, addr Addr) Value { + return &intValueStruct{ commonValue{IntKind, typ, addr} } +} + +func (v *intValueStruct) Get() int { + return *(*int)(v.addr) +} + +func (v *intValueStruct) Set(i int) { + *(*int)(v.addr) = i +} + +// -- Int8 + +// Int8Value represents an int8 value. +type Int8Value interface { + Value; + Get() int8; // Get the underlying int8. + Set(int8); // Set the underlying int8. +} + +type int8ValueStruct struct { + commonValue +} + +func int8Creator(typ Type, addr Addr) Value { + return &int8ValueStruct{ commonValue{Int8Kind, typ, addr} } +} + +func (v *int8ValueStruct) Get() int8 { + return *(*int8)(v.addr) +} + +func (v *int8ValueStruct) Set(i int8) { + *(*int8)(v.addr) = i +} + +// -- Int16 + +// Int16Value represents an int16 value. +type Int16Value interface { + Value; + Get() int16; // Get the underlying int16. + Set(int16); // Set the underlying int16. +} + +type int16ValueStruct struct { + commonValue +} + +func int16Creator(typ Type, addr Addr) Value { + return &int16ValueStruct{ commonValue{Int16Kind, typ, addr} } +} + +func (v *int16ValueStruct) Get() int16 { + return *(*int16)(v.addr) +} + +func (v *int16ValueStruct) Set(i int16) { + *(*int16)(v.addr) = i +} + +// -- Int32 + +// Int32Value represents an int32 value. +type Int32Value interface { + Value; + Get() int32; // Get the underlying int32. + Set(int32); // Set the underlying int32. +} + +type int32ValueStruct struct { + commonValue +} + +func int32Creator(typ Type, addr Addr) Value { + return &int32ValueStruct{ commonValue{Int32Kind, typ, addr} } +} + +func (v *int32ValueStruct) Get() int32 { + return *(*int32)(v.addr) +} + +func (v *int32ValueStruct) Set(i int32) { + *(*int32)(v.addr) = i +} + +// -- Int64 + +// Int64Value represents an int64 value. +type Int64Value interface { + Value; + Get() int64; // Get the underlying int64. + Set(int64); // Set the underlying int64. +} + +type int64ValueStruct struct { + commonValue +} + +func int64Creator(typ Type, addr Addr) Value { + return &int64ValueStruct{ commonValue{Int64Kind, typ, addr} } +} + +func (v *int64ValueStruct) Get() int64 { + return *(*int64)(v.addr) +} + +func (v *int64ValueStruct) Set(i int64) { + *(*int64)(v.addr) = i +} + +// -- Uint + +// UintValue represents a uint value. +type UintValue interface { + Value; + Get() uint; // Get the underlying uint. + Set(uint); // Set the underlying uint. +} + +type uintValueStruct struct { + commonValue +} + +func uintCreator(typ Type, addr Addr) Value { + return &uintValueStruct{ commonValue{UintKind, typ, addr} } +} + +func (v *uintValueStruct) Get() uint { + return *(*uint)(v.addr) +} + +func (v *uintValueStruct) Set(i uint) { + *(*uint)(v.addr) = i +} + +// -- Uint8 + +// Uint8Value represents a uint8 value. +type Uint8Value interface { + Value; + Get() uint8; // Get the underlying uint8. + Set(uint8); // Set the underlying uint8. +} + +type uint8ValueStruct struct { + commonValue +} + +func uint8Creator(typ Type, addr Addr) Value { + return &uint8ValueStruct{ commonValue{Uint8Kind, typ, addr} } +} + +func (v *uint8ValueStruct) Get() uint8 { + return *(*uint8)(v.addr) +} + +func (v *uint8ValueStruct) Set(i uint8) { + *(*uint8)(v.addr) = i +} + +// -- Uint16 + +// Uint16Value represents a uint16 value. +type Uint16Value interface { + Value; + Get() uint16; // Get the underlying uint16. + Set(uint16); // Set the underlying uint16. +} + +type uint16ValueStruct struct { + commonValue +} + +func uint16Creator(typ Type, addr Addr) Value { + return &uint16ValueStruct{ commonValue{Uint16Kind, typ, addr} } +} + +func (v *uint16ValueStruct) Get() uint16 { + return *(*uint16)(v.addr) +} + +func (v *uint16ValueStruct) Set(i uint16) { + *(*uint16)(v.addr) = i +} + +// -- Uint32 + +// Uint32Value represents a uint32 value. +type Uint32Value interface { + Value; + Get() uint32; // Get the underlying uint32. + Set(uint32); // Set the underlying uint32. +} + +type uint32ValueStruct struct { + commonValue +} + +func uint32Creator(typ Type, addr Addr) Value { + return &uint32ValueStruct{ commonValue{Uint32Kind, typ, addr} } +} + +func (v *uint32ValueStruct) Get() uint32 { + return *(*uint32)(v.addr) +} + +func (v *uint32ValueStruct) Set(i uint32) { + *(*uint32)(v.addr) = i +} + +// -- Uint64 + +// Uint64Value represents a uint64 value. +type Uint64Value interface { + Value; + Get() uint64; // Get the underlying uint64. + Set(uint64); // Set the underlying uint64. +} + +type uint64ValueStruct struct { + commonValue +} + +func uint64Creator(typ Type, addr Addr) Value { + return &uint64ValueStruct{ commonValue{Uint64Kind, typ, addr} } +} + +func (v *uint64ValueStruct) Get() uint64 { + return *(*uint64)(v.addr) +} + +func (v *uint64ValueStruct) Set(i uint64) { + *(*uint64)(v.addr) = i +} + +// -- Uintptr + +// UintptrValue represents a uintptr value. +type UintptrValue interface { + Value; + Get() uintptr; // Get the underlying uintptr. + Set(uintptr); // Set the underlying uintptr. +} + +type uintptrValueStruct struct { + commonValue +} + +func uintptrCreator(typ Type, addr Addr) Value { + return &uintptrValueStruct{ commonValue{UintptrKind, typ, addr} } +} + +func (v *uintptrValueStruct) Get() uintptr { + return *(*uintptr)(v.addr) +} + +func (v *uintptrValueStruct) Set(i uintptr) { + *(*uintptr)(v.addr) = i +} + +// -- Float + +// FloatValue represents a float value. +type FloatValue interface { + Value; + Get() float; // Get the underlying float. + Set(float); // Get the underlying float. +} + +type floatValueStruct struct { + commonValue +} + +func floatCreator(typ Type, addr Addr) Value { + return &floatValueStruct{ commonValue{FloatKind, typ, addr} } +} + +func (v *floatValueStruct) Get() float { + return *(*float)(v.addr) +} + +func (v *floatValueStruct) Set(f float) { + *(*float)(v.addr) = f +} + +// -- Float32 + +// Float32Value represents a float32 value. +type Float32Value interface { + Value; + Get() float32; // Get the underlying float32. + Set(float32); // Get the underlying float32. +} + +type float32ValueStruct struct { + commonValue +} + +func float32Creator(typ Type, addr Addr) Value { + return &float32ValueStruct{ commonValue{Float32Kind, typ, addr} } +} + +func (v *float32ValueStruct) Get() float32 { + return *(*float32)(v.addr) +} + +func (v *float32ValueStruct) Set(f float32) { + *(*float32)(v.addr) = f +} + +// -- Float64 + +// Float64Value represents a float64 value. +type Float64Value interface { + Value; + Get() float64; // Get the underlying float64. + Set(float64); // Get the underlying float64. +} + +type float64ValueStruct struct { + commonValue +} + +func float64Creator(typ Type, addr Addr) Value { + return &float64ValueStruct{ commonValue{Float64Kind, typ, addr} } +} + +func (v *float64ValueStruct) Get() float64 { + return *(*float64)(v.addr) +} + +func (v *float64ValueStruct) Set(f float64) { + *(*float64)(v.addr) = f +} + +// -- String + +// StringValue represents a string value. +type StringValue interface { + Value; + Get() string; // Get the underlying string value. + Set(string); // Set the underlying string value. +} + +type stringValueStruct struct { + commonValue +} + +func stringCreator(typ Type, addr Addr) Value { + return &stringValueStruct{ commonValue{StringKind, typ, addr} } +} + +func (v *stringValueStruct) Get() string { + return *(*string)(v.addr) +} + +func (v *stringValueStruct) Set(s string) { + *(*string)(v.addr) = s +} + +// -- Bool + +// BoolValue represents a bool value. +type BoolValue interface { + Value; + Get() bool; // Get the underlying bool value. + Set(bool); // Set the underlying bool value. +} + +type boolValueStruct struct { + commonValue +} + +func boolCreator(typ Type, addr Addr) Value { + return &boolValueStruct{ commonValue{BoolKind, typ, addr} } +} + +func (v *boolValueStruct) Get() bool { + return *(*bool)(v.addr) +} + +func (v *boolValueStruct) Set(b bool) { + *(*bool)(v.addr) = b +} + +// -- Pointer + +// PtrValue represents a pointer value. +type PtrValue interface { + Value; + Sub() Value; // The Value pointed to. + Get() Addr; // Get the address stored in the pointer. + SetSub(Value); // Set the the pointed-to Value. + IsNil() bool; +} + +type ptrValueStruct struct { + commonValue +} + +func (v *ptrValueStruct) Get() Addr { + return *(*Addr)(v.addr) +} + +func (v *ptrValueStruct) Sub() Value { + return newValueAddr(v.typ.(PtrType).Sub(), v.Get()); +} + +func (v *ptrValueStruct) SetSub(subv Value) { + a := v.typ.(PtrType).Sub(); + b := subv.Type(); + if !equalType(a, b) { + panicln("reflect: incompatible types in PtrValue.SetSub:", + a.String(), b.String()); + } + *(*Addr)(v.addr) = subv.Addr(); +} + +func (v *ptrValueStruct) IsNil() bool { + return uintptr(*(*Addr)(v.addr)) == 0 +} + +func ptrCreator(typ Type, addr Addr) Value { + return &ptrValueStruct{ commonValue{PtrKind, typ, addr} }; +} + +// -- Array +// Slices and arrays are represented by the same interface. + +// ArrayValue represents an array or slice value. +type ArrayValue interface { + Value; + IsSlice() bool; // Is this a slice (true) or array (false)? + Len() int; // The length of the array/slice. + Cap() int; // The capacity of the array/slice (==Len() for arrays). + Elem(i int) Value; // The Value of the i'th element. + SetLen(len int); // Set the length; slice only. + Set(src ArrayValue); // Set the underlying Value; slice only for src and dest both. + CopyFrom(src ArrayValue, n int); // Copy the elements from src; lengths must match. + IsNil() bool; +} + +func copyArray(dst ArrayValue, src ArrayValue, n int); + +/* + Run-time representation of slices looks like this: + struct Slice { + byte* array; // actual data + uint32 nel; // number of elements + uint32 cap; + }; +*/ +type runtimeSlice struct { + data Addr; + len uint32; + cap uint32; +} + +type sliceValueStruct struct { + commonValue; + elemtype Type; + elemsize int; + slice *runtimeSlice; +} + +func (v *sliceValueStruct) IsSlice() bool { + return true +} + +func (v *sliceValueStruct) Len() int { + return int(v.slice.len); +} + +func (v *sliceValueStruct) Cap() int { + return int(v.slice.cap); +} + +func (v *sliceValueStruct) SetLen(len int) { + if len > v.Cap() { + panicln("reflect: sliceValueStruct.SetLen", len, v.Cap()); + } + v.slice.len = uint32(len); +} + +func (v *sliceValueStruct) Set(src ArrayValue) { + if !src.IsSlice() { + panic("can't set slice from array"); + } + s := src.(*sliceValueStruct); + if !equalType(v.typ, s.typ) { + panicln("incompatible types in ArrayValue.Set()"); + } + *v.slice = *s.slice; +} + +func (v *sliceValueStruct) Elem(i int) Value { + data_uint := uintptr(v.slice.data) + uintptr(i * v.elemsize); + return newValueAddr(v.elemtype, Addr(data_uint)); +} + +func (v *sliceValueStruct) CopyFrom(src ArrayValue, n int) { + copyArray(v, src, n); +} + +func (v *sliceValueStruct) IsNil() bool { + return uintptr(v.slice.data) == 0 +} + +type arrayValueStruct struct { + commonValue; + elemtype Type; + elemsize int; + len int; +} + +func (v *arrayValueStruct) IsSlice() bool { + return false +} + +func (v *arrayValueStruct) Len() int { + return v.len +} + +func (v *arrayValueStruct) Cap() int { + return v.len +} + +func (v *arrayValueStruct) SetLen(len int) { + panicln("can't set len of array"); +} + +func (v *arrayValueStruct) Set(src ArrayValue) { + panicln("can't set array"); +} + +func (v *arrayValueStruct) Elem(i int) Value { + data_uint := uintptr(v.addr) + uintptr(i * v.elemsize); + return newValueAddr(v.elemtype, Addr(data_uint)); +} + +func (v *arrayValueStruct) CopyFrom(src ArrayValue, n int) { + copyArray(v, src, n); +} + +func (v *arrayValueStruct) IsNil() bool { + return false +} + +func arrayCreator(typ Type, addr Addr) Value { + arraytype := typ.(ArrayType); + if arraytype.IsSlice() { + v := new(sliceValueStruct); + v.kind = ArrayKind; + v.addr = addr; + v.typ = typ; + v.elemtype = arraytype.Elem(); + v.elemsize = v.elemtype.Size(); + v.slice = (*runtimeSlice)(addr); + return v; + } + v := new(arrayValueStruct); + v.kind = ArrayKind; + v.addr = addr; + v.typ = typ; + v.elemtype = arraytype.Elem(); + v.elemsize = v.elemtype.Size(); + v.len = arraytype.Len(); + return v; +} + +// -- Map TODO: finish and test + +// MapValue represents a map value. +// Its implementation is incomplete. +type MapValue interface { + Value; + Len() int; // The number of elements; currently always returns 0. + Elem(key Value) Value; // The value indexed by key; unimplemented. + IsNil() bool; +} + +type mapValueStruct struct { + commonValue +} + +func mapCreator(typ Type, addr Addr) Value { + return &mapValueStruct{ commonValue{MapKind, typ, addr} } +} + +func (v *mapValueStruct) Len() int { + return 0 // TODO: probably want this to be dynamic +} + +func (v *mapValueStruct) IsNil() bool { + return false // TODO: implement this properly +} + +func (v *mapValueStruct) Elem(key Value) Value { + panic("map value element"); + return nil +} + +// -- Chan + +// ChanValue represents a chan value. +// Its implementation is incomplete. +type ChanValue interface { + Value; + IsNil() bool; +} + +type chanValueStruct struct { + commonValue +} + +func (v *chanValueStruct) IsNil() bool { + return false // TODO: implement this properly +} + +func chanCreator(typ Type, addr Addr) Value { + return &chanValueStruct{ commonValue{ChanKind, typ, addr} } +} + +// -- Struct + +// StructValue represents a struct value. +type StructValue interface { + Value; + Len() int; // The number of fields. + Field(i int) Value; // The Value of field i. +} + +type structValueStruct struct { + commonValue; + field []Value; +} + +func (v *structValueStruct) Len() int { + return len(v.field) +} + +func (v *structValueStruct) Field(i int) Value { + return v.field[i] +} + +func structCreator(typ Type, addr Addr) Value { + t := typ.(StructType); + nfield := t.Len(); + v := &structValueStruct{ commonValue{StructKind, typ, addr}, make([]Value, nfield) }; + for i := 0; i < nfield; i++ { + name, ftype, str, offset := t.Field(i); + addr_uint := uintptr(addr) + uintptr(offset); + v.field[i] = newValueAddr(ftype, Addr(addr_uint)); + } + v.typ = typ; + return v; +} + +// -- Interface + +// InterfaceValue represents an interface value. +type InterfaceValue interface { + Value; + Get() interface {}; // Get the underlying interface{} value. + Value() Value; + IsNil() bool; +} + +type interfaceValueStruct struct { + commonValue +} + +func (v *interfaceValueStruct) Get() interface{} { + // There are two different representations of interface values, + // one if the interface type has methods and one if it doesn't. + // These two representations require different expressions + // to extract correctly. + if v.Type().(InterfaceType).Len() == 0 { + // Extract as interface value without methods. + return *(*interface{})(v.addr) + } + // Extract from v.addr as interface value with methods. + return *(*interface{ m() })(v.addr) +} + +func (v *interfaceValueStruct) Interface() interface{} { + return v.Get(); +} + +func (v *interfaceValueStruct) Value() Value { + i := v.Get(); + if i == nil { + return nil; + } + return NewValue(i); +} + +func (v *interfaceValueStruct) IsNil() bool { + return *(*interface{})(v.addr) == nil +} + +func interfaceCreator(typ Type, addr Addr) Value { + return &interfaceValueStruct{ commonValue{InterfaceKind, typ, addr} } +} + +// -- Func + + +// FuncValue represents a func value. +// Its implementation is incomplete. +type FuncValue interface { + Value; + Get() Addr; // The address of the function. + IsNil() bool; +} + +type funcValueStruct struct { + commonValue +} + +func (v *funcValueStruct) Get() Addr { + return *(*Addr)(v.addr) +} + +func (v *funcValueStruct) IsNil() bool { + return *(*Addr)(v.addr) == nil +} + +func funcCreator(typ Type, addr Addr) Value { + return &funcValueStruct{ commonValue{FuncKind, typ, addr} } +} + +var creator = map[int] creatorFn { + MissingKind : missingCreator, + IntKind : intCreator, + Int8Kind : int8Creator, + Int16Kind : int16Creator, + Int32Kind : int32Creator, + Int64Kind : int64Creator, + UintKind : uintCreator, + Uint8Kind : uint8Creator, + Uint16Kind : uint16Creator, + Uint32Kind : uint32Creator, + Uint64Kind : uint64Creator, + UintptrKind : uintptrCreator, + FloatKind : floatCreator, + Float32Kind : float32Creator, + Float64Kind : float64Creator, + StringKind : stringCreator, + BoolKind : boolCreator, + PtrKind : ptrCreator, + ArrayKind : arrayCreator, + MapKind : mapCreator, + ChanKind : chanCreator, + StructKind : structCreator, + InterfaceKind : interfaceCreator, + FuncKind : funcCreator, +} + +var typecache = make(map[string] Type); + +func newValueAddr(typ Type, addr Addr) Value { + c, ok := creator[typ.Kind()]; + if !ok { + panicln("no creator for type" , typ.String()); + } + return c(typ, addr); +} + +// NewZeroValue creates a new, zero-initialized Value for the specified Type. +func NewZeroValue(typ Type) Value { + size := typ.Size(); + if size == 0 { + size = 1; + } + data := make([]uint8, size); + return newValueAddr(typ, Addr(&data[0])); +} + +// NewSliceValue creates a new, zero-initialized slice value (ArrayValue) for the specified +// slice type (ArrayType), length, and capacity. +func NewSliceValue(typ ArrayType, len, cap int) ArrayValue { + if !typ.IsSlice() { + return nil + } + + array := new(runtimeSlice); + size := typ.Elem().Size() * cap; + if size == 0 { + size = 1; + } + data := make([]uint8, size); + array.data = Addr(&data[0]); + array.len = uint32(len); + array.cap = uint32(cap); + + return newValueAddr(typ, Addr(array)).(ArrayValue); +} + +// Works on both slices and arrays +func copyArray(dst ArrayValue, src ArrayValue, n int) { + if n == 0 { + return + } + dt := dst.Type().(ArrayType).Elem(); + st := src.Type().(ArrayType).Elem(); + if !equalType(dt, st) { + panicln("reflect: incompatible types in CopyArray:", + dt.String(), st.String()); + } + if n < 0 || n > dst.Len() || n > src.Len() { + panicln("reflect: CopyArray: invalid count", n); + } + dstp := uintptr(dst.Elem(0).Addr()); + srcp := uintptr(src.Elem(0).Addr()); + end := uintptr(n)*uintptr(dt.Size()); + if end % 8 == 0 { + for i := uintptr(0); i < end; i += 8{ + di := Addr(dstp + i); + si := Addr(srcp + i); + *(*uint64)(di) = *(*uint64)(si); + } + } else { + for i := uintptr(0); i < end; i++ { + di := Addr(dstp + i); + si := Addr(srcp + i); + *(*byte)(di) = *(*byte)(si); + } + } +} + +// NewValue creates a new Value from the interface{} object provided. +func NewValue(e interface {}) Value { + value, typestring, indir := unsafe.Reflect(e); + typ, ok := typecache[typestring]; + if !ok { + typ = ParseTypeString("", typestring); + if typ.Kind() == MissingKind { + // This can not happen: unsafe.Reflect should only + // ever tell us the names of types that exist. + // Of course it does happen, and when it does + // it is more helpful to catch it in action here than + // to see $missing$ in a later print. + panicln("missing type for", typestring); + } + typecache[typestring] = typ; + } + var ap Addr; + if indir { + // Content of interface is large and didn't + // fit, so it's a pointer to the actual content. + // We have an address, but we need to + // make a copy to avoid letting the caller + // edit the content inside the interface. + n := uintptr(typ.Size()); + data := make([]byte, n); + p1 := uintptr(Addr(&data[0])); + p2 := uintptr(value); + for i := uintptr(0); i < n; i++ { + *(*byte)(Addr(p1+i)) = *(*byte)(Addr(p2+i)); + } + ap = Addr(&data[0]); + } else { + // Content of interface is small and stored + // inside the interface. Make a copy so we + // can take its address. + x := new(uint64); + *x = value; + ap = Addr(x); + } + return newValueAddr(typ, ap); +} + +// Indirect indirects one level through a value, if it is a pointer. +// If not a pointer, the value is returned unchanged. +// Useful when walking arbitrary data structures. +func Indirect(v Value) Value { + if v.Kind() == PtrKind { + p := v.(PtrValue); + if p.Get() == nil { + return nil + } + v = p.Sub() + } + return v +} diff --git a/src/pkg/regexp/Makefile b/src/pkg/regexp/Makefile new file mode 100644 index 000000000..0312d510e --- /dev/null +++ b/src/pkg/regexp/Makefile @@ -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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D= + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + regexp.$O\ + + +phases: a1 +_obj$D/regexp.a: phases + +a1: $(O1) + $(AR) grc _obj$D/regexp.a regexp.$O + rm -f $(O1) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/regexp.a + +$(O1): newpkg +$(O2): a1 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/regexp.a + +packages: _obj$D/regexp.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/regexp.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/regexp.a diff --git a/src/pkg/regexp/all_test.go b/src/pkg/regexp/all_test.go new file mode 100644 index 000000000..a9f275893 --- /dev/null +++ b/src/pkg/regexp/all_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 regexp + +import ( + "os"; + "regexp"; + "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]`, +} + +// TODO: nice to do this with a map +type stringError struct { + re string; + err os.Error; +} +var bad_re = []stringError{ + stringError{ `*`, regexp.ErrBareClosure }, + stringError{ `(abc`, regexp.ErrUnmatchedLpar }, + stringError{ `abc)`, regexp.ErrUnmatchedRpar }, + stringError{ `x[a-z`, regexp.ErrUnmatchedLbkt }, + stringError{ `abc]`, regexp.ErrUnmatchedRbkt }, + stringError{ `[z-a]`, regexp.ErrBadRange }, + stringError{ `abc\`, regexp.ErrExtraneousBackslash }, + stringError{ `a**`, regexp.ErrBadClosure }, + stringError{ `a*+`, regexp.ErrBadClosure }, + stringError{ `a??`, regexp.ErrBadClosure }, + stringError{ `*`, regexp.ErrBareClosure }, + stringError{ `\x`, regexp.ErrBadBackslash }, +} + +type vec []int; + +type tester struct { + re string; + text string; + match vec; +} + +var matches = []tester { + tester{ ``, "", vec{0,0} }, + tester{ `a`, "a", vec{0,1} }, + tester{ `x`, "y", vec{} }, + tester{ `b`, "abc", vec{1,2} }, + tester{ `.`, "a", vec{0,1} }, + tester{ `.*`, "abcdef", vec{0,6} }, + tester{ `^abcd$`, "abcd", vec{0,4} }, + tester{ `^bcd'`, "abcdef", vec{} }, + tester{ `^abcd$`, "abcde", vec{} }, + tester{ `a+`, "baaab", vec{1,4} }, + tester{ `a*`, "baaab", vec{0,0} }, + tester{ `[a-z]+`, "abcd", vec{0,4} }, + tester{ `[^a-z]+`, "ab1234cd", vec{2,6} }, + tester{ `[a\-\]z]+`, "az]-bcz", vec{0,4} }, + tester{ `[日本語]+`, "日本語日本語", vec{0,18} }, + tester{ `()`, "", vec{0,0, 0,0} }, + tester{ `(a)`, "a", vec{0,1, 0,1} }, + tester{ `(.)(.)`, "日a", vec{0,4, 0,3, 3,4} }, + tester{ `(.*)`, "", vec{0,0, 0,0} }, + tester{ `(.*)`, "abcd", vec{0,4, 0,4} }, + tester{ `(..)(..)`, "abcd", vec{0,4, 0,2, 2,4} }, + tester{ `(([^xyz]*)(d))`, "abcd", vec{0,4, 0,4, 0,3, 3,4} }, + tester{ `((a|b|c)*(d))`, "abcd", vec{0,4, 0,4, 2,3, 3,4} }, + tester{ `(((a|b|c)*)(d))`, "abcd", vec{0,4, 0,4, 0,3, 2,3, 3,4} }, + tester{ `a*(|(b))c*`, "aacc", vec{0,4, 2,2, -1,-1} }, +} + +func compileTest(t *testing.T, expr string, error os.Error) *regexp.Regexp { + re, err := regexp.Compile(expr); + if err != error { + t.Error("compiling `", expr, "`; unexpected error: ", err.String()); + } + return re +} + +func printVec(t *testing.T, m []int) { + l := len(m); + if l == 0 { + t.Log("\t"); + } else { + for i := 0; i < l; i = i+2 { + t.Log("\t", m[i], ",", m[i+1]) + } + } +} + +func printStrings(t *testing.T, m []string) { + l := len(m); + if l == 0 { + t.Log("\t"); + } else { + for i := 0; i < l; i = i+2 { + t.Logf("\t%q", m[i]) + } + } +} + +func equal(m1, m2 []int) bool { + l := len(m1); + if l != len(m2) { + return false + } + for i := 0; i < l; i++ { + if m1[i] != m2[i] { + return false + } + } + return true +} + +func equalStrings(m1, m2 []string) bool { + l := len(m1); + if l != len(m2) { + return false + } + for i := 0; i < l; i++ { + if m1[i] != m2[i] { + return false + } + } + return true +} + +func executeTest(t *testing.T, expr string, str string, match []int) { + re := compileTest(t, expr, nil); + if re == nil { + return + } + m := re.Execute(str); + if !equal(m, match) { + t.Error("Execute failure on `", expr, "` matching `", str, "`:"); + printVec(t, m); + t.Log("should be:"); + printVec(t, match); + } +} + +func TestGoodCompile(t *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 TestExecute(t *testing.T) { + for i := 0; i < len(matches); i++ { + test := &matches[i]; + executeTest(t, test.re, test.text, test.match) + } +} + +func matchTest(t *testing.T, expr string, str string, match []int) { + re := compileTest(t, expr, nil); + if re == nil { + return + } + m := re.Match(str); + if m != (len(match) > 0) { + t.Error("Match failure on `", expr, "` matching `", str, "`:", m, "should be", len(match) > 0); + } +} + +func TestMatch(t *testing.T) { + for i := 0; i < len(matches); i++ { + test := &matches[i]; + matchTest(t, test.re, test.text, test.match) + } +} + +func matchStringsTest(t *testing.T, expr string, str string, match []int) { + re := compileTest(t, expr, nil); + if re == nil { + return + } + strs := make([]string, len(match)/2); + for i := 0; i < len(match); i++ { + strs[i/2] = str[match[i] : match[i+1]] + } + m := re.MatchStrings(str); + if !equalStrings(m, strs) { + t.Error("MatchStrings failure on `", expr, "` matching `", str, "`:"); + printStrings(t, m); + t.Log("should be:"); + printStrings(t, strs); + } +} + +func TestMatchStrings(t *testing.T) { + for i := 0; i < len(matches); i++ { + test := &matches[i]; + matchTest(t, test.re, test.text, test.match) + } +} + +func matchFunctionTest(t *testing.T, expr string, str string, match []int) { + m, err := Match(expr, str); + if err == nil { + return + } + if m != (len(match) > 0) { + t.Error("function Match failure on `", expr, "` matching `", str, "`:", m, "should be", len(match) > 0); + } +} + +func TestMatchFunction(t *testing.T) { + for i := 0; i < len(matches); i++ { + test := &matches[i]; + matchFunctionTest(t, test.re, test.text, test.match) + } +} diff --git a/src/pkg/regexp/regexp.go b/src/pkg/regexp/regexp.go new file mode 100644 index 000000000..b79800dd9 --- /dev/null +++ b/src/pkg/regexp/regexp.go @@ -0,0 +1,764 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package regexp implements a simple regular expression library. +// +// The syntax of the regular expressions accepted is: +// +// regexp: +// concatenation { '|' concatenation } +// concatenation: +// { closure } +// closure: +// term [ '*' | '+' | '?' ] +// term: +// '^' +// '$' +// '.' +// character +// '[' [ '^' ] character-ranges ']' +// '(' regexp ')' +// +package regexp + +import ( + "container/vector"; + "os"; + "runtime"; + "utf8"; +) + +var debug = false; + +// Error codes returned by failures to parse an expression. +var ( + ErrInternal = os.NewError("internal error"); + ErrUnmatchedLpar = os.NewError("unmatched '('"); + ErrUnmatchedRpar = os.NewError("unmatched ')'"); + ErrUnmatchedLbkt = os.NewError("unmatched '['"); + ErrUnmatchedRbkt = os.NewError("unmatched ']'"); + ErrBadRange = os.NewError("bad range in character class"); + ErrExtraneousBackslash = os.NewError("extraneous backslash"); + ErrBadClosure = os.NewError("repeated closure (**, ++, etc.)"); + ErrBareClosure = os.NewError("closure applies to nothing"); + ErrBadBackslash = os.NewError("illegal backslash escape"); +) + +// An instruction executed by the NFA +type instr interface { + kind() int; // the type of this instruction: _CHAR, _ANY, etc. + next() instr; // the instruction to execute after this one + setNext(i instr); + index() int; + setIndex(i int); + print(); +} + +// Fields and methods common to all instructions +type common struct { + _next instr; + _index int; +} + +func (c *common) next() instr { return c._next } +func (c *common) setNext(i instr) { c._next = i } +func (c *common) index() int { return c._index } +func (c *common) setIndex(i int) { c._index = i } + +// The representation of a compiled regular expression. +// The public interface is entirely through methods. +type Regexp struct { + expr string; // the original expression + ch chan<- *Regexp; // reply channel when we're done + error os.Error; // compile- or run-time error; nil if OK + inst *vector.Vector; + start instr; + nbra int; // number of brackets in expression, for subexpressions +} + +const ( + _START // beginning of program + = iota; + _END; // end of program: success + _BOT; // '^' beginning of text + _EOT; // '$' end of text + _CHAR; // 'a' regular character + _CHARCLASS; // [a-z] character class + _ANY; // '.' any character + _BRA; // '(' parenthesized expression + _EBRA; // ')'; end of '(' parenthesized expression + _ALT; // '|' alternation + _NOP; // do nothing; makes it easy to link without patching +) + +// --- START start of program +type _Start struct { + common +} + +func (start *_Start) kind() int { return _START } +func (start *_Start) print() { print("start") } + +// --- END end of program +type _End struct { + common +} + +func (end *_End) kind() int { return _END } +func (end *_End) print() { print("end") } + +// --- BOT beginning of text +type _Bot struct { + common +} + +func (bot *_Bot) kind() int { return _BOT } +func (bot *_Bot) print() { print("bot") } + +// --- EOT end of text +type _Eot struct { + common +} + +func (eot *_Eot) kind() int { return _EOT } +func (eot *_Eot) print() { print("eot") } + +// --- CHAR a regular character +type _Char struct { + common; + char int; +} + +func (char *_Char) kind() int { return _CHAR } +func (char *_Char) print() { print("char ", string(char.char)) } + +func newChar(char int) *_Char { + c := new(_Char); + c.char = char; + return c; +} + +// --- CHARCLASS [a-z] + +type _CharClass struct { + common; + char int; + negate bool; // is character class negated? ([^a-z]) + // vector of int, stored pairwise: [a-z] is (a,z); x is (x,x): + ranges *vector.IntVector; +} + +func (cclass *_CharClass) kind() int { return _CHARCLASS } + +func (cclass *_CharClass) print() { + print("charclass"); + if cclass.negate { + print(" (negated)"); + } + for i := 0; i < cclass.ranges.Len(); i += 2 { + l := cclass.ranges.At(i); + r := cclass.ranges.At(i+1); + 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.Push(a); + cclass.ranges.Push(b); +} + +func (cclass *_CharClass) matches(c int) bool { + for i := 0; i < cclass.ranges.Len(); i = i+2 { + min := cclass.ranges.At(i); + max := cclass.ranges.At(i+1); + if min <= c && c <= max { + return !cclass.negate + } + } + return cclass.negate +} + +func newCharClass() *_CharClass { + c := new(_CharClass); + c.ranges = vector.NewIntVector(0); + return c; +} + +// --- ANY any character +type _Any struct { + common +} + +func (any *_Any) kind() int { return _ANY } +func (any *_Any) print() { print("any") } + +// --- BRA parenthesized expression +type _Bra struct { + common; + n int; // subexpression number +} + +func (bra *_Bra) kind() int { return _BRA } +func (bra *_Bra) print() { print("bra", bra.n); } + +// --- EBRA end of parenthesized expression +type _Ebra struct { + common; + n int; // subexpression number +} + +func (ebra *_Ebra) kind() int { return _EBRA } +func (ebra *_Ebra) print() { print("ebra ", ebra.n); } + +// --- ALT alternation +type _Alt struct { + common; + left instr; // other branch +} + +func (alt *_Alt) kind() int { return _ALT } +func (alt *_Alt) print() { print("alt(", alt.left.index(), ")"); } + +// --- NOP no operation +type _Nop struct { + common +} + +func (nop *_Nop) kind() int { return _NOP } +func (nop *_Nop) print() { print("nop") } + +// report error and exit compiling/executing goroutine +func (re *Regexp) setError(err os.Error) { + re.error = err; + re.ch <- re; + runtime.Goexit(); +} + +func (re *Regexp) add(i instr) instr { + i.setIndex(re.inst.Len()); + re.inst.Push(i); + return i; +} + +type parser struct { + re *Regexp; + nlpar int; // number of unclosed lpars + pos int; + ch int; +} + +const endOfFile = -1 + +func (p *parser) c() int { + return p.ch; +} + +func (p *parser) nextc() int { + if p.pos >= len(p.re.expr) { + p.ch = endOfFile + } else { + c, w := utf8.DecodeRuneInString(p.re.expr[p.pos:len(p.re.expr)]); + 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 (p *parser) regexp() (start, end instr) + +var iNULL instr + +func special(c int) bool { + s := `\.+*?()|[]`; + for i := 0; i < len(s); i++ { + if c == int(s[i]) { + return true + } + } + return false +} + +func specialcclass(c int) bool { + s := `\-[]`; + for i := 0; i < len(s); i++ { + if c == int(s[i]) { + return true + } + } + return false +} + +func (p *parser) charClass() instr { + cc := newCharClass(); + p.re.add(cc); + if p.c() == '^' { + cc.negate = true; + p.nextc(); + } + left := -1; + for { + switch c := p.c(); c { + case ']', endOfFile: + if left >= 0 { + p.re.setError(ErrBadRange); + } + return cc; + case '-': // do this before backslash processing + p.re.setError(ErrBadRange); + case '\\': + c = p.nextc(); + switch { + case c == endOfFile: + p.re.setError(ErrExtraneousBackslash); + case c == 'n': + c = '\n'; + case specialcclass(c): + // c is as delivered + default: + p.re.setError(ErrBadBackslash); + } + fallthrough; + default: + p.nextc(); + switch { + case left < 0: // first of pair + if p.c() == '-' { // range + p.nextc(); + left = c; + } else { // single char + cc.addRange(c, c); + } + case left <= c: // second of pair + cc.addRange(left, c); + left = -1; + default: + p.re.setError(ErrBadRange); + } + } + } + return iNULL +} + +func (p *parser) term() (start, end instr) { + switch c := p.c(); c { + case '|', endOfFile: + return iNULL, iNULL; + case '*', '+': + p.re.setError(ErrBareClosure); + case ')': + if p.nlpar == 0 { + p.re.setError(ErrUnmatchedRpar); + } + return iNULL, iNULL; + case ']': + p.re.setError(ErrUnmatchedRbkt); + case '^': + p.nextc(); + start = p.re.add(new(_Bot)); + return start, start; + case '$': + p.nextc(); + start = p.re.add(new(_Eot)); + return start, start; + case '.': + p.nextc(); + start = p.re.add(new(_Any)); + return start, start; + case '[': + p.nextc(); + start = p.charClass(); + if p.c() != ']' { + p.re.setError(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.re.setError(ErrUnmatchedLpar); + } + p.nlpar--; + p.nextc(); + bra := new(_Bra); + p.re.add(bra); + ebra := new(_Ebra); + p.re.add(ebra); + bra.n = nbra; + ebra.n = nbra; + if start == iNULL { + if end == iNULL { + p.re.setError(ErrInternal) + } + start = ebra + } else { + end.setNext(ebra); + } + bra.setNext(start); + return bra, ebra; + case '\\': + c = p.nextc(); + switch { + case c == endOfFile: + p.re.setError(ErrExtraneousBackslash); + case c == 'n': + c = '\n'; + case special(c): + // c is as delivered + default: + p.re.setError(ErrBadBackslash); + } + fallthrough; + default: + p.nextc(); + start = newChar(c); + p.re.add(start); + return start, start + } + panic("unreachable"); +} + +func (p *parser) closure() (start, end instr) { + start, end = p.term(); + if start == iNULL { + return + } + switch p.c() { + case '*': + // (start,end)*: + alt := new(_Alt); + p.re.add(alt); + end.setNext(alt); // after end, do alt + alt.left = start; // alternate brach: return to start + start = alt; // alt becomes new (start, end) + end = alt; + case '+': + // (start,end)+: + alt := new(_Alt); + p.re.add(alt); + end.setNext(alt); // after end, do alt + alt.left = start; // alternate brach: return to start + end = alt; // start is unchanged; end is alt + case '?': + // (start,end)?: + alt := new(_Alt); + p.re.add(alt); + nop := new(_Nop); + p.re.add(nop); + alt.left = start; // alternate branch is start + alt.setNext(nop); // follow on to nop + end.setNext(nop); // after end, go to nop + start = alt; // start is now alt + end = nop; // end is nop pointed to by both branches + default: + return + } + switch p.nextc() { + case '*', '+', '?': + p.re.setError(ErrBadClosure); + } + return +} + +func (p *parser) concatenation() (start, end instr) { + start, end = iNULL, iNULL; + for { + nstart, nend := p.closure(); + switch { + case nstart == iNULL: // end of this concatenation + if start == iNULL { // this is the empty string + nop := p.re.add(new(_Nop)); + return nop, nop; + } + return; + case start == iNULL: // this is first element of concatenation + start, end = nstart, nend; + default: + end.setNext(nstart); + end = nend; + } + } + panic("unreachable"); +} + +func (p *parser) regexp() (start, end instr) { + start, end = p.concatenation(); + for { + switch p.c() { + default: + return; + case '|': + p.nextc(); + nstart, nend := p.concatenation(); + alt := new(_Alt); + p.re.add(alt); + alt.left = start; + alt.setNext(nstart); + nop := new(_Nop); + p.re.add(nop); + end.setNext(nop); + nend.setNext(nop); + start, end = alt, nop; + } + } + panic("unreachable"); +} + +func unNop(i instr) instr { + for i.kind() == _NOP { + i = i.next() + } + return i +} + +func (re *Regexp) eliminateNops() { + for i := 0; i < re.inst.Len(); i++ { + inst := re.inst.At(i).(instr); + if inst.kind() == _END { + continue + } + inst.setNext(unNop(inst.next())); + if inst.kind() == _ALT { + alt := inst.(*_Alt); + alt.left = unNop(alt.left); + } + } +} + +func (re *Regexp) dump() { + for i := 0; i < re.inst.Len(); i++ { + inst := re.inst.At(i).(instr); + print(inst.index(), ": "); + inst.print(); + if inst.kind() != _END { + print(" -> ", inst.next().index()) + } + print("\n"); + } +} + +func (re *Regexp) doParse() { + p := newParser(re); + start := new(_Start); + re.add(start); + s, e := p.regexp(); + start.setNext(s); + re.start = start; + e.setNext(re.add(new(_End))); + + if debug { + re.dump(); + println(); + } + + re.eliminateNops(); + + if debug { + re.dump(); + println(); + } +} + + +func compiler(str string, ch chan *Regexp) { + re := new(Regexp); + re.expr = str; + re.inst = vector.New(0); + re.ch = ch; + re.doParse(); + ch <- re; +} + +// 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) { + // Compile in a separate goroutine and wait for the result. + ch := make(chan *Regexp); + go compiler(str, ch); + re := <-ch; + return re, re.error +} + +type state struct { + inst instr; // next instruction to execute + match []int; // pairs of bracketing submatches. 0th is start,end +} + +// Append new state to to-do list. Leftmost-longest wins so avoid +// adding a state that's already active. +func addState(s []state, inst instr, match []int) []state { + index := inst.index(); + l := len(s); + pos := match[0]; + // TODO: Once the state is a vector and we can do insert, have inputs always + // go in order correctly and this "earlier" test is never necessary, + for i := 0; i < l; i++ { + if s[i].inst.index() == index && // same instruction + s[i].match[0] < pos { // earlier match already going; lefmost wins + return s + } + } + if l == cap(s) { + s1 := make([]state, 2*l)[0:l]; + for i := 0; i < l; i++ { + s1[i] = s[i]; + } + s = s1; + } + s = s[0:l+1]; + s[l].inst = inst; + s[l].match = match; + return s; +} + +func (re *Regexp) doExecute(str string, pos int) []int { + var s [2][]state; // TODO: use a vector when state values (not ptrs) can be vector elements + s[0] = make([]state, 10)[0:0]; + s[1] = make([]state, 10)[0:0]; + in, out := 0, 1; + var final state; + found := false; + for pos <= len(str) { + if !found { + // prime the pump if we haven't seen a match yet + match := make([]int, 2*(re.nbra+1)); + for i := 0; i < len(match); i++ { + match[i] = -1; // no match seen; catches cases like "a(b)?c" on "ac" + } + match[0] = pos; + s[out] = addState(s[out], re.start.next(), match); + } + in, out = out, in; // old out state is new in state + s[out] = s[out][0:0]; // clear out state + if len(s[in]) == 0 { + // machine has completed + break; + } + charwidth := 1; + c := endOfFile; + if pos < len(str) { + c, charwidth = utf8.DecodeRuneInString(str[pos:len(str)]); + } + for i := 0; i < len(s[in]); i++ { + st := s[in][i]; + switch s[in][i].inst.kind() { + case _BOT: + if pos == 0 { + s[in] = addState(s[in], st.inst.next(), st.match) + } + case _EOT: + if pos == len(str) { + s[in] = addState(s[in], st.inst.next(), st.match) + } + case _CHAR: + if c == st.inst.(*_Char).char { + s[out] = addState(s[out], st.inst.next(), st.match) + } + case _CHARCLASS: + if st.inst.(*_CharClass).matches(c) { + s[out] = addState(s[out], st.inst.next(), st.match) + } + case _ANY: + if c != endOfFile { + s[out] = addState(s[out], st.inst.next(), st.match) + } + case _BRA: + n := st.inst.(*_Bra).n; + st.match[2*n] = pos; + s[in] = addState(s[in], st.inst.next(), st.match); + case _EBRA: + n := st.inst.(*_Ebra).n; + st.match[2*n+1] = pos; + s[in] = addState(s[in], st.inst.next(), st.match); + case _ALT: + s[in] = addState(s[in], st.inst.(*_Alt).left, st.match); + // give other branch a copy of this match vector + s1 := make([]int, 2*(re.nbra+1)); + for i := 0; i < len(s1); i++ { + s1[i] = st.match[i] + } + s[in] = addState(s[in], st.inst.next(), s1); + case _END: + // choose leftmost longest + if !found || // first + st.match[0] < final.match[0] || // leftmost + (st.match[0] == final.match[0] && pos > final.match[1]) { // longest + final = st; + final.match[1] = pos; + } + found = true; + default: + st.inst.print(); + panic("unknown instruction in execute"); + } + } + pos += charwidth; + } + return final.match; +} + + +// Execute matches the Regexp against the string s. +// The return value is an array of integers, in pairs, identifying the positions of +// substrings matched by the expression. +// s[a[0]:a[1]] is the substring matched by the entire expression. +// s[a[2*i]:a[2*i+1]] for i > 0 is the substring matched by the ith parenthesized subexpression. +// A negative value means the subexpression did not match any element of the string. +// An empty array means "no match". +func (re *Regexp) Execute(s string) (a []int) { + return re.doExecute(s, 0) +} + + +// Match returns whether the Regexp matches the string s. +// The return value is a boolean: true for match, false for no match. +func (re *Regexp) Match(s string) bool { + return len(re.doExecute(s, 0)) > 0 +} + + +// MatchStrings matches the Regexp against the string s. +// The return value is an array of strings matched by the expression. +// a[0] is the substring matched by the entire expression. +// a[i] for i > 0 is the substring matched by the ith parenthesized subexpression. +// An empty array means ``no match''. +func (re *Regexp) MatchStrings(s string) (a []string) { + r := re.doExecute(s, 0); + if r == nil { + return nil + } + a = make([]string, len(r)/2); + for i := 0; i < len(r); i += 2 { + if r[i] != -1 { // -1 means no match for this subexpression + a[i/2] = s[r[i] : r[i+1]] + } + } + return +} + +// Match checks whether a textual regular expression +// matches a substring. More complicated queries need +// to use Compile and the full Regexp interface. +func Match(pattern string, s string) (matched bool, error os.Error) { + re, err := Compile(pattern); + if err != nil { + return false, err + } + return re.Match(s), nil +} diff --git a/src/pkg/runtime/386/asm.s b/src/pkg/runtime/386/asm.s new file mode 100644 index 000000000..5d3c4261a --- /dev/null +++ b/src/pkg/runtime/386/asm.s @@ -0,0 +1,217 @@ +// Copyright 2009 The Go 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(SB),7,$0 + // copy arguments forward on an even stack + MOVL 0(SP), AX // argc + LEAL 4(SP), BX // argv + SUBL $128, SP // plenty of scratch + ANDL $~7, SP + MOVL AX, 120(SP) // save argc, argv away + MOVL BX, 124(SP) + +/* + // write "go386\n" + PUSHL $6 + PUSHL $hello(SB) + PUSHL $1 + CALL sys·write(SB) + POPL AX + POPL AX + POPL AX +*/ + + CALL ldt0setup(SB) + + // set up %fs to refer to that ldt entry + MOVL $(7*8+7), AX + MOVW AX, FS + + // store through it, to make sure it works + MOVL $0x123, 0(FS) + MOVL tls0(SB), AX + CMPL AX, $0x123 + JEQ ok + MOVL AX, 0 +ok: + + // set up m and g "registers" + // g is 0(FS), m is 4(FS) + LEAL g0(SB), CX + MOVL CX, 0(FS) + LEAL m0(SB), AX + MOVL AX, 4(FS) + + // save m->g0 = g0 + MOVL CX, 0(AX) + + // create istack out of the OS stack + LEAL (-8192+104)(SP), AX // TODO: 104? + MOVL AX, 0(CX) // 8(g) is stack limit (w 104b guard) + MOVL SP, 4(CX) // 12(g) is base + CALL emptyfunc(SB) // fault if stack check is wrong + + // convention is D is always cleared + CLD + + CALL check(SB) + + // saved argc, argv + MOVL 120(SP), AX + MOVL AX, 0(SP) + MOVL 124(SP), AX + MOVL AX, 4(SP) + CALL args(SB) + CALL osinit(SB) + CALL schedinit(SB) + + // create a new goroutine to start program + PUSHL $mainstart(SB) // entry + PUSHL $8 // arg size + CALL sys·newproc(SB) + POPL AX + POPL AX + + // start this M + CALL mstart(SB) + + INT $3 + RET + +TEXT mainstart(SB),7,$0 + CALL main·init(SB) + CALL initdone(SB) + CALL main·main(SB) + PUSHL $0 + CALL exit(SB) + POPL AX + INT $3 + RET + +TEXT breakpoint(SB),7,$0 + BYTE $0xcc + RET + +// go-routine +TEXT gogo(SB), 7, $0 + MOVL 4(SP), AX // gobuf + MOVL 0(AX), SP // restore SP + MOVL 4(AX), AX + MOVL AX, 0(SP) // put PC on the stack + MOVL $1, AX + RET + +TEXT gosave(SB), 7, $0 + MOVL 4(SP), AX // gobuf + MOVL SP, 0(AX) // save SP + MOVL 0(SP), BX + MOVL BX, 4(AX) // save PC + MOVL $0, AX // return 0 + RET + +// support for morestack + +// return point when leaving new stack. +// save AX, jmp to lesstack to switch back +TEXT retfromnewstack(SB),7,$0 + MOVL 4(FS), BX // m + MOVL AX, 12(BX) // save AX in m->cret + JMP lessstack(SB) + +// gogo, returning 2nd arg instead of 1 +TEXT gogoret(SB), 7, $0 + MOVL 8(SP), AX // return 2nd arg + MOVL 4(SP), BX // gobuf + MOVL 0(BX), SP // restore SP + MOVL 4(BX), BX + MOVL BX, 0(SP) // put PC on the stack + RET + +TEXT setspgoto(SB), 7, $0 + MOVL 4(SP), AX // SP + MOVL 8(SP), BX // fn to call + MOVL 12(SP), CX // fn to return + MOVL AX, SP + PUSHL CX + JMP BX + POPL AX // not reached + RET + +// bool cas(int32 *val, int32 old, int32 new) +// Atomically: +// if(*val == old){ +// *val = new; +// return 1; +// }else +// return 0; +TEXT 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 + +// 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 jmpdefer(SB), 7, $0 + MOVL 4(SP), AX // fn + MOVL 8(SP), BX // caller sp + LEAL -4(BX), SP // caller sp after CALL + SUBL $5, (SP) // return to CALL again + JMP AX // but first run the deferred function + +TEXT sys·memclr(SB),7,$0 + MOVL 4(SP), DI // arg 1 addr + MOVL 8(SP), CX // arg 2 count + ADDL $3, CX + SHRL $2, CX + MOVL $0, AX + CLD + REP + STOSL + RET + +TEXT sys·getcallerpc+0(SB),7,$0 + MOVL x+0(FP),AX // addr of first arg + MOVL -4(AX),AX // get calling pc + RET + +TEXT sys·setcallerpc+0(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 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. + MOVL $7, 0(SP) + LEAL tls0(SB), AX + MOVL AX, 4(SP) + MOVL $32, 8(SP) // sizeof(tls array) + CALL setldt(SB) + RET + +GLOBL m0+0(SB), $1024 +GLOBL g0+0(SB), $1024 + +GLOBL tls0+0(SB), $32 + +TEXT emptyfunc(SB),0,$0 + RET + +TEXT abort(SB),7,$0 + INT $0x3 + +DATA hello+0(SB)/8, $"go386\n\z\z" +GLOBL hello+0(SB), $8 + diff --git a/src/pkg/runtime/386/closure.c b/src/pkg/runtime/386/closure.c new file mode 100644 index 000000000..6ccbe3b8b --- /dev/null +++ b/src/pkg/runtime/386/closure.c @@ -0,0 +1,104 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "runtime.h" + +#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 +sys·closure(int32 siz, byte *fn, byte *arg0) +{ + byte *p, *q, **ret; + int32 i, n; + int32 pcrel; + + if(siz < 0 || siz%4 != 0) + throw("bad closure size"); + + ret = (byte**)((byte*)&arg0 + siz); + + if(siz > 100) { + // TODO(rsc): implement stack growth preamble? + throw("closure too big"); + } + + // 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 = mal(n); + *ret = p; + q = p + n - siz; + mcpy(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 q) + throw("bad math in sys.closure"); +} + + diff --git a/src/pkg/runtime/386/traceback.c b/src/pkg/runtime/386/traceback.c new file mode 100644 index 000000000..05724d9ac --- /dev/null +++ b/src/pkg/runtime/386/traceback.c @@ -0,0 +1,148 @@ +// Copyright 2009 The Go Authors. 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" + +// TODO(rsc): Move this into portable code, with calls to a +// machine-dependent isclosure() function. + +void +traceback(byte *pc0, byte *sp, G *g) +{ + Stktop *stk; + uintptr pc; + int32 i, n; + Func *f; + byte *p; + + pc = (uintptr)pc0; + + // 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); + } + + stk = (Stktop*)g->stackbase; + for(n=0; n<100; n++) { + while(pc == (uintptr)retfromnewstack) { + // pop to earlier stack block + sp = stk->oldsp; + stk = (Stktop*)stk->oldbase; + pc = *(uintptr*)(sp+sizeof(uintptr)); + sp += 2*sizeof(uintptr); // two irrelevant calls on stack: morestack plus its call + } + f = findfunc(pc); + if(f == nil) { + // dangerous, but poke around to see if it is a closure + p = (byte*)pc; + // ADDL $xxx, SP; RET + if(p[0] == 0x81 && p[1] == 0xc4 && p[6] == 0xc3) { + sp += *(uint32*)(p+2) + 8; + pc = *(uintptr*)(sp - 8); + if(pc <= 0x1000) + return; + continue; + } + printf("%p unknown pc\n", pc); + return; + } + if(f->frame < sizeof(uintptr)) // assembly funcs say 0 but lie + sp += sizeof(uintptr); + else + sp += f->frame; + + // print this frame + // main+0xf /home/rsc/go/src/runtime/x.go:23 + // main(0x1, 0x2, 0x3) + printf("%S", f->name); + if(pc > f->entry) + printf("+%p", (uintptr)(pc - f->entry)); + printf(" %S:%d\n", f->src, funcline(f, pc-1)); // -1 to get to CALL instr. + printf("\t%S(", f->name); + for(i = 0; i < f->args; i++) { + if(i != 0) + prints(", "); + sys·printhex(((uint32*)sp)[i]); + if(i >= 4) { + prints(", ..."); + break; + } + } + prints(")\n"); + + pc = *(uintptr*)(sp-sizeof(uintptr)); + if(pc <= 0x1000) + return; + } + prints("...\n"); +} + +// func caller(n int) (pc uintptr, file string, line int, ok bool) +void +runtime·Caller(int32 n, uintptr retpc, String retfile, int32 retline, bool retbool) +{ + uintptr pc; + byte *sp; + byte *p; + Stktop *stk; + Func *f; + + // our caller's pc, sp. + sp = (byte*)&n; + pc = *((uintptr*)sp - 1); + if((f = findfunc(pc)) == nil) { + error: + retpc = 0; + retline = 0; + retfile = emptystring; + retbool = false; + FLUSH(&retpc); + FLUSH(&retfile); + FLUSH(&retline); + FLUSH(&retbool); + return; + } + + // now unwind n levels + stk = (Stktop*)g->stackbase; + while(n-- > 0) { + while(pc == (uintptr)retfromnewstack) { + sp = stk->oldsp; + stk = (Stktop*)stk->oldbase; + pc = *((uintptr*)sp + 1); + sp += 2*sizeof(uintptr); + } + + if(f->frame < sizeof(uintptr)) // assembly functions lie + sp += sizeof(uintptr); + else + sp += f->frame; + + loop: + pc = *((uintptr*)sp - 1); + if(pc <= 0x1000 || (f = findfunc(pc)) == nil) { + // dangerous, but let's try this. + // see if it is a closure. + p = (byte*)pc; + // ADDL $xxx, SP; RET + if(p[0] == 0x81 && p[1] == 0xc4 && p[6] == 0xc3) { + sp += *(uint32*)(p+2) + sizeof(uintptr); + goto loop; + } + goto error; + } + } + + retpc = pc; + retfile = f->src; + retline = funcline(f, pc-1); + retbool = true; + FLUSH(&retpc); + FLUSH(&retfile); + FLUSH(&retline); + FLUSH(&retbool); +} + diff --git a/src/pkg/runtime/386/vlop.s b/src/pkg/runtime/386/vlop.s new file mode 100755 index 000000000..803276ce2 --- /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 100755 index 000000000..093cca70d --- /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 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 +sys·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 +sys·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 +sys·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 +sys·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: + 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..5a5ace9c5 --- /dev/null +++ b/src/pkg/runtime/Makefile @@ -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. + +# Set SIZE to 32 or 64. +SIZE_386=32 +SIZE_amd64=64 +SIZE_arm=32 +SIZE=$(SIZE_$(GOARCH)) + +# Setup CFLAGS. Add -D_64BIT on 64-bit platforms (sorry). +CFLAGS_64=-D_64BIT +CFLAGS=-I$(GOOS) -I$(GOOS)/$(GOARCH) -wF $(CFLAGS_$(SIZE)) + +# Set O to right letter. +O_386=8 +O_amd64=6 +O_arm=5 +O=$(O_$(GOARCH)) + +# Tools +CC=$(O)c +GC=$(O)g +AS=$(O)a +AR=gopack + +LIB=runtime.a + +# 386-specific object files +OFILES_386=\ + vlop.$O\ + vlrt.$O\ + +OFILES=\ + array.$O\ + asm.$O\ + chan.$O\ + closure.$O\ + extern.$O\ + float.$O\ + float_go.$O\ + hashmap.$O\ + iface.$O\ + malloc.$O\ + malloc_go.$O\ + mcache.$O\ + mcentral.$O\ + mem.$O\ + mfixalloc.$O\ + mgc0.$O\ + mheap.$O\ + mheapmap$(SIZE).$O\ + msize.$O\ + print.$O\ + proc.$O\ + rune.$O\ + runtime.$O\ + rt0.$O\ + sema.$O\ + sema_go.$O\ + signal.$O\ + string.$O\ + symtab.$O\ + sys.$O\ + thread.$O\ + traceback.$O\ + $(OFILES_$(GOARCH))\ + +HFILES=\ + runtime.h\ + hashmap.h\ + malloc.h\ + $(GOOS)/os.h\ + $(GOOS)/$(GOARCH)/defs.h\ + +install: $(LIB) runtime.acid + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH) + cp $(LIB) $(GOROOT)/pkg/$(GOOS)_$(GOARCH)/$(LIB) + cp runtime.acid $(GOROOT)/acid/runtime.acid + +$(LIB): $(OFILES) + $(AR) grc $(LIB) $(OFILES) + +$(OFILES): $(HFILES) + +nuke: + rm -f *.[568] *.a $(GOROOT)/lib/$(LIB) + +clean: + rm -f *.[568] *.a runtime.acid cgo2c + +%.$O: %.go + $(GC) $< + +%.$O: %.c + $(CC) $(CFLAGS) $< + +%.$O: $(GOARCH)/%.c + $(CC) $(CFLAGS) $< + +%.$O: $(GOOS)/%.c + $(CC) $(CFLAGS) $< + +%.$O: $(GOOS)/$(GOARCH)/%.c + $(CC) $(CFLAGS) $< + +%.$O: $(GOARCH)/%.s + $(AS) $< + +%.$O: $(GOOS)/$(GOARCH)/%.s + $(AS) $< + +cgo2c: cgo2c.c + quietgcc -o $@ $< + +%.c: %.cgo cgo2c + ./cgo2c $< > $@.tmp + mv -f $@.tmp $@ + +runtime.acid: runtime.h proc.c + $(CC) -a proc.c >runtime.acid + +chan.acid: runtime.h chan.c + $(CC) -a chan.c >chan.acid + diff --git a/src/pkg/runtime/amd64/asm.s b/src/pkg/runtime/amd64/asm.s new file mode 100644 index 000000000..6fc01bbc9 --- /dev/null +++ b/src/pkg/runtime/amd64/asm.s @@ -0,0 +1,207 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + + +TEXT _rt0_amd64(SB),7,$-8 + + // copy arguments forward on an even stack + + MOVQ 0(SP), AX // argc + LEAQ 8(SP), BX // argv + SUBQ $(4*8+7), SP // 2args 2auto + ANDQ $~7, SP + MOVQ AX, 16(SP) + MOVQ BX, 24(SP) + + // set the per-goroutine and per-mach registers + + LEAQ m0(SB), R14 // dedicated m. register + LEAQ g0(SB), R15 // dedicated g. register + MOVQ R15, 0(R14) // m has pointer to its g0 + + // create istack out of the given (operating system) stack + + LEAQ (-8192+104)(SP), AX + MOVQ AX, 0(R15) // 0(R15) is stack limit (w 104b guard) + MOVQ SP, 8(R15) // 8(R15) is base + + CLD // convention is D is always left cleared + CALL check(SB) + + MOVL 16(SP), AX // copy argc + MOVL AX, 0(SP) + MOVQ 24(SP), AX // copy argv + MOVQ AX, 8(SP) + CALL args(SB) + CALL osinit(SB) + CALL schedinit(SB) + + // create a new goroutine to start program + PUSHQ $mainstart(SB) // entry + PUSHQ $16 // arg size + CALL sys·newproc(SB) + POPQ AX + POPQ AX + + // start this M + CALL mstart(SB) + + CALL notok(SB) // never returns + RET + +TEXT mainstart(SB),7,$0 + CALL main·init(SB) + CALL initdone(SB) + CALL main·main(SB) + PUSHQ $0 + CALL exit(SB) + POPQ AX + CALL notok(SB) + RET + +TEXT breakpoint(SB),7,$0 + BYTE $0xcc + RET + +/* + * go-routine + */ +TEXT gogo(SB), 7, $0 + MOVQ 8(SP), AX // gobuf + MOVQ 0(AX), SP // restore SP + MOVQ 8(AX), AX + MOVQ AX, 0(SP) // put PC on the stack + MOVL $1, AX // return 1 + RET + +TEXT gosave(SB), 7, $0 + MOVQ 8(SP), AX // gobuf + MOVQ SP, 0(AX) // save SP + MOVQ 0(SP), BX + MOVQ BX, 8(AX) // save PC + MOVL $0, AX // return 0 + RET + +/* + * support for morestack + */ + +// morestack trampolines +TEXT sys·morestack00+0(SB),7,$0 + MOVQ $0, AX + MOVQ AX, 8(R14) + MOVQ $sys·morestack+0(SB), AX + JMP AX + +TEXT sys·morestack01+0(SB),7,$0 + SHLQ $32, AX + MOVQ AX, 8(R14) + MOVQ $sys·morestack+0(SB), AX + JMP AX + +TEXT sys·morestack10+0(SB),7,$0 + MOVLQZX AX, AX + MOVQ AX, 8(R14) + MOVQ $sys·morestack+0(SB), AX + JMP AX + +TEXT sys·morestack11+0(SB),7,$0 + MOVQ AX, 8(R14) + MOVQ $sys·morestack+0(SB), AX + JMP AX + +TEXT sys·morestackx(SB),7,$0 + POPQ AX + SHLQ $35, AX + MOVQ AX, 8(R14) + MOVQ $sys·morestack(SB), AX + JMP AX + +// subcases of morestack01 +// with const of 8,16,...48 +TEXT sys·morestack8(SB),7,$0 + PUSHQ $1 + MOVQ $sys·morestackx(SB), AX + JMP AX + +TEXT sys·morestack16(SB),7,$0 + PUSHQ $2 + MOVQ $sys·morestackx(SB), AX + JMP AX + +TEXT sys·morestack24(SB),7,$0 + PUSHQ $3 + MOVQ $sys·morestackx(SB), AX + JMP AX + +TEXT sys·morestack32(SB),7,$0 + PUSHQ $4 + MOVQ $sys·morestackx(SB), AX + JMP AX + +TEXT sys·morestack40(SB),7,$0 + PUSHQ $5 + MOVQ $sys·morestackx(SB), AX + JMP AX + +TEXT sys·morestack48(SB),7,$0 + PUSHQ $6 + MOVQ $sys·morestackx(SB), AX + JMP AX + +// return point when leaving new stack. save AX, jmp to lessstack to switch back +TEXT retfromnewstack(SB), 7, $0 + MOVQ AX, 16(R14) // save AX in m->cret + MOVQ $lessstack(SB), AX + JMP AX + +// gogo, returning 2nd arg instead of 1 +TEXT gogoret(SB), 7, $0 + MOVQ 16(SP), AX // return 2nd arg + MOVQ 8(SP), BX // gobuf + MOVQ 0(BX), SP // restore SP + MOVQ 8(BX), BX + MOVQ BX, 0(SP) // put PC on the stack + RET + +TEXT setspgoto(SB), 7, $0 + MOVQ 8(SP), AX // SP + MOVQ 16(SP), BX // fn to call + MOVQ 24(SP), CX // fn to return + MOVQ AX, SP + PUSHQ CX + JMP BX + POPQ AX // not reached + RET + +// bool cas(int32 *val, int32 old, int32 new) +// Atomically: +// if(*val == old){ +// *val = new; +// return 1; +// } else +// return 0; +TEXT 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 + +// 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 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 diff --git a/src/pkg/runtime/amd64/closure.c b/src/pkg/runtime/amd64/closure.c new file mode 100644 index 000000000..5717d3c5e --- /dev/null +++ b/src/pkg/runtime/amd64/closure.c @@ -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 "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 +sys·closure(int32 siz, byte *fn, byte *arg0) +{ + byte *p, *q, **ret; + int32 i, n; + int64 pcrel; + + if(siz < 0 || siz%8 != 0) + throw("bad closure size"); + + ret = (byte**)((byte*)&arg0 + siz); + + if(siz > 100) { + // TODO(rsc): implement stack growth preamble? + 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 = mal(n); + *ret = p; + q = p + n - siz; + mcpy(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 q) + throw("bad math in sys.closure"); +} + + diff --git a/src/pkg/runtime/amd64/traceback.c b/src/pkg/runtime/amd64/traceback.c new file mode 100644 index 000000000..16d7bed72 --- /dev/null +++ b/src/pkg/runtime/amd64/traceback.c @@ -0,0 +1,146 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "runtime.h" + +void +traceback(byte *pc0, byte *sp, G *g) +{ + Stktop *stk; + uint64 pc; + int32 i, n; + Func *f; + byte *p; + + pc = (uint64)pc0; + + // If the PC is zero, it's likely a nil function call. + // Start in the caller's frame. + if(pc == 0) { + pc = *(uint64*)sp; + sp += 8; + } + + stk = (Stktop*)g->stackbase; + for(n=0; n<100; n++) { + while(pc == (uint64)retfromnewstack) { + // pop to earlier stack block + sp = stk->oldsp; + stk = (Stktop*)stk->oldbase; + pc = *(uint64*)(sp+8); + sp += 16; // two irrelevant calls on stack: morestack plus its call + } + f = findfunc(pc); + if(f == nil) { + // dangerous, but poke around to see if it is a closure + p = (byte*)pc; + // ADDQ $xxx, SP; RET + if(p[0] == 0x48 && p[1] == 0x81 && p[2] == 0xc4 && p[7] == 0xc3) { + sp += *(uint32*)(p+3) + 8; + pc = *(uint64*)(sp - 8); + if(pc <= 0x1000) + return; + continue; + } + printf("%p unknown pc\n", pc); + return; + } + if(f->frame < 8) // assembly funcs say 0 but lie + sp += 8; + else + sp += f->frame; + + // print this frame + // main+0xf /home/rsc/go/src/runtime/x.go:23 + // main(0x1, 0x2, 0x3) + printf("%S", f->name); + if(pc > f->entry) + printf("+%X", pc - f->entry); + printf(" %S:%d\n", f->src, funcline(f, pc-1)); // -1 to get to CALL instr. + printf("\t%S(", f->name); + for(i = 0; i < f->args; i++) { + if(i != 0) + prints(", "); + sys·printhex(((uint32*)sp)[i]); + if(i >= 4) { + prints(", ..."); + break; + } + } + prints(")\n"); + + pc = *(uint64*)(sp-8); + if(pc <= 0x1000) + return; + } + prints("...\n"); +} + +// func caller(n int) (pc uint64, file string, line int, ok bool) +void +runtime·Caller(int32 n, uint64 retpc, String retfile, int32 retline, bool retbool) +{ + uint64 pc; + byte *sp; + byte *p; + Stktop *stk; + Func *f; + + // our caller's pc, sp. + sp = (byte*)&n; + pc = *(uint64*)(sp-8); + if((f = findfunc(pc)) == nil) { + error: + retpc = 0; + retline = 0; + retfile = emptystring; + retbool = false; + FLUSH(&retpc); + FLUSH(&retfile); + FLUSH(&retline); + FLUSH(&retbool); + return; + } + + // now unwind n levels + stk = (Stktop*)g->stackbase; + while(n-- > 0) { + while(pc == (uint64)retfromnewstack) { + sp = stk->oldsp; + stk = (Stktop*)stk->oldbase; + pc = *(uint64*)(sp+8); + sp += 16; + } + + if(f->frame < 8) // assembly functions lie + sp += 8; + else + sp += f->frame; + + loop: + pc = *(uint64*)(sp-8); + if(pc <= 0x1000 || (f = findfunc(pc)) == nil) { + // dangerous, but let's try this. + // see if it is a closure. + p = (byte*)pc; + // ADDQ $xxx, SP; RET + if(p[0] == 0x48 && p[1] == 0x81 && p[2] == 0xc4 && p[7] == 0xc3) { + sp += *(uint32*)(p+3) + 8; + goto loop; + } + goto error; + } + } + + retpc = pc; + retfile = f->src; + retline = funcline(f, pc-1); + retbool = true; + FLUSH(&retpc); + FLUSH(&retfile); + FLUSH(&retline); + FLUSH(&retbool); +} + + diff --git a/src/pkg/runtime/arm/asm.s b/src/pkg/runtime/arm/asm.s new file mode 100644 index 000000000..232ab4ddf --- /dev/null +++ b/src/pkg/runtime/arm/asm.s @@ -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. + +TEXT _rt0_arm(SB),7,$0 + // copy arguments forward on an even stack + // MOVW $0(SP), R0 + // MOVL 0(SP), R1 // argc +// LEAL 4(SP), R1 // argv +// SUBL $128, SP // plenty of scratch +// ANDL $~7, SP +// MOVL AX, 120(SP) // save argc, argv away +// MOVL BX, 124(SP) + + +// // write "go386\n" +// PUSHL $6 +// PUSHL $hello(SB) +// PUSHL $1 +// CALL sys·write(SB) +// POPL AX +// POPL AX +// POPL AX + + +// CALL ldt0setup(SB) + + // set up %fs to refer to that ldt entry +// MOVL $(7*8+7), AX +// MOVW AX, FS + +// // store through it, to make sure it works +// MOVL $0x123, 0(FS) +// MOVL tls0(SB), AX +// CMPL AX, $0x123 +// JEQ ok +// MOVL AX, 0 +// ok: + +// // set up m and g "registers" +// // g is 0(FS), m is 4(FS) +// LEAL g0(SB), CX +// MOVL CX, 0(FS) +// LEAL m0(SB), AX +// MOVL AX, 4(FS) + +// // save m->g0 = g0 +// MOVL CX, 0(AX) + +// // create istack out of the OS stack +// LEAL (-8192+104)(SP), AX // TODO: 104? +// MOVL AX, 0(CX) // 8(g) is stack limit (w 104b guard) +// MOVL SP, 4(CX) // 12(g) is base +// CALL emptyfunc(SB) // fault if stack check is wrong + +// // convention is D is always cleared +// CLD + +// CALL check(SB) + +// // saved argc, argv +// MOVL 120(SP), AX +// MOVL AX, 0(SP) +// MOVL 124(SP), AX +// MOVL AX, 4(SP) +// CALL args(SB) +// CALL osinit(SB) +// CALL schedinit(SB) + +// // create a new goroutine to start program +// PUSHL $mainstart(SB) // entry +// PUSHL $8 // arg size +// CALL sys·newproc(SB) +// POPL AX +// POPL AX + +// // start this M +// CALL mstart(SB) + + BL main�main(SB) + MOVW $99, R0 + SWI $0x00900001 + diff --git a/src/pkg/runtime/arm/closure.c b/src/pkg/runtime/arm/closure.c new file mode 100644 index 000000000..bfa9df67f --- /dev/null +++ b/src/pkg/runtime/arm/closure.c @@ -0,0 +1,3 @@ +// Copyright 2009 The Go 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/arm/traceback.s b/src/pkg/runtime/arm/traceback.s new file mode 100644 index 000000000..e69de29bb diff --git a/src/pkg/runtime/array.c b/src/pkg/runtime/array.c new file mode 100644 index 000000000..bbd57b03e --- /dev/null +++ b/src/pkg/runtime/array.c @@ -0,0 +1,175 @@ +// Copyright 2009 The Go Authors. 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 int32 debug = 0; + +// newarray(nel int, cap int, width int) (ary []any); +void +sys·newarray(uint32 nel, uint32 cap, uint32 width, Array ret) +{ + uint64 size; + + if(cap < nel) + cap = nel; + size = cap*width; + + ret.nel = nel; + ret.cap = cap; + ret.array = mal(size); + + FLUSH(&ret); + + if(debug) { + prints("newarray: nel="); + sys·printint(nel); + prints("; cap="); + sys·printint(cap); + prints("; width="); + sys·printint(width); + prints("; ret="); + sys·printarray(ret); + prints("\n"); + } +} + +static void +throwslice(uint32 lb, uint32 hb, uint32 n) +{ + prints("slice["); + sys·printint(lb); + prints(":"); + sys·printint(hb); + prints("] of ["); + sys·printint(n); + prints("] array\n"); + throw("array slice"); +} + +// arraysliced(old []any, lb int, hb int, width int) (ary []any); +void +sys·arraysliced(Array old, uint32 lb, uint32 hb, uint32 width, Array ret) +{ + + if(hb > old.cap || lb > hb) { + if(debug) { + prints("sys·arraysliced: old="); + sys·printarray(old); + prints("; lb="); + sys·printint(lb); + prints("; hb="); + sys·printint(hb); + prints("; width="); + sys·printint(width); + prints("\n"); + + prints("oldarray: nel="); + sys·printint(old.nel); + prints("; cap="); + sys·printint(old.cap); + prints("\n"); + } + throwslice(lb, hb, old.cap); + } + + // new array is inside old array + ret.nel = hb-lb; + ret.cap = old.cap - lb; + ret.array = old.array + lb*width; + + FLUSH(&ret); + + if(debug) { + prints("sys·arraysliced: old="); + sys·printarray(old); + prints("; lb="); + sys·printint(lb); + prints("; hb="); + sys·printint(hb); + prints("; width="); + sys·printint(width); + prints("; ret="); + sys·printarray(ret); + prints("\n"); + } +} + +// arrayslices(old *any, nel int, lb int, hb int, width int) (ary []any); +void +sys·arrayslices(byte* old, uint32 nel, uint32 lb, uint32 hb, uint32 width, Array ret) +{ + + if(hb > nel || lb > hb) { + if(debug) { + prints("sys·arrayslices: old="); + sys·printpointer(old); + prints("; nel="); + sys·printint(nel); + prints("; lb="); + sys·printint(lb); + prints("; hb="); + sys·printint(hb); + prints("; width="); + sys·printint(width); + prints("\n"); + } + throwslice(lb, hb, nel); + } + + // new array is inside old array + ret.nel = hb-lb; + ret.cap = nel-lb; + ret.array = old + lb*width; + + FLUSH(&ret); + + if(debug) { + prints("sys·arrayslices: old="); + sys·printpointer(old); + prints("; nel="); + sys·printint(nel); + prints("; lb="); + sys·printint(lb); + prints("; hb="); + sys·printint(hb); + prints("; width="); + sys·printint(width); + prints("; ret="); + sys·printarray(ret); + prints("\n"); + } +} + +// arrays2d(old *any, nel int) (ary []any) +void +sys·arrays2d(byte* old, uint32 nel, Array ret) +{ + + // new dope to old array + ret.nel = nel; + ret.cap = nel; + ret.array = old; + + FLUSH(&ret); + + if(debug) { + prints("sys·arrays2d: old="); + sys·printpointer(old); + prints("; ret="); + sys·printarray(ret); + prints("\n"); + } +} + +void +sys·printarray(Array a) +{ + prints("["); + sys·printint(a.nel); + prints("/"); + sys·printint(a.cap); + prints("]"); + sys·printpointer(a.array); +} diff --git a/src/pkg/runtime/cgo2c.c b/src/pkg/runtime/cgo2c.c new file mode 100644 index 000000000..3905f7e6d --- /dev/null +++ b/src/pkg/runtime/cgo2c.c @@ -0,0 +1,602 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* Translate a .cgo file into a .c file. A .cgo 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 +#include +#include +#include +#include +#include + +/* Whether we're emitting for gcc */ +static int gcc; + +/* File and line number */ +static const char *file; +static unsigned int lineno; + +/* List of names and types. */ +struct params { + struct params *next; + char *name; + char *type; +}; + +/* Unexpected EOF. */ +static void +bad_eof(void) +{ + fprintf(stderr, "%s:%u: unexpected EOF\n", file, lineno); + exit(1); +} + +/* Out of memory. */ +static void +bad_mem(void) +{ + fprintf(stderr, "%s:%u: out of memory\n", file, lineno); + exit(1); +} + +/* Allocate memory without fail. */ +static void * +xmalloc(unsigned int size) +{ + void *ret = malloc(size); + if (ret == NULL) + bad_mem(); + return ret; +} + +/* Reallocate memory without fail. */ +static void* +xrealloc(void *buf, unsigned int size) +{ + void *ret = realloc(buf, size); + if (ret == NULL) + bad_mem(); + return ret; +} + +/* Free a list of parameters. */ +static void +free_params(struct params *p) +{ + while (p != NULL) { + struct params *next; + + next = p->next; + free(p->name); + free(p->type); + free(p); + p = next; + } +} + +/* Read a character, tracking lineno. */ +static int +getchar_update_lineno(void) +{ + int c; + + c = getchar(); + if (c == '\n') + ++lineno; + return c; +} + +/* Read a character, giving an error on EOF, tracking lineno. */ +static int +getchar_no_eof(void) +{ + int c; + + c = getchar_update_lineno(); + if (c == EOF) + bad_eof(); + return c; +} + +/* Read a character, skipping comments. */ +static int +getchar_skipping_comments(void) +{ + int c; + + while (1) { + c = getchar_update_lineno(); + if (c != '/') + return c; + + c = getchar(); + if (c == '/') { + do { + c = getchar_update_lineno(); + } while (c != EOF && c != '\n'); + return c; + } else if (c == '*') { + while (1) { + c = getchar_update_lineno(); + if (c == EOF) + return EOF; + if (c == '*') { + do { + c = getchar_update_lineno(); + } while (c == '*'); + if (c == '/') + break; + } + } + } else { + ungetc(c, stdin); + return '/'; + } + } +} + +/* Read and return a token. Tokens are delimited by whitespace or by + [(),{}]. The latter are all returned as single characters. */ +static char * +read_token(void) +{ + int c; + char *buf; + unsigned int alc, off; + const char* delims = "(),{}"; + + while (1) { + c = getchar_skipping_comments(); + if (c == EOF) + return NULL; + if (!isspace(c)) + break; + } + alc = 16; + buf = xmalloc(alc + 1); + off = 0; + if (strchr(delims, c) != NULL) { + buf[off] = c; + ++off; + } else { + while (1) { + if (off >= alc) { + alc *= 2; + buf = xrealloc(buf, alc + 1); + } + buf[off] = c; + ++off; + c = getchar_skipping_comments(); + if (c == EOF) + break; + if (isspace(c) || strchr(delims, c) != NULL) { + ungetc(c, stdin); + break; + } + } + } + buf[off] = '\0'; + return buf; +} + +/* Read a token, giving an error on EOF. */ +static char * +read_token_no_eof(void) +{ + char *token = read_token(); + if (token == NULL) + bad_eof(); + return token; +} + +/* Read the package clause, and return the package name. */ +static char * +read_package(void) +{ + char *token; + + token = read_token_no_eof(); + if (strcmp(token, "package") != 0) { + fprintf(stderr, + "%s:%u: expected \"package\", got \"%s\"\n", + file, lineno, token); + exit(1); + } + return read_token_no_eof(); +} + +/* Read and copy preprocessor lines. */ +static void +read_preprocessor_lines(void) +{ + while (1) { + int c; + + do { + c = getchar_skipping_comments(); + } while (isspace(c)); + if (c != '#') { + ungetc(c, stdin); + return; + } + 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; +} + +/* 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(void) +{ + char *token; + struct params *ret, **pp; + + ret = NULL; + pp = &ret; + token = read_token_no_eof(); + if (strcmp(token, ")") != 0) { + while (1) { + *pp = xmalloc(sizeof(struct params)); + (*pp)->name = token; + (*pp)->type = read_type(); + pp = &(*pp)->next; + *pp = NULL; + + token = read_token_no_eof(); + if (strcmp(token, ",") != 0) + break; + token = read_token_no_eof(); + } + } + if (strcmp(token, ")") != 0) { + fprintf(stderr, "%s:%u: expected '('\n", + file, lineno); + exit(1); + } + 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, struct params **rets) +{ + char *token; + + token = read_token(); + if (token == NULL) + return 0; + if (strcmp(token, "func") != 0) { + fprintf(stderr, "%s:%u: expected \"func\"\n", + file, lineno); + exit(1); + } + *name = read_token_no_eof(); + + token = read_token(); + if (token == NULL || strcmp(token, "(") != 0) { + fprintf(stderr, "%s:%u: expected \"(\"\n", + file, lineno); + exit(1); + } + *params = read_params(); + + token = read_token(); + if (token == NULL || strcmp(token, "(") != 0) + *rets = NULL; + else { + *rets = read_params(); + token = read_token(); + } + if (token == NULL || strcmp(token, "{") != 0) { + fprintf(stderr, "%s:%u: expected \"{\"\n", + file, lineno); + exit(1); + } + return 1; +} + +/* Write out parameters. */ +static void +write_params(struct params *params, int *first) +{ + struct params *p; + + for (p = params; p != NULL; p = p->next) { + if (*first) + *first = 0; + else + printf(", "); + printf("%s %s", p->type, p->name); + } +} + +/* Write a 6g function header. */ +static void +write_6g_func_header(char *package, char *name, struct params *params, + struct params *rets) +{ + int first; + + printf("void\n%s·%s(", package, name); + first = 1; + write_params(params, &first); + 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, struct params *rets) +{ + if (gcc) + write_gcc_func_header(package, name, params, rets); + else + write_6g_func_header(package, name, params, 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; + + package = read_package(); + read_preprocessor_lines(); + while (read_func_header(&name, ¶ms, &rets)) { + write_func_header(package, name, params, rets); + copy_body(); + write_func_trailer(package, name, rets); + free(name); + free_params(params); + free_params(rets); + } + free(package); +} + +static void +usage(void) +{ + fprintf(stderr, "Usage: cgo2c [--6g | --gc] [file]\n"); + exit(1); +} + +int +main(int argc, char **argv) +{ + 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 = ""; + process_file(); + return 0; + } + + if(argc > 2) + usage(); + + file = argv[1]; + if(freopen(file, "r", stdin) == 0) { + fprintf(stderr, "open %s: %s\n", file, strerror(errno)); + exit(1); + } + process_file(); + return 0; +} diff --git a/src/pkg/runtime/chan.c b/src/pkg/runtime/chan.c new file mode 100644 index 000000000..be65bcbc1 --- /dev/null +++ b/src/pkg/runtime/chan.c @@ -0,0 +1,1024 @@ +// Copyright 2009 The Go Authors. 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 int32 debug = 0; +static Lock chanlock; + +enum +{ + Wclosed = 0x0001, // writer has closed + Rclosed = 0x0002, // reader has seen close + Eincr = 0x0004, // increment errors + Emax = 0x0800, // error limit before throw +}; + +typedef struct Hchan Hchan; +typedef struct Link Link; +typedef struct WaitQ WaitQ; +typedef struct SudoG SudoG; +typedef struct Select Select; +typedef struct Scase Scase; + +struct SudoG +{ + G* g; // g and selgen constitute + int32 selgen; // a weak pointer to g + int16 offset; // offset of case number + int8 isfree; // offset of case number + SudoG* link; + byte elem[8]; // synch data element (+ more) +}; + +struct WaitQ +{ + SudoG* first; + SudoG* last; +}; + +struct Hchan +{ + uint16 elemsize; + uint16 closed; // Wclosed Rclosed errorcount + uint32 dataqsiz; // size of the circular q + uint32 qcount; // total data in the q + Alg* elemalg; // interface for element type + Link* senddataq; // pointer for sender + Link* recvdataq; // pointer for receiver + WaitQ recvq; // list of recv waiters + WaitQ sendq; // list of send waiters + SudoG* free; // freelist +}; + +struct Link +{ + Link* link; // asynch queue circular linked list + byte elem[8]; // asynch queue data element (+ more) +}; + +struct Scase +{ + Hchan* chan; // chan + byte* pc; // return pc + uint16 send; // 0-recv 1-send 2-default + uint16 so; // vararg of selected bool + union { + byte elem[8]; // element (send) + byte* elemp; // pointer to element (recv) + } u; +}; + +struct Select +{ + uint16 tcase; // total count of scase[] + uint16 ncase; // currently filled scase[] + Select* link; // for freelist + Scase* scase[1]; // one per case +}; + +static Select* selfree[20]; + +static SudoG* dequeue(WaitQ*, Hchan*); +static void enqueue(WaitQ*, SudoG*); +static SudoG* allocsg(Hchan*); +static void freesg(Hchan*, SudoG*); +static uint32 gcd(uint32, uint32); +static uint32 fastrand1(void); +static uint32 fastrand2(void); + +// newchan(elemsize uint32, elemalg uint32, hint uint32) (hchan *chan any); +void +sys·newchan(uint32 elemsize, uint32 elemalg, uint32 hint, + Hchan* ret) +{ + Hchan *c; + int32 i; + + if(elemalg >= nelem(algarray)) { + printf("chan(alg=%d)\n", elemalg); + throw("sys·newchan: unsupported elem type"); + } + + c = mal(sizeof(*c)); + + c->elemsize = elemsize; + c->elemalg = &algarray[elemalg]; + + if(hint > 0) { + Link *d, *b, *e; + + // make a circular q + b = nil; + e = nil; + for(i=0; ielemsize - sizeof(d->elem)); + if(e == nil) + e = d; + d->link = b; + b = d; + } + e->link = b; + c->recvdataq = b; + c->senddataq = b; + c->qcount = 0; + c->dataqsiz = hint; + } + + ret = c; + FLUSH(&ret); + + if(debug) { + prints("newchan: chan="); + sys·printpointer(c); + prints("; elemsize="); + sys·printint(elemsize); + prints("; elemalg="); + sys·printint(elemalg); + prints("; dataqsiz="); + sys·printint(c->dataqsiz); + prints("\n"); + } +} + +static void +incerr(Hchan* c) +{ + c->closed += Eincr; + if(c->closed & Emax) { + unlock(&chanlock); + throw("too many operations on a closed channel"); + } +} + +/* + * 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 + */ +void +sendchan(Hchan *c, byte *ep, bool *pres) +{ + SudoG *sg; + G* gp; + + if(debug) { + prints("chansend: chan="); + sys·printpointer(c); + prints("; elem="); + c->elemalg->print(c->elemsize, ep); + prints("\n"); + } + + lock(&chanlock); +loop: + if(c->closed & Wclosed) + goto closed; + + if(c->dataqsiz > 0) + goto asynch; + + sg = dequeue(&c->recvq, c); + if(sg != nil) { + if(ep != nil) + c->elemalg->copy(c->elemsize, sg->elem, ep); + + gp = sg->g; + gp->param = sg; + unlock(&chanlock); + ready(gp); + + if(pres != nil) + *pres = true; + return; + } + + if(pres != nil) { + unlock(&chanlock); + *pres = false; + return; + } + + sg = allocsg(c); + if(ep != nil) + c->elemalg->copy(c->elemsize, sg->elem, ep); + g->param = nil; + g->status = Gwaiting; + enqueue(&c->sendq, sg); + unlock(&chanlock); + gosched(); + + lock(&chanlock); + sg = g->param; + if(sg == nil) + goto loop; + freesg(c, sg); + unlock(&chanlock); + if(pres != nil) + *pres = true; + return; + +asynch: + if(c->closed & Wclosed) + goto closed; + + if(c->qcount >= c->dataqsiz) { + if(pres != nil) { + unlock(&chanlock); + *pres = false; + return; + } + sg = allocsg(c); + g->status = Gwaiting; + enqueue(&c->sendq, sg); + unlock(&chanlock); + gosched(); + + lock(&chanlock); + goto asynch; + } + if(ep != nil) + c->elemalg->copy(c->elemsize, c->senddataq->elem, ep); + c->senddataq = c->senddataq->link; + c->qcount++; + + sg = dequeue(&c->recvq, c); + if(sg != nil) { + gp = sg->g; + freesg(c, sg); + unlock(&chanlock); + ready(gp); + } else + unlock(&chanlock); + if(pres != nil) + *pres = true; + return; + +closed: + incerr(c); + if(pres != nil) + *pres = true; + unlock(&chanlock); +} + +static void +chanrecv(Hchan* c, byte *ep, bool* pres) +{ + SudoG *sg; + G *gp; + + if(debug) { + prints("chanrecv: chan="); + sys·printpointer(c); + prints("\n"); + } + + lock(&chanlock); +loop: + if(c->dataqsiz > 0) + goto asynch; + + if(c->closed & Wclosed) + goto closed; + + sg = dequeue(&c->sendq, c); + if(sg != nil) { + c->elemalg->copy(c->elemsize, ep, sg->elem); + + gp = sg->g; + gp->param = sg; + unlock(&chanlock); + ready(gp); + + if(pres != nil) + *pres = true; + return; + } + + if(pres != nil) { + unlock(&chanlock); + *pres = false; + return; + } + + sg = allocsg(c); + g->param = nil; + g->status = Gwaiting; + enqueue(&c->recvq, sg); + unlock(&chanlock); + gosched(); + + lock(&chanlock); + sg = g->param; + if(sg == nil) + goto loop; + + c->elemalg->copy(c->elemsize, ep, sg->elem); + freesg(c, sg); + unlock(&chanlock); + if(pres != nil) + *pres = true; + return; + +asynch: + if(c->qcount <= 0) { + if(c->closed & Wclosed) + goto closed; + + if(pres != nil) { + unlock(&chanlock); + *pres = false; + return; + } + sg = allocsg(c); + g->status = Gwaiting; + enqueue(&c->recvq, sg); + unlock(&chanlock); + gosched(); + + lock(&chanlock); + goto asynch; + } + c->elemalg->copy(c->elemsize, ep, c->recvdataq->elem); + c->recvdataq = c->recvdataq->link; + c->qcount--; + sg = dequeue(&c->sendq, c); + if(sg != nil) { + gp = sg->g; + freesg(c, sg); + unlock(&chanlock); + ready(gp); + if(pres != nil) + *pres = true; + return; + } + + unlock(&chanlock); + if(pres != nil) + *pres = true; + return; + +closed: + c->elemalg->copy(c->elemsize, ep, nil); + c->closed |= Rclosed; + incerr(c); + if(pres != nil) + *pres = true; + unlock(&chanlock); +} + +// chansend1(hchan *chan any, elem any); +void +sys·chansend1(Hchan* c, ...) +{ + int32 o; + byte *ae; + + o = rnd(sizeof(c), c->elemsize); + ae = (byte*)&c + o; + sendchan(c, ae, nil); +} + +// chansend2(hchan *chan any, elem any) (pres bool); +void +sys·chansend2(Hchan* c, ...) +{ + int32 o; + byte *ae, *ap; + + o = rnd(sizeof(c), c->elemsize); + ae = (byte*)&c + o; + o = rnd(o+c->elemsize, 1); + ap = (byte*)&c + o; + + sendchan(c, ae, ap); +} + +// chanrecv1(hchan *chan any) (elem any); +void +sys·chanrecv1(Hchan* c, ...) +{ + int32 o; + byte *ae; + + o = rnd(sizeof(c), c->elemsize); + ae = (byte*)&c + o; + + chanrecv(c, ae, nil); +} + +// chanrecv2(hchan *chan any) (elem any, pres bool); +void +sys·chanrecv2(Hchan* c, ...) +{ + int32 o; + byte *ae, *ap; + + o = rnd(sizeof(c), c->elemsize); + ae = (byte*)&c + o; + o = rnd(o+c->elemsize, 1); + ap = (byte*)&c + o; + + chanrecv(c, ae, ap); +} + +// chanrecv3(hchan *chan any, elem *any) (pres bool); +void +sys·chanrecv3(Hchan* c, byte* ep, byte pres) +{ + chanrecv(c, ep, &pres); +} + +// newselect(size uint32) (sel *byte); +void +sys·newselect(int32 size, Select *sel) +{ + int32 n; + + n = 0; + if(size > 1) + n = size-1; + + lock(&chanlock); + sel = nil; + if(size >= 1 && size < nelem(selfree)) { + sel = selfree[size]; + if(sel != nil) + selfree[size] = sel->link; + } + unlock(&chanlock); + if(sel == nil) + sel = mal(sizeof(*sel) + n*sizeof(sel->scase[0])); + + sel->tcase = size; + sel->ncase = 0; + FLUSH(&sel); + if(debug) { + prints("newselect s="); + sys·printpointer(sel); + prints(" size="); + sys·printint(size); + prints("\n"); + } +} + +// selectsend(sel *byte, hchan *chan any, elem any) (selected bool); +void +sys·selectsend(Select *sel, Hchan *c, ...) +{ + int32 i, eo; + Scase *cas; + byte *ae; + + // nil cases do not compete + if(c == nil) + return; + + i = sel->ncase; + if(i >= sel->tcase) + throw("selectsend: too many cases"); + sel->ncase = i+1; + cas = sel->scase[i]; + if(cas == nil) { + cas = mal(sizeof *cas + c->elemsize - sizeof(cas->u.elem)); + sel->scase[i] = cas; + } + + cas->pc = sys·getcallerpc(&sel); + cas->chan = c; + + eo = rnd(sizeof(sel), sizeof(c)); + eo = rnd(eo+sizeof(c), c->elemsize); + cas->so = rnd(eo+c->elemsize, 1); + cas->send = 1; + + ae = (byte*)&sel + eo; + c->elemalg->copy(c->elemsize, cas->u.elem, ae); + + if(debug) { + prints("selectsend s="); + sys·printpointer(sel); + prints(" pc="); + sys·printpointer(cas->pc); + prints(" chan="); + sys·printpointer(cas->chan); + prints(" po="); + sys·printint(cas->so); + prints(" send="); + sys·printint(cas->send); + prints("\n"); + } +} + +// selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool); +void +sys·selectrecv(Select *sel, Hchan *c, ...) +{ + int32 i, eo; + Scase *cas; + + // nil cases do not compete + if(c == nil) + return; + + i = sel->ncase; + if(i >= sel->tcase) + throw("selectrecv: too many cases"); + sel->ncase = i+1; + cas = sel->scase[i]; + if(cas == nil) { + cas = mal(sizeof *cas); + sel->scase[i] = cas; + } + cas->pc = sys·getcallerpc(&sel); + cas->chan = c; + + eo = rnd(sizeof(sel), sizeof(c)); + eo = rnd(eo+sizeof(c), sizeof(byte*)); + cas->so = rnd(eo+sizeof(byte*), 1); + cas->send = 0; + cas->u.elemp = *(byte**)((byte*)&sel + eo); + + if(debug) { + prints("selectrecv s="); + sys·printpointer(sel); + prints(" pc="); + sys·printpointer(cas->pc); + prints(" chan="); + sys·printpointer(cas->chan); + prints(" so="); + sys·printint(cas->so); + prints(" send="); + sys·printint(cas->send); + prints("\n"); + } +} + + +// selectdefaul(sel *byte) (selected bool); +void +sys·selectdefault(Select *sel, ...) +{ + int32 i; + Scase *cas; + + i = sel->ncase; + if(i >= sel->tcase) + throw("selectdefault: too many cases"); + sel->ncase = i+1; + cas = sel->scase[i]; + if(cas == nil) { + cas = mal(sizeof *cas); + sel->scase[i] = cas; + } + cas->pc = sys·getcallerpc(&sel); + cas->chan = nil; + + cas->so = rnd(sizeof(sel), 1); + cas->send = 2; + cas->u.elemp = nil; + + if(debug) { + prints("selectdefault s="); + sys·printpointer(sel); + prints(" pc="); + sys·printpointer(cas->pc); + prints(" so="); + sys·printint(cas->so); + prints(" send="); + sys·printint(cas->send); + prints("\n"); + } +} + +// selectgo(sel *byte); +void +sys·selectgo(Select *sel) +{ + uint32 p, o, i; + Scase *cas, *dfl; + Hchan *c; + SudoG *sg; + G *gp; + byte *as; + + if(debug) { + prints("selectgo: sel="); + sys·printpointer(sel); + prints("\n"); + } + + if(sel->ncase < 2) { + if(sel->ncase < 1) + throw("selectgo: no cases"); + // make special case of one. + } + + // select a (relative) prime + for(i=0;; i++) { + p = fastrand1(); + if(gcd(p, sel->ncase) == 1) + break; + if(i > 1000) { + throw("selectgo: failed to select prime"); + } + } + + // select an initial offset + o = fastrand2(); + + p %= sel->ncase; + o %= sel->ncase; + + lock(&chanlock); + +loop: + // pass 1 - look for something already waiting + dfl = nil; + for(i=0; incase; i++) { + cas = sel->scase[o]; + + if(cas->send == 2) { // default + dfl = cas; + goto next1; + } + + c = cas->chan; + if(c->dataqsiz > 0) { + if(cas->send) { + if(c->closed & Wclosed) + goto sclose; + if(c->qcount < c->dataqsiz) + goto asyns; + goto next1; + } + if(c->qcount > 0) + goto asynr; + if(c->closed & Wclosed) + goto rclose; + goto next1; + } + + if(cas->send) { + if(c->closed & Wclosed) + goto sclose; + sg = dequeue(&c->recvq, c); + if(sg != nil) + goto gots; + goto next1; + } + sg = dequeue(&c->sendq, c); + if(sg != nil) + goto gotr; + if(c->closed & Wclosed) + goto rclose; + + next1: + o += p; + if(o >= sel->ncase) + o -= sel->ncase; + } + + if(dfl != nil) { + cas = dfl; + goto retc; + } + + + // pass 2 - enqueue on all chans + for(i=0; incase; i++) { + cas = sel->scase[o]; + c = cas->chan; + + if(c->dataqsiz > 0) { + if(cas->send) { + if(c->qcount < c->dataqsiz) { + prints("selectgo: pass 2 async send\n"); + goto asyns; + } + sg = allocsg(c); + sg->offset = o; + enqueue(&c->sendq, sg); + goto next2; + } + if(c->qcount > 0) { + prints("selectgo: pass 2 async recv\n"); + goto asynr; + } + sg = allocsg(c); + sg->offset = o; + enqueue(&c->recvq, sg); + goto next2; + } + + if(cas->send) { + sg = dequeue(&c->recvq, c); + if(sg != nil) { + prints("selectgo: pass 2 sync send\n"); + g->selgen++; + goto gots; + } + sg = allocsg(c); + sg->offset = o; + c->elemalg->copy(c->elemsize, sg->elem, cas->u.elem); + enqueue(&c->sendq, sg); + goto next2; + } + sg = dequeue(&c->sendq, c); + if(sg != nil) { + prints("selectgo: pass 2 sync recv\n"); + g->selgen++; + goto gotr; + } + sg = allocsg(c); + sg->offset = o; + enqueue(&c->recvq, sg); + + next2: + o += p; + if(o >= sel->ncase) + o -= sel->ncase; + } + + g->param = nil; + g->status = Gwaiting; + unlock(&chanlock); + gosched(); + + lock(&chanlock); + sg = g->param; + if(sg == nil) + goto loop; + + o = sg->offset; + cas = sel->scase[o]; + c = cas->chan; + + if(c->dataqsiz > 0) { +// prints("shouldnt happen\n"); + goto loop; + } + + if(debug) { + prints("wait-return: sel="); + sys·printpointer(sel); + prints(" c="); + sys·printpointer(c); + prints(" cas="); + sys·printpointer(cas); + prints(" send="); + sys·printint(cas->send); + prints(" o="); + sys·printint(o); + prints("\n"); + } + + if(!cas->send) { + if(cas->u.elemp != nil) + c->elemalg->copy(c->elemsize, cas->u.elemp, sg->elem); + } + + freesg(c, sg); + goto retc; + +asynr: + if(cas->u.elemp != nil) + c->elemalg->copy(c->elemsize, cas->u.elemp, c->recvdataq->elem); + c->recvdataq = c->recvdataq->link; + c->qcount--; + sg = dequeue(&c->sendq, c); + if(sg != nil) { + gp = sg->g; + freesg(c, sg); + ready(gp); + } + goto retc; + +asyns: + if(cas->u.elem != nil) + c->elemalg->copy(c->elemsize, c->senddataq->elem, cas->u.elem); + c->senddataq = c->senddataq->link; + c->qcount++; + sg = dequeue(&c->recvq, c); + if(sg != nil) { + gp = sg->g; + freesg(c, sg); + ready(gp); + } + goto retc; + +gotr: + // recv path to wakeup the sender (sg) + if(debug) { + prints("gotr: sel="); + sys·printpointer(sel); + prints(" c="); + sys·printpointer(c); + prints(" o="); + sys·printint(o); + prints("\n"); + } + if(cas->u.elemp != nil) + c->elemalg->copy(c->elemsize, cas->u.elemp, sg->elem); + gp = sg->g; + gp->param = sg; + ready(gp); + goto retc; + +rclose: + if(cas->u.elemp != nil) + c->elemalg->copy(c->elemsize, cas->u.elemp, nil); + c->closed |= Rclosed; + incerr(c); + goto retc; + +gots: + // send path to wakeup the receiver (sg) + if(debug) { + prints("gots: sel="); + sys·printpointer(sel); + prints(" c="); + sys·printpointer(c); + prints(" o="); + sys·printint(o); + prints("\n"); + } + if(c->closed & Wclosed) + goto sclose; + c->elemalg->copy(c->elemsize, sg->elem, cas->u.elem); + gp = sg->g; + gp->param = sg; + ready(gp); + goto retc; + +sclose: + incerr(c); + goto retc; + +retc: + if(sel->ncase >= 1 && sel->ncase < nelem(selfree)) { + sel->link = selfree[sel->ncase]; + selfree[sel->ncase] = sel; + } + unlock(&chanlock); + + sys·setcallerpc(&sel, cas->pc); + as = (byte*)&sel + cas->so; + *as = true; +} + +// closechan(sel *byte); +void +sys·closechan(Hchan *c) +{ + SudoG *sg; + G* gp; + + lock(&chanlock); + incerr(c); + c->closed |= Wclosed; + + // release all readers + for(;;) { + sg = dequeue(&c->recvq, c); + if(sg == nil) + break; + gp = sg->g; + gp->param = nil; + freesg(c, sg); + ready(gp); + } + + // release all writers + for(;;) { + sg = dequeue(&c->sendq, c); + if(sg == nil) + break; + gp = sg->g; + gp->param = nil; + freesg(c, sg); + ready(gp); + } + + unlock(&chanlock); +} + +// closedchan(sel *byte) bool; +void +sys·closedchan(Hchan *c, bool closed) +{ + // test Rclosed + closed = 0; + if(c->closed & Rclosed) + closed = 1; + FLUSH(&closed); +} + +static SudoG* +dequeue(WaitQ *q, Hchan *c) +{ + SudoG *sgp; + +loop: + sgp = q->first; + if(sgp == nil) + return nil; + q->first = sgp->link; + + // if sgp is stale, ignore it + if(sgp->selgen != sgp->g->selgen) { + //prints("INVALID PSEUDOG POINTER\n"); + freesg(c, sgp); + goto loop; + } + + // invalidate any others + sgp->g->selgen++; + return sgp; +} + +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; +} + +static SudoG* +allocsg(Hchan *c) +{ + SudoG* sg; + + sg = c->free; + if(sg != nil) { + c->free = sg->link; + } else + sg = mal(sizeof(*sg) + c->elemsize - sizeof(sg->elem)); + sg->selgen = g->selgen; + sg->g = g; + sg->offset = 0; + sg->isfree = 0; + + return sg; +} + +static void +freesg(Hchan *c, SudoG *sg) +{ + if(sg != nil) { + if(sg->isfree) + throw("chan.freesg: already free"); + sg->isfree = 1; + sg->link = c->free; + c->free = sg; + } +} + +static uint32 +gcd(uint32 u, uint32 v) +{ + for(;;) { + if(u > v) { + if(v == 0) + return u; + u = u%v; + continue; + } + if(u == 0) + return v; + v = v%u; + } +} + +static uint32 +fastrand1(void) +{ + static uint32 x = 0x49f6428aUL; + + x += x; + if(x & 0x80000000L) + x ^= 0x88888eefUL; + return x; +} + +static uint32 +fastrand2(void) +{ + static uint32 x = 0x49f6428aUL; + + x += x; + if(x & 0x80000000L) + x ^= 0xfafd871bUL; + return x; +} diff --git a/src/pkg/runtime/darwin/386/defs.h b/src/pkg/runtime/darwin/386/defs.h new file mode 100644 index 000000000..b66a5d8b4 --- /dev/null +++ b/src/pkg/runtime/darwin/386/defs.h @@ -0,0 +1,229 @@ +// 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, + 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, +}; + +// 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 { + void *__sa_handler; + void *__sa_sigaction; +}; + +typedef struct Sigaction Sigaction; +struct Sigaction { + Sighandler __sigaction_u; + void *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 FPControl FPControl; +struct FPControl { + byte pad0[2]; +}; + +typedef struct FPStatus FPStatus; +struct FPStatus { + byte pad0[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 { + int32 fpu_reserved[2]; + FPControl fpu_fcw; + FPStatus fpu_fsw; + uint8 fpu_ftw; + uint8 fpu_rsrv1; + uint16 fpu_fop; + uint32 fpu_ip; + uint16 fpu_cs; + uint16 fpu_rsrv2; + uint32 fpu_dp; + uint16 fpu_ds; + uint16 fpu_rsrv3; + uint32 fpu_mxcsr; + uint32 fpu_mxcsrmask; + RegMMST fpu_stmm0; + RegMMST fpu_stmm1; + RegMMST fpu_stmm2; + RegMMST fpu_stmm3; + RegMMST fpu_stmm4; + RegMMST fpu_stmm5; + RegMMST fpu_stmm6; + RegMMST fpu_stmm7; + RegXMM fpu_xmm0; + RegXMM fpu_xmm1; + RegXMM fpu_xmm2; + RegXMM fpu_xmm3; + RegXMM fpu_xmm4; + RegXMM fpu_xmm5; + RegXMM fpu_xmm6; + RegXMM fpu_xmm7; + int8 fpu_rsrv4[224]; + int32 fpu_reserved1; +}; + +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; + Ucontext *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 100755 index 000000000..5b52e912c --- /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..3a63c4b38 --- /dev/null +++ b/src/pkg/runtime/darwin/386/signal.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. + +#include "runtime.h" +#include "defs.h" +#include "os.h" +#include "signals.h" + +void +dumpregs(Regs *r) +{ + printf("eax %x\n", r->eax); + printf("ebx %x\n", r->ebx); + printf("ecx %x\n", r->ecx); + printf("edx %x\n", r->edx); + printf("edi %x\n", r->edi); + printf("esi %x\n", r->esi); + printf("ebp %x\n", r->ebp); + printf("esp %x\n", r->esp); + printf("eip %x\n", r->eip); + printf("eflags %x\n", r->eflags); + printf("cs %x\n", r->cs); + printf("fs %x\n", r->fs); + printf("gs %x\n", r->gs); +} + +void +sighandler(int32 sig, Siginfo *info, void *context) +{ + Ucontext *uc; + Mcontext *mc; + Regs *r; + + if(panicking) // traceback already printed + exit(2); + panicking = 1; + + if(sig < 0 || sig >= NSIG){ + printf("Signal %d\n", sig); + }else{ + printf("%s\n", sigtab[sig].name); + } + + uc = context; + mc = uc->uc_mcontext; + r = &mc->ss; + + printf("Faulting address: %p\n", info->si_addr); + printf("pc: %x\n", r->eip); + printf("\n"); + + if(gotraceback()){ + traceback((void*)r->eip, (void*)r->esp, m->curg); + tracebackothers(m->curg); + dumpregs(r); + } + + breakpoint(); + exit(2); +} + +void +sigignore(int32, Siginfo*, void*) +{ +} + +void +signalstack(byte *p, int32 n) +{ + StackT st; + + st.ss_sp = p; + st.ss_size = n; + st.ss_flags = 0; + sigaltstack(&st, nil); +} + +void +initsig(void) +{ + int32 i; + static Sigaction sa; + + sa.sa_flags |= SA_SIGINFO|SA_ONSTACK; + sa.sa_mask = 0; // 0xFFFFFFFFU; + sa.sa_tramp = sigtramp; // sigtramp's job is to call into real handler + for(i = 0; igsignal + MOVL BP, 0(FS) // g = m->gsignal + + MOVL handler+4(FP), DI + MOVL signo+12(FP), AX + MOVL siginfo+16(FP), BX + MOVL context+20(FP), CX + + MOVL AX, 0(SP) + MOVL BX, 4(SP) + MOVL CX, 8(SP) + CALL DI + + MOVL context+20(FP), CX + MOVL style+8(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 notok(SB) + RET + +TEXT sigaltstack(SB),7,$0 + MOVL $53, AX + INT $0x80 + JAE 2(PC) + CALL notok(SB) + RET + +// void bsdthread_create(void *stk, M *m, G *g, void (*fn)(void)) +// System call args are: func arg stack pthread flags. +TEXT bsdthread_create(SB),7,$32 + 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 m+4(FP), BX + MOVL BX, 8(SP) // arg + MOVL stk+0(FP), BX + MOVL BX, 12(SP) // stack + MOVL g+8(FP), BX + MOVL BX, 16(SP) // pthread + MOVL $0x1000000, 20(SP) // flags = PTHREAD_START_CUSTOM + INT $0x80 + JAE 2(PC) + CALL notok(SB) + 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 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 40(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 setldt(SB) + POPL AX + POPL AX + POPL AX + POPAL + SHLL $3, DI // segment# is ldt*8 + 7. + ADDL $7, DI + MOVW DI, FS + + // Now segment is established. Initialize m, g. + MOVL AX, 0(FS) // g + MOVL DX, 4(FS) // m + MOVL BX, 20(DX) // m->procid = thread port (for debuggers) + CALL CX // fn() + CALL exit1(SB) + RET + +// void bsdthread_register(void) +// registers callbacks for threadstart (see bsdthread_create above +// and wqthread and pthsize (not used). returns 0 on success. +TEXT bsdthread_register(SB),7,$40 + MOVL $366, AX + // 0(SP) is where kernel expects caller PC; ignored + MOVL $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) // paranoia + MOVL $0, 20(SP) + MOVL $0, 24(SP) + INT $0x80 + JAE 2(PC) + CALL 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 sysenter(SB),7,$0 + POPL DX + MOVL SP, CX + BYTE $0x0F; BYTE $0x34; // SYSENTER + // returns to DX with SP set to CX + +TEXT mach_msg_trap(SB),7,$0 + MOVL $-31, AX + CALL sysenter(SB) + RET + +TEXT mach_reply_port(SB),7,$0 + MOVL $-26, AX + CALL sysenter(SB) + RET + +TEXT mach_task_self(SB),7,$0 + MOVL $-28, AX + CALL sysenter(SB) + RET + +// Mach provides trap versions of the semaphore ops, +// instead of requiring the use of RPC. + +// uint32 mach_semaphore_wait(uint32) +TEXT mach_semaphore_wait(SB),7,$0 + MOVL $-36, AX + CALL sysenter(SB) + RET + +// uint32 mach_semaphore_timedwait(uint32, uint32, uint32) +TEXT mach_semaphore_timedwait(SB),7,$0 + MOVL $-38, AX + CALL sysenter(SB) + RET + +// uint32 mach_semaphore_signal(uint32) +TEXT mach_semaphore_signal(SB),7,$0 + MOVL $-33, AX + CALL sysenter(SB) + RET + +// uint32 mach_semaphore_signal_all(uint32) +TEXT mach_semaphore_signal_all(SB),7,$0 + MOVL $-34, AX + CALL sysenter(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 setldt(SB),7,$32 + // set up data_desc + LEAL 16(SP), AX // struct data_desc + MOVL $0, 0(AX) + MOVL $0, 4(AX) + + MOVL address+4(FP), BX // aka base + MOVW BX, 2(AX) + SHRL $16, BX + MOVB BX, 4(AX) + SHRL $8, BX + MOVB BX, 7(AX) + + MOVL limit+8(FP), BX + MOVW BX, 0(AX) + SHRL $16, BX + ANDL $0x0F, BX + ORL $0x40, BX // 32-bit operand size + MOVB BX, 6(AX) + + MOVL $0xF2, 5(AX) // r/w data descriptor, dpl=3, present + + // call i386_set_ldt(entry, desc, 1) + MOVL entry+0(FP), BX + MOVL BX, 0(SP) + MOVL AX, 4(SP) + MOVL $1, 8(SP) + CALL i386_set_ldt(SB) + RET + +TEXT i386_set_ldt(SB),7,$0 + MOVL $5, AX + INT $0x82 // sic + JAE 2(PC) + CALL notok(SB) + 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..1076e4c10 --- /dev/null +++ b/src/pkg/runtime/darwin/amd64/defs.h @@ -0,0 +1,244 @@ +// 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, + 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, +}; + +// 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 pad0[4]; +}; + +typedef union Sighandler Sighandler; +union Sighandler { + void *__sa_handler; + void *__sa_sigaction; +}; + +typedef struct Sigaction Sigaction; +struct Sigaction { + Sighandler __sigaction_u; + void *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 FPControl FPControl; +struct FPControl { + byte pad0[2]; +}; + +typedef struct FPStatus FPStatus; +struct FPStatus { + byte pad0[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 { + int32 fpu_reserved[2]; + FPControl fpu_fcw; + FPStatus fpu_fsw; + uint8 fpu_ftw; + uint8 fpu_rsrv1; + uint16 fpu_fop; + uint32 fpu_ip; + uint16 fpu_cs; + uint16 fpu_rsrv2; + uint32 fpu_dp; + uint16 fpu_ds; + uint16 fpu_rsrv3; + uint32 fpu_mxcsr; + uint32 fpu_mxcsrmask; + RegMMST fpu_stmm0; + RegMMST fpu_stmm1; + RegMMST fpu_stmm2; + RegMMST fpu_stmm3; + RegMMST fpu_stmm4; + RegMMST fpu_stmm5; + RegMMST fpu_stmm6; + RegMMST fpu_stmm7; + RegXMM fpu_xmm0; + RegXMM fpu_xmm1; + RegXMM fpu_xmm2; + RegXMM fpu_xmm3; + RegXMM fpu_xmm4; + RegXMM fpu_xmm5; + RegXMM fpu_xmm6; + RegXMM fpu_xmm7; + RegXMM fpu_xmm8; + RegXMM fpu_xmm9; + RegXMM fpu_xmm10; + RegXMM fpu_xmm11; + RegXMM fpu_xmm12; + RegXMM fpu_xmm13; + RegXMM fpu_xmm14; + RegXMM fpu_xmm15; + int8 fpu_rsrv4[96]; + int32 fpu_reserved1; +}; + +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 pad0[4]; +}; + +typedef struct Ucontext Ucontext; +struct Ucontext { + int32 uc_onstack; + uint32 uc_sigmask; + StackT uc_stack; + Ucontext *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..0a0011781 --- /dev/null +++ b/src/pkg/runtime/darwin/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_darwin(SB),7,$-8 + MOVQ $_rt0_amd64(SB), AX + 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..45e5e8d47 --- /dev/null +++ b/src/pkg/runtime/darwin/amd64/signal.c @@ -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. + +#include "runtime.h" +#include "defs.h" +#include "os.h" +#include "signals.h" + +void +dumpregs(Regs *r) +{ + printf("rax %X\n", r->rax); + printf("rbx %X\n", r->rbx); + printf("rcx %X\n", r->rcx); + printf("rdx %X\n", r->rdx); + printf("rdi %X\n", r->rdi); + printf("rsi %X\n", r->rsi); + printf("rbp %X\n", r->rbp); + printf("rsp %X\n", r->rsp); + printf("r8 %X\n", r->r8 ); + printf("r9 %X\n", r->r9 ); + printf("r10 %X\n", r->r10); + printf("r11 %X\n", r->r11); + printf("r12 %X\n", r->r12); + printf("r13 %X\n", r->r13); + printf("r14 %X\n", r->r14); + printf("r15 %X\n", r->r15); + printf("rip %X\n", r->rip); + printf("rflags %X\n", r->rflags); + printf("cs %X\n", r->cs); + printf("fs %X\n", r->fs); + printf("gs %X\n", r->gs); +} + +void +sighandler(int32 sig, Siginfo *info, void *context) +{ + Ucontext *uc; + Mcontext *mc; + Regs *r; + + if(panicking) // traceback already printed + exit(2); + panicking = 1; + + if(sig < 0 || sig >= NSIG){ + printf("Signal %d\n", sig); + }else{ + printf("%s\n", sigtab[sig].name); + } + + uc = context; + mc = uc->uc_mcontext; + r = &mc->ss; + + printf("Faulting address: %p\n", info->si_addr); + printf("pc: %X\n", r->rip); + printf("\n"); + + if(gotraceback()){ + traceback((void*)r->rip, (void*)r->rsp, (void*)r->r15); + tracebackothers((void*)r->r15); + dumpregs(r); + } + + breakpoint(); + exit(2); +} + +void +sigignore(int32, Siginfo*, void*) +{ +} + +void +signalstack(byte *p, int32 n) +{ + StackT st; + + st.ss_sp = p; + st.ss_size = n; + st.ss_flags = 0; + sigaltstack(&st, nil); +} + +void +initsig(void) +{ + int32 i; + static Sigaction sa; + + sa.sa_flags |= SA_SIGINFO|SA_ONSTACK; + sa.sa_mask = 0; // 0xFFFFFFFFU; + sa.sa_tramp = sigtramp; // sigtramp's job is to call into real handler + for(i = 0; igsignal + MOVL DX,0(SP) + MOVQ CX,8(SP) + MOVQ R8,16(SP) + MOVQ R8, 24(SP) // save ucontext + MOVQ SI, 32(SP) // save infostyle + CALL DI + MOVL $(0x2000000+184), AX // sigreturn(ucontext, infostyle) + MOVQ 24(SP), DI // saved ucontext + MOVQ 32(SP), SI // saved infostyle + SYSCALL + INT $3 // not reached + +TEXT sys·mmap(SB),7,$-8 + MOVQ 8(SP), DI // arg 1 addr + MOVL 16(SP), SI // arg 2 len + MOVL 20(SP), DX // arg 3 prot + MOVL 24(SP), R10 // arg 4 flags + MOVL 28(SP), R8 // arg 5 fid + MOVL 32(SP), R9 // arg 6 offset + MOVL $(0x2000000+197), AX // syscall entry + SYSCALL + JCC 2(PC) + CALL notok(SB) + RET + +TEXT notok(SB),7,$-8 + MOVL $0xf1, BP + MOVQ BP, (BP) + RET + +TEXT sys·memclr(SB),7,$-8 + MOVQ 8(SP), DI // arg 1 addr + MOVL 16(SP), CX // arg 2 count + ADDL $7, CX + SHRL $3, CX + MOVQ $0, AX + CLD + REP + STOSQ + RET + +TEXT sys·getcallerpc+0(SB),7,$0 + MOVQ x+0(FP),AX // addr of first arg + MOVQ -8(AX),AX // get calling pc + RET + +TEXT sys·setcallerpc+0(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 sigaltstack(SB),7,$-8 + MOVQ new+8(SP), DI + MOVQ old+16(SP), SI + MOVQ $(0x2000000+53), AX + SYSCALL + JCC 2(PC) + CALL notok(SB) + RET + +// void bsdthread_create(void *stk, M *m, G *g, void (*fn)(void)) +TEXT bsdthread_create(SB),7,$-8 + // 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 m+16(SP), SI // "arg" + MOVQ stk+8(SP), DX // stack + MOVQ g+24(SP), R10 // "pthread" +// TODO(rsc): why do we get away with 0 flags here but not on 386? + MOVQ $0, R8 // flags + MOVQ $(0x2000000+360), AX // bsdthread_create + SYSCALL + JCC 2(PC) + CALL notok(SB) + RET + +// The thread that bsdthread_create creates starts executing here, +// because we registered this function using bsdthread_register +// at startup. +// DI = "pthread" (= g) +// SI = mach thread port +// DX = "func" (= fn) +// CX = "arg" (= m) +// R8 = stack +// R9 = flags (= 0) +// SP = stack - C_64_REDZONE_LEN (= stack - 128) +TEXT bsdthread_start(SB),7,$-8 + MOVQ CX, R14 // m + MOVQ DI, R15 // g + MOVQ SI, 24(R14) // thread port is m->procid + CALL DX // fn + CALL exit1(SB) + RET + +// void bsdthread_register(void) +// registers callbacks for threadstart (see bsdthread_create above +// and wqthread and pthsize (not used). returns 0 on success. +TEXT bsdthread_register(SB),7,$-8 + MOVQ $bsdthread_start(SB), DI // threadstart + MOVQ $0, SI // wqthread, not used by us + MOVQ $0, DX // pthsize, not used by us + MOVQ $(0x2000000+366), AX // bsdthread_register + SYSCALL + JCC 2(PC) + CALL notok(SB) + RET + +// Mach system calls use 0x1000000 instead of the BSD's 0x2000000. + +// uint32 mach_msg_trap(void*, uint32, uint32, uint32, uint32, uint32, uint32) +TEXT mach_msg_trap(SB),7,$0 + 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 mach_task_self(SB),7,$0 + MOVL $(0x1000000+28), AX // task_self_trap + SYSCALL + RET + +TEXT mach_thread_self(SB),7,$0 + MOVL $(0x1000000+27), AX // thread_self_trap + SYSCALL + RET + +TEXT 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 mach_semaphore_wait(SB),7,$0 + MOVL 8(SP), DI + MOVL $(0x1000000+36), AX // semaphore_wait_trap + SYSCALL + RET + +// uint32 mach_semaphore_timedwait(uint32, uint32, uint32) +TEXT mach_semaphore_timedwait(SB),7,$0 + 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 mach_semaphore_signal(SB),7,$0 + MOVL 8(SP), DI + MOVL $(0x1000000+33), AX // semaphore_signal_trap + SYSCALL + RET + +// uint32 mach_semaphore_signal_all(uint32) +TEXT mach_semaphore_signal_all(SB),7,$0 + MOVL 8(SP), DI + MOVL $(0x1000000+34), AX // semaphore_signal_all_trap + SYSCALL + RET + diff --git a/src/pkg/runtime/darwin/defs.c b/src/pkg/runtime/darwin/defs.c new file mode 100644 index 000000000..1ed662957 --- /dev/null +++ b/src/pkg/runtime/darwin/defs.c @@ -0,0 +1,104 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* + * Input to godefs. + * + godefs -f -m64 defs.c >amd64/defs.h + godefs defs.c >386/defs.h + */ + +#define __DARWIN_UNIX03 0 + +#include +#include +#include +#include +#include +#include + +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, + + $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, +}; + +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 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/os.h b/src/pkg/runtime/darwin/os.h new file mode 100644 index 000000000..2a3ca87bd --- /dev/null +++ b/src/pkg/runtime/darwin/os.h @@ -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. + +void bsdthread_create(void*, M*, G*, void(*)(void)); +void bsdthread_register(void); +int32 mach_msg_trap(MachHeader*, int32, uint32, uint32, uint32, uint32, uint32); +uint32 mach_reply_port(void); +void mach_semacquire(uint32); +uint32 mach_semcreate(void); +void mach_semdestroy(uint32); +void mach_semrelease(uint32); +void mach_semreset(uint32); +uint32 mach_task_self(void); +uint32 mach_task_self(void); +uint32 mach_thread_self(void); +uint32 mach_thread_self(void); + +struct Sigaction; +void sigaction(int64, struct Sigaction*, struct Sigaction*); + +struct StackT; +void sigaltstack(struct StackT*, struct StackT*); +void sigtramp(void); diff --git a/src/pkg/runtime/darwin/signals.h b/src/pkg/runtime/darwin/signals.h new file mode 100644 index 000000000..8cca361f7 --- /dev/null +++ b/src/pkg/runtime/darwin/signals.h @@ -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. + +#define C SigCatch +#define I SigIgnore +#define R SigRestart + +static SigTab sigtab[] = { + /* 0 */ 0, "SIGNONE: no trap", + /* 1 */ 0, "SIGHUP: terminal line hangup", + /* 2 */ 0, "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, "SIGFPE: floating-point exception", + /* 9 */ 0, "SIGKILL: kill", + /* 10 */ C, "SIGBUS: bus error", + /* 11 */ C, "SIGSEGV: segmentation violation", + /* 12 */ C, "SIGSYS: bad system call", + /* 13 */ I, "SIGPIPE: write to broken pipe", + /* 14 */ 0, "SIGALRM: alarm clock", + /* 15 */ 0, "SIGTERM: termination", + /* 16 */ 0, "SIGURG: urgent condition on socket", + /* 17 */ 0, "SIGSTOP: stop", + /* 18 */ 0, "SIGTSTP: keyboard stop", + /* 19 */ 0, "SIGCONT: continue after stop", + /* 20 */ I+R, "SIGCHLD: child status has changed", + /* 21 */ 0, "SIGTTIN: background read from tty", + /* 22 */ 0, "SIGTTOU: background write to tty", + /* 23 */ 0, "SIGIO: i/o now possible", + /* 24 */ 0, "SIGXCPU: cpu limit exceeded", + /* 25 */ 0, "SIGXFSZ: file size limit exceeded", + /* 26 */ 0, "SIGVTALRM: virtual alarm clock", + /* 27 */ 0, "SIGPROF: profiling alarm clock", + /* 28 */ I+R, "SIGWINCH: window size change", + /* 29 */ 0, "SIGINFO: status request from keyboard", + /* 30 */ 0, "SIGUSR1: user-defined signal 1", + /* 31 */ 0, "SIGUSR2: user-defined signal 2", +}; +#undef C +#undef I +#undef R + +#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..3a982471a --- /dev/null +++ b/src/pkg/runtime/darwin/thread.c @@ -0,0 +1,441 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "runtime.h" +#include "defs.h" +#include "os.h" + +static void +unimplemented(int8 *name) +{ + prints(name); + 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 = mach_semcreate(); + if(!cas(psema, 0, sema)){ + // Someone else filled it in. Use theirs. + mach_semdestroy(sema); + return; + } +} + + +// Atomic add and return new value. +static uint32 +xadd(uint32 volatile *val, int32 delta) +{ + uint32 oval, nval; + + for(;;){ + oval = *val; + nval = oval + delta; + if(cas(val, oval, nval)) + return nval; + } +} + + +// 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. +// +// Note that semaphores are never destroyed (the kernel +// will clean up when the process exits). We assume for now +// that Locks are only used for long-lived structures like M and G. + +void +lock(Lock *l) +{ + if(m->locks < 0) + throw("lock count"); + m->locks++; + + // Allocate semaphore if needed. + if(l->sema == 0) + initsema(&l->sema); + + if(xadd(&l->key, 1) > 1) // someone else has it; wait + mach_semacquire(l->sema); +} + +void +unlock(Lock *l) +{ + m->locks--; + if(m->locks < 0) + throw("lock count"); + + if(xadd(&l->key, -1) > 0) // someone else is waiting + mach_semrelease(l->sema); +} + + +// 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 +usemacquire(Usema *s) +{ + if((int32)xadd(&s->u, -1) < 0) + mach_semacquire(s->k); +} + +void +usemrelease(Usema *s) +{ + if((int32)xadd(&s->u, 1) <= 0) + mach_semrelease(s->k); +} + + +// Event notifications. +void +noteclear(Note *n) +{ + n->wakeup = 0; +} + +void +notesleep(Note *n) +{ + if(n->sema.k == 0) + initsema(&n->sema.k); + while(!n->wakeup) + usemacquire(&n->sema); +} + +void +notewakeup(Note *n) +{ + if(n->sema.k == 0) + initsema(&n->sema.k); + n->wakeup = 1; + usemrelease(&n->sema); +} + + +// BSD interface for threading. +void +osinit(void) +{ + // Register our thread-creation callback (see {amd64,386}/sys.s). + bsdthread_register(); +} + +void +newosproc(M *m, G *g, void *stk, void (*fn)(void)) +{ + // printf("newosproc m=%p g=%p stk=%p fn=%p\n", m, g, stk, fn); + m->tls[0] = m->id; // so 386 asm can find it + bsdthread_create(stk, m, g, fn); +} + +// Called to initialize a new m (including the bootstrap m). +void +minit(void) +{ + // Initialize signal handling. + m->gsignal = malg(32*1024); // OS X wants >=8K, Linux >=2K + signalstack(m->gsignal->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) +{ + printf("mach error %s: %d\n", fn, r); + 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 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 = 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; + prints("send:\t"); + for(i=0; imsgh_size/sizeof(p[0]); i++){ + prints(" "); + sys·printpointer((void*)p[i]); + if(i%8 == 7) + prints("\n\t"); + } + if(i%8) + prints("\n"); + } + + ret = mach_msg(h, MACH_SEND_MSG|MACH_RCV_MSG, + h->msgh_size, maxsize, port, 0, 0); + if(ret != 0){ + if(DebugMach){ + prints("mach_msg error "); + sys·printint(ret); + prints("\n"); + } + return ret; + } + + if(DebugMach){ + p = (uint32*)h; + prints("recv:\t"); + for(i=0; imsgh_size/sizeof(p[0]); i++){ + prints(" "); + sys·printpointer((void*)p[i]); + if(i%8 == 7) + prints("\n\t"); + } + if(i%8) + prints("\n"); + } + + if(h->msgh_id != id+Reply){ + if(DebugMach){ + prints("mach_msg reply id mismatch "); + sys·printint(h->msgh_id); + prints(" != "); + sys·printint(id+Reply); + 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){ + prints("mig result "); + sys·printint(c->code); + prints("\n"); + } + return c->code; + } + + if(h->msgh_size != rxsize){ + if(DebugMach){ + prints("mach_msg reply size mismatch "); + sys·printint(h->msgh_size); + prints(" != "); + sys·printint(rxsize); + 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 +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 = 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 +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 = 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){ + macherror(r, "semaphore_destroy"); + } +} + +// The other calls have simple system call traps in sys.s +int32 mach_semaphore_wait(uint32 sema); +int32 mach_semaphore_timedwait(uint32 sema, uint32 sec, uint32 nsec); +int32 mach_semaphore_signal(uint32 sema); +int32 mach_semaphore_signal_all(uint32 sema); + +void +mach_semacquire(uint32 sem) +{ + int32 r; + + while((r = mach_semaphore_wait(sem)) != 0) { + if(r == KERN_ABORTED) // interrupted + continue; + macherror(r, "semaphore_wait"); + } +} + +void +mach_semrelease(uint32 sem) +{ + int32 r; + + while((r = mach_semaphore_signal(sem)) != 0) { + if(r == KERN_ABORTED) // interrupted + continue; + macherror(r, "semaphore_signal"); + } +} + diff --git a/src/pkg/runtime/extern.go b/src/pkg/runtime/extern.go new file mode 100644 index 000000000..6fb5756d6 --- /dev/null +++ b/src/pkg/runtime/extern.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. + +/* + The runtime package contains operations that interact with Go's runtime system, + such as functions to control goroutines. + */ +package runtime + +// These functions are implemented in the base runtime library, ../../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. +func Goexit() + +// Breakpoint() executes a breakpoint trap. +func Breakpoint() + +// Caller reports file and line number information about function invocations on +// the calling goroutine's stack. The argument is the number of stack frames to +// ascend, with 1 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(n int) (pc uintptr, file string, line int, ok bool) diff --git a/src/pkg/runtime/float.c b/src/pkg/runtime/float.c new file mode 100644 index 000000000..5122f359a --- /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 +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 +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 +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 +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 +isInf(float64 f, int32 sign) +{ + uint64 x; + + x = float64tobits(f); + if(sign == 0) + return x == uvinf || x == uvneginf; + if(sign > 0) + return x == uvinf; + return x == uvneginf; +} + +float64 +NaN(void) +{ + return float64frombits(uvnan); +} + +bool +isNaN(float64 f) +{ + uint64 x; + + x = float64tobits(f); + return ((uint32)(x>>52) & 0x7FF) == 0x7FF && !isInf(f, 0); +} + +float64 +Inf(int32 sign) +{ + if(sign >= 0) + return float64frombits(uvinf); + else + return float64frombits(uvneginf); +} + +enum +{ + MASK = 0x7ffL, + SHIFT = 64-11-1, + BIAS = 1022L, +}; + +float64 +frexp(float64 d, int32 *ep) +{ + uint64 x; + + if(d == 0) { + *ep = 0; + return 0; + } + x = float64tobits(d); + *ep = (int32)((x >> SHIFT) & MASK) - BIAS; + x &= ~((uint64)MASK << SHIFT); + x |= (uint64)BIAS << SHIFT; + return float64frombits(x); +} + +float64 +ldexp(float64 d, int32 e) +{ + uint64 x; + + if(d == 0) + return 0; + x = float64tobits(d); + e += (int32)(x >> SHIFT) & MASK; + if(e <= 0) + return 0; /* underflow */ + if(e >= MASK){ /* overflow */ + if(d < 0) + return Inf(-1); + return Inf(1); + } + x &= ~((uint64)MASK << SHIFT); + x |= (uint64)e << SHIFT; + return float64frombits(x); +} + +float64 +modf(float64 d, float64 *ip) +{ + float64 dd; + uint64 x; + int32 e; + + if(d < 1) { + if(d < 0) { + d = modf(-d, ip); + *ip = -*ip; + return -d; + } + *ip = 0; + return d; + } + + x = 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 = float64frombits(x); + *ip = dd; + return d - dd; +} + diff --git a/src/pkg/runtime/float_go.cgo b/src/pkg/runtime/float_go.cgo new file mode 100644 index 000000000..518d55950 --- /dev/null +++ b/src/pkg/runtime/float_go.cgo @@ -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. + +package math + +#include "runtime.h" + +func Frexp(f float64) (frac float64, exp int32) { + frac = frexp(f, &exp); +} + +func Ldexp(frac float64, exp int32) (f float64) { + f = ldexp(frac, exp); +} + +func Modf(f float64) (integer float64, frac float64) { + frac = modf(f, &integer); +} + +func IsInf(f float64, sign int32) (is bool) { + is = isInf(f, sign); +} + +func IsNaN(f float64) (is bool) { + is = isNaN(f); +} + +func Inf(sign int32) (f float64) { + f = Inf(sign); +} + +func NaN() (f float64) { + f = NaN(); +} + +func Float32bits(f float32) (b uint32) { + b = float32tobits(f); +} + +func Float64bits(f float64) (b uint64) { + b = float64tobits(f); +} + +func Float32frombits(b uint32) (f float32) { + f = float32frombits(b); +} + +func Float64frombits(b uint64) (f float64) { + f = float64frombits(b); +} + diff --git a/src/pkg/runtime/hashmap.c b/src/pkg/runtime/hashmap.c new file mode 100644 index 000000000..b3022ca14 --- /dev/null +++ b/src/pkg/runtime/hashmap.c @@ -0,0 +1,954 @@ +// Copyright 2009 The Go Authors. 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" + +/* Return a pointer to the struct/union of type "type" + whose "field" field is addressed by pointer "p". */ + + +struct hash { /* 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 */ + 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; + uint32 ko; + uint32 vo; + uint32 po; + 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 (struct hash *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 (struct hash *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 = 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, + struct hash *h, void *data, void **pres); + +static void +hash_conv (struct hash *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 (struct hash *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); +} + +int32 +hash_lookup (struct hash *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); +} + +int32 +hash_remove (struct hash *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->keysize, 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, + struct hash *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); + } + } +} + +int32 +hash_insert (struct hash *h, void *data, void **pres) +{ + int32 rc = hash_insert_internal (&h->st, 0, (*h->data_hash) (h->keysize, data), h, data, pres); + + h->count += (rc == 0); /* increment count if element didn't previously exist */ + return (rc); +} + +uint32 +hash_count (struct hash *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; +} + +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; + } + } +} + +void +hash_iter_init (struct hash *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; +} + +void +hash_destroy (struct hash *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++; + } +} + +void +hash_visit (struct hash *h, void (*data_visit) (void *arg, int32 level, void *data), void *arg) +{ + hash_visit_internal (h->st, 0, 0, data_visit, arg); +} + +// +/// interfaces to go runtime +// + +static void +donothing(uint32 s, void *a, void *b) +{ + USED(s); + USED(a); + USED(b); +} + +typedef struct hash Hmap; +static int32 debug = 0; + +// newmap(keysize uint32, valsize uint32, +// keyalg uint32, valalg uint32, +// hint uint32) (hmap *map[any]any); +void +sys·newmap(uint32 keysize, uint32 valsize, + uint32 keyalg, uint32 valalg, uint32 hint, + Hmap* ret) +{ + Hmap *h; + + if(keyalg >= nelem(algarray) || algarray[keyalg].hash == nohash) { + printf("map(keyalg=%d)\n", keyalg); + throw("sys·newmap: unsupported map key type"); + } + + if(valalg >= nelem(algarray)) { + printf("map(valalg=%d)\n", valalg); + throw("sys·newmap: unsupported map value type"); + } + + h = mal(sizeof(*h)); + + // 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 >= sizeof(void*)) + h->datavo = rnd(keysize, sizeof(void*)); + + hash_init(h, h->datavo+valsize, + algarray[keyalg].hash, + algarray[keyalg].equal, + donothing, + hint); + + h->keysize = keysize; + h->valsize = valsize; + h->keyalg = &algarray[keyalg]; + h->valalg = &algarray[valalg]; + + // these calculations are compiler dependent. + // figure out offsets of map call arguments. + h->ko = rnd(sizeof(h), keysize); + h->vo = rnd(h->ko+keysize, valsize); + h->po = rnd(h->vo+valsize, 1); + + ret = h; + FLUSH(&ret); + + if(debug) { + prints("newmap: map="); + sys·printpointer(h); + prints("; keysize="); + sys·printint(keysize); + prints("; valsize="); + sys·printint(valsize); + prints("; keyalg="); + sys·printint(keyalg); + prints("; valalg="); + sys·printint(valalg); + prints("; ko="); + sys·printint(h->ko); + prints("; vo="); + sys·printint(h->vo); + prints("; po="); + sys·printint(h->po); + prints("\n"); + } +} + +// mapaccess1(hmap *map[any]any, key any) (val any); +void +sys·mapaccess1(Hmap *h, ...) +{ + byte *ak, *av; + byte *res; + int32 hit; + + ak = (byte*)&h + h->ko; + av = (byte*)&h + h->vo; + + res = nil; + hit = hash_lookup(h, ak, (void**)&res); + if(!hit) + throw("sys·mapaccess1: key not in map"); + h->valalg->copy(h->valsize, av, res+h->datavo); + + if(debug) { + prints("sys·mapaccess1: map="); + sys·printpointer(h); + prints("; key="); + h->keyalg->print(h->keysize, ak); + prints("; val="); + h->valalg->print(h->valsize, av); + prints("; hit="); + sys·printint(hit); + prints("; res="); + sys·printpointer(res); + prints("\n"); + } +} + +// mapaccess2(hmap *map[any]any, key any) (val any, pres bool); +void +sys·mapaccess2(Hmap *h, ...) +{ + byte *ak, *av, *ap; + byte *res; + int32 hit; + + ak = (byte*)&h + h->ko; + av = (byte*)&h + h->vo; + ap = (byte*)&h + h->po; + + res = nil; + hit = hash_lookup(h, ak, (void**)&res); + if(!hit) { + *ap = false; + h->valalg->copy(h->valsize, av, nil); + } else { + *ap = true; + h->valalg->copy(h->valsize, av, res+h->datavo); + } + + if(debug) { + prints("sys·mapaccess2: map="); + sys·printpointer(h); + prints("; key="); + h->keyalg->print(h->keysize, ak); + prints("; val="); + h->valalg->print(h->valsize, av); + prints("; hit="); + sys·printint(hit); + prints("; res="); + sys·printpointer(res); + prints("; pres="); + sys·printbool(*ap); + prints("\n"); + } +} + +static void +mapassign(Hmap *h, byte *ak, byte *av) +{ + byte *res; + int32 hit; + + res = nil; + hit = hash_insert(h, ak, (void**)&res); + h->keyalg->copy(h->keysize, res, ak); + h->valalg->copy(h->valsize, res+h->datavo, av); + + if(debug) { + prints("mapassign: map="); + sys·printpointer(h); + prints("; key="); + h->keyalg->print(h->keysize, ak); + prints("; val="); + h->valalg->print(h->valsize, av); + prints("; hit="); + sys·printint(hit); + prints("; res="); + sys·printpointer(res); + prints("\n"); + } +} + +// mapassign1(hmap *map[any]any, key any, val any); +void +sys·mapassign1(Hmap *h, ...) +{ + byte *ak, *av; + + ak = (byte*)&h + h->ko; + av = (byte*)&h + h->vo; + + mapassign(h, ak, av); +} + +// mapassign2(hmap *map[any]any, key any, val any, pres bool); +void +sys·mapassign2(Hmap *h, ...) +{ + byte *ak, *av, *ap; + byte *res; + int32 hit; + + ak = (byte*)&h + h->ko; + av = (byte*)&h + h->vo; + ap = (byte*)&h + h->po; + + if(*ap == true) { + // assign + mapassign(h, ak, av); + return; + } + + // delete + hit = hash_remove(h, ak, (void**)&res); + + if(debug) { + prints("mapassign2: map="); + sys·printpointer(h); + prints("; key="); + h->keyalg->print(h->keysize, ak); + prints("; hit="); + sys·printint(hit); + prints("; res="); + sys·printpointer(res); + prints("\n"); + } +} + +// mapiterinit(hmap *map[any]any, hiter *any); +void +sys·mapiterinit(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) { + prints("sys·mapiterinit: map="); + sys·printpointer(h); + prints("; iter="); + sys·printpointer(it); + prints("; data="); + sys·printpointer(it->data); + prints("\n"); + } +} + +// mapiternext(hiter *any); +void +sys·mapiternext(struct hash_iter *it) +{ + it->data = hash_next(it); + if(debug) { + prints("sys·mapiternext: iter="); + sys·printpointer(it); + prints("; data="); + sys·printpointer(it->data); + prints("\n"); + } +} + +// mapiter1(hiter *any) (key any); +void +sys·mapiter1(struct hash_iter *it, ...) +{ + Hmap *h; + byte *ak, *res; + + h = it->h; + ak = (byte*)&it + h->ko; + + res = it->data; + if(res == nil) + throw("sys·mapiter2: key:val nil pointer"); + + h->keyalg->copy(h->keysize, ak, res); + + if(debug) { + prints("mapiter2: iter="); + sys·printpointer(it); + prints("; map="); + sys·printpointer(h); + prints("\n"); + } +} + +// mapiter2(hiter *any) (key any, val any); +void +sys·mapiter2(struct hash_iter *it, ...) +{ + Hmap *h; + byte *ak, *av, *res; + + h = it->h; + ak = (byte*)&it + h->ko; + av = (byte*)&it + h->vo; + + res = it->data; + if(res == nil) + throw("sys·mapiter2: key:val nil pointer"); + + h->keyalg->copy(h->keysize, ak, res); + h->valalg->copy(h->valsize, av, res+h->datavo); + + if(debug) { + prints("mapiter2: iter="); + sys·printpointer(it); + prints("; map="); + sys·printpointer(h); + prints("\n"); + } +} diff --git a/src/pkg/runtime/hashmap.h b/src/pkg/runtime/hashmap.h new file mode 100644 index 000000000..e8bcfab29 --- /dev/null +++ b/src/pkg/runtime/hashmap.h @@ -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 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 mal +#define free(a) USED(a) +#define offsetof(s,m) (uint32)(&(((s*)0)->m)) +#define memset(a,b,c) sys·memclr((byte*)(a), (uint32)(c)) +#define memmove(a,b,c) mmov((byte*)(a),(byte*)(b),(uint32)(c)) +#define memcpy(a,b,c) mcpy((byte*)(a),(byte*)(b),(uint32)(c)) +#define assert(a) if(!(a)) throw("assert") + +struct hash; /* 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 hash *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..6c933b1b2 --- /dev/null +++ b/src/pkg/runtime/iface.c @@ -0,0 +1,906 @@ +// Copyright 2009 The Go Authors. 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" + +int32 iface_debug = 0; + +typedef struct Sigt Sigt; +typedef struct Sigi Sigi; +typedef struct Itype Itype; + +/* + * the layout of Iface, Sigt and Sigi are known to the compiler + */ +struct Sigt +{ + byte* name; // name of basic type + Sigt* link; // for linking into hash tables + uint32 thash; // hash of type + uint32 mhash; // hash of methods + uint16 width; // width of base type in bytes + uint16 alg; // algorithm + // note: on amd64 there is a 32-bit pad here. + struct { + byte* fname; + uint32 fhash; // hash of type + uint32 offset; // offset of substruct + void (*fun)(void); + } meth[1]; // one or more - last name is nil +}; + +struct Sigi +{ + byte* name; + uint32 hash; + uint32 size; // number of methods + struct { + byte* fname; + uint32 fhash; + uint32 perm; // location of fun in Sigt + } meth[1]; // [size+1] - last name is nil +}; + +struct Itype +{ + Sigi* sigi; + Sigt* sigt; + Itype* link; + int32 bad; + int32 unused; + void (*fun[])(void); +}; + +static Iface niliface; +static Eface nileface; + +static Itype* hash[1009]; +static Lock ifacelock; + +Sigi sigi·empty[2] = { (byte*)"interface { }" }; + +static void +printsigi(Sigi *si) +{ + int32 i; + byte *name; + + sys·printpointer(si); + prints("{"); + prints((int8*)si->name); + prints(":"); + for(i=0;; i++) { + name = si->meth[i].fname; + if(name == nil) + break; + prints("["); + sys·printint(i); + prints("]\""); + prints((int8*)name); + prints("\""); + sys·printint(si->meth[i].fhash%999); + prints("/"); + sys·printint(si->meth[i].perm); + } + prints("}"); +} + +static void +printsigt(Sigt *st) +{ + int32 i; + byte *name; + + sys·printpointer(st); + prints("{"); + prints((int8*)st->name); + prints(":"); + sys·printint(st->thash%999); // type hash + prints(","); + sys·printint(st->mhash%999); // method hash + prints(","); + sys·printint(st->width); // width + prints(","); + sys·printint(st->alg); // algorithm + for(i=0;; i++) { + name = st->meth[i].fname; + if(name == nil) + break; + prints("["); + sys·printint(i); + prints("]\""); + prints((int8*)name); + prints("\""); + sys·printint(st->meth[i].fhash%999); + prints("/"); + sys·printint(st->meth[i].offset); + prints("/"); + sys·printpointer(st->meth[i].fun); + } + prints("}"); +} + +static void +printiface(Iface i) +{ + prints("("); + sys·printpointer(i.type); + prints(","); + sys·printpointer(i.data); + prints(")"); +} + +static void +printeface(Eface e) +{ + prints("("); + sys·printpointer(e.type); + prints(","); + sys·printpointer(e.data); + prints(")"); +} + +static Itype* +itype(Sigi *si, Sigt *st, int32 canfail) +{ + int32 locked; + int32 nt, ni; + uint32 ihash, h; + byte *sname, *iname; + Itype *m; + + if(si->size == 0) + throw("internal error - misuse of itype"); + + // easy case + if(st->meth[0].fname == nil) { + if(canfail) + return nil; + iname = si->meth[0].fname; + goto throw1; + } + + // compiler has provided some good hash codes for us. + h = 0; + if(si) + h += si->hash; + if(st) { + h += st->thash; + h += st->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) + lock(&ifacelock); + for(m=hash[h]; m!=nil; m=m->link) { + if(m->sigi == si && m->sigt == st) { + 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 + // give a better error. + goto throw; + } + } + if(locked) + unlock(&ifacelock); + return m; + } + } + } + + ni = si->size; + m = malloc(sizeof(*m) + ni*sizeof(m->fun[0])); + m->sigi = si; + m->sigt = st; + +throw: + nt = 0; + for(ni=0;; ni++) { + iname = si->meth[ni].fname; + if(iname == nil) + break; + + // pick up next name from + // interface signature + ihash = si->meth[ni].fhash; + + for(;; nt++) { + // pick up and compare next name + // from structure signature + sname = st->meth[nt].fname; + if(sname == nil) { + if(!canfail) { + throw1: + printf("cannot convert type %s to interface %s: missing method %s\n", + st->name, si->name, iname); + if(iface_debug) { + prints("interface"); + printsigi(si); + prints("\ntype"); + printsigt(st); + prints("\n"); + } + throw("interface conversion"); + return nil; // not reached + } + m->bad = 1; + m->link = hash[h]; + hash[h] = m; + if(locked) + unlock(&ifacelock); + return nil; + } + if(ihash == st->meth[nt].fhash && strcmp(sname, iname) == 0) + break; + } + m->fun[si->meth[ni].perm] = st->meth[nt].fun; + } + m->link = hash[h]; + hash[h] = m; + if(locked) + unlock(&ifacelock); + + return m; +} + +static void +copyin(Sigt *st, void *src, void **dst) +{ + int32 wid, alg; + void *p; + + wid = st->width; + alg = st->alg; + + if(wid <= sizeof(*dst)) + algarray[alg].copy(wid, dst, src); + else { + p = mal(wid); + algarray[alg].copy(wid, p, src); + *dst = p; + } +} + +static void +copyout(Sigt *st, void **src, void *dst) +{ + int32 wid, alg; + + wid = st->width; + alg = st->alg; + + if(wid <= sizeof(*src)) + algarray[alg].copy(wid, dst, src); + else + algarray[alg].copy(wid, dst, *src); +} + +// ifaceT2I(sigi *byte, sigt *byte, elem any) (ret any); +#pragma textflag 7 +void +sys·ifaceT2I(Sigi *si, Sigt *st, ...) +{ + byte *elem; + Iface *ret; + int32 wid; + + elem = (byte*)(&st+1); + wid = st->width; + ret = (Iface*)(elem + rnd(wid, sizeof(uintptr))); + + ret->type = itype(si, st, 0); + copyin(st, elem, &ret->data); +} + +// ifaceT2E(sigt *byte, elem any) (ret any); +#pragma textflag 7 +void +sys·ifaceT2E(Sigt *st, ...) +{ + byte *elem; + Eface *ret; + int32 wid; + + elem = (byte*)(&st+1); + wid = st->width; + ret = (Eface*)(elem + rnd(wid, sizeof(uintptr))); + + ret->type = st; + copyin(st, elem, &ret->data); +} + +// ifaceI2T(sigt *byte, iface any) (ret any); +#pragma textflag 7 +void +sys·ifaceI2T(Sigt *st, Iface i, ...) +{ + Itype *im; + byte *ret; + + ret = (byte*)(&i+1); + + im = i.type; + if(im == nil) { + printf("interface is nil, not %s\n", st->name); + throw("interface conversion"); + } + if(im->sigt != st) { + printf("%s is %s, not %s\n", im->sigi->name, im->sigt->name, st->name); + throw("interface conversion"); + } + copyout(st, &i.data, ret); +} + +// ifaceI2T2(sigt *byte, iface any) (ret any, ok bool); +#pragma textflag 7 +void +sys·ifaceI2T2(Sigt *st, Iface i, ...) +{ + byte *ret; + bool *ok; + Itype *im; + int32 wid; + + ret = (byte*)(&i+1); + wid = st->width; + ok = (bool*)(ret+rnd(wid, 1)); + + im = i.type; + if(im == nil || im->sigt != st) { + *ok = false; + sys·memclr(ret, wid); + return; + } + + *ok = true; + copyout(st, &i.data, ret); +} + +// ifaceE2T(sigt *byte, iface any) (ret any); +#pragma textflag 7 +void +sys·ifaceE2T(Sigt *st, Eface e, ...) +{ + Sigt *t; + byte *ret; + + ret = (byte*)(&e+1); + + t = e.type; + if(t == nil) { + printf("interface is nil, not %s\n", st->name); + throw("interface conversion"); + } + if(t != st) { + printf("interface is %s, not %s\n", t->name, st->name); + throw("interface conversion"); + } + copyout(st, &e.data, ret); +} + +// ifaceE2T2(sigt *byte, iface any) (ret any, ok bool); +#pragma textflag 7 +void +sys·ifaceE2T2(Sigt *st, Eface e, ...) +{ + byte *ret; + bool *ok; + Sigt *t; + int32 wid; + + ret = (byte*)(&e+1); + wid = st->width; + ok = (bool*)(ret+rnd(wid, 1)); + + t = e.type; + if(t != st) { + *ok = false; + sys·memclr(ret, wid); + return; + } + + *ok = true; + copyout(st, &e.data, ret); +} + +// ifaceI2E(sigi *byte, iface any) (ret any); +// TODO(rsc): Move to back end, throw away function. +void +sys·ifaceI2E(Iface i, Eface ret) +{ + Itype *im; + + ret.data = i.data; + im = i.type; + if(im == nil) + ret.type = nil; + else + ret.type = im->sigt; + FLUSH(&ret); +} + +// ifaceI2I(sigi *byte, iface any) (ret any); +// called only for implicit (no type assertion) conversions +void +sys·ifaceI2I(Sigi *si, Iface i, Iface ret) +{ + Itype *im; + + im = i.type; + if(im == nil) { + // If incoming interface is uninitialized (zeroed) + // make the outgoing interface zeroed as well. + ret = niliface; + } else { + ret = i; + if(im->sigi != si) + ret.type = itype(si, im->sigt, 0); + } + + FLUSH(&ret); +} + +// ifaceI2Ix(sigi *byte, iface any) (ret any); +// called only for explicit conversions (with type assertion). +void +sys·ifaceI2Ix(Sigi *si, Iface i, Iface ret) +{ + Itype *im; + + im = i.type; + if(im == nil) { + // explicit conversions require non-nil interface value. + printf("interface is nil, not %s\n", si->name); + throw("interface conversion"); + } else { + ret = i; + if(im->sigi != si) + ret.type = itype(si, im->sigt, 0); + } + + FLUSH(&ret); +} + +// ifaceI2I2(sigi *byte, iface any) (ret any, ok bool); +void +sys·ifaceI2I2(Sigi *si, Iface i, Iface ret, bool ok) +{ + Itype *im; + + im = i.type; + if(im == nil) { + // If incoming interface is nil, the conversion fails. + ret = niliface; + ok = false; + } else { + ret = i; + ok = true; + if(im->sigi != si) { + ret.type = itype(si, im->sigt, 1); + if(ret.type == nil) { + ret = niliface; + ok = false; + } + } + } + + FLUSH(&ret); + FLUSH(&ok); +} + +// ifaceE2I(sigi *byte, iface any) (ret any); +// Called only for explicit conversions (with type assertion). +void +sys·ifaceE2I(Sigi *si, Eface e, Iface ret) +{ + Sigt *t; + + t = e.type; + if(t == nil) { + // explicit conversions require non-nil interface value. + printf("interface is nil, not %s\n", si->name); + throw("interface conversion"); + } else { + ret.data = e.data; + ret.type = itype(si, t, 0); + } + FLUSH(&ret); +} + +// ifaceE2I2(sigi *byte, iface any) (ret any, ok bool); +void +sys·ifaceE2I2(Sigi *si, Eface e, Iface ret, bool ok) +{ + Sigt *t; + + t = e.type; + ok = true; + if(t == nil) { + // If incoming interface is nil, the conversion fails. + ret = niliface; + ok = false; + } else { + ret.data = e.data; + ret.type = itype(si, t, 1); + if(ret.type == nil) { + ret = niliface; + ok = false; + } + } + FLUSH(&ret); + FLUSH(&ok); +} + +static uintptr +ifacehash1(void *data, Sigt *sigt) +{ + int32 alg, wid; + + if(sigt == nil) + return 0; + + alg = sigt->alg; + wid = sigt->width; + if(algarray[alg].hash == nohash) { + // calling nohash will throw too, + // but we can print a better error. + printf("hash of unhashable type %s\n", sigt->name); + if(alg == AFAKE) + throw("fake interface hash"); + throw("interface hash"); + } + if(wid <= sizeof(data)) + return algarray[alg].hash(wid, &data); + return algarray[alg].hash(wid, data); +} + +uintptr +ifacehash(Iface a) +{ + if(a.type == nil) + return 0; + return ifacehash1(a.data, a.type->sigt); +} + +uintptr +efacehash(Eface a) +{ + return ifacehash1(a.data, a.type); +} + +static bool +ifaceeq1(void *data1, void *data2, Sigt *sigt) +{ + int32 alg, wid; + + alg = sigt->alg; + wid = sigt->width; + + if(algarray[alg].equal == noequal) { + // calling noequal will throw too, + // but we can print a better error. + printf("comparing uncomparable type %s\n", sigt->name); + if(alg == AFAKE) + throw("fake interface compare"); + throw("interface compare"); + } + + if(wid <= sizeof(data1)) + return algarray[alg].equal(wid, &data1, &data2); + return algarray[alg].equal(wid, data1, data2); +} + +bool +ifaceeq(Iface i1, Iface i2) +{ + if(i1.type != i2.type) + return false; + if(i1.type == nil) + return true; + return ifaceeq1(i1.data, i2.data, i1.type->sigt); +} + +bool +efaceeq(Eface e1, Eface e2) +{ + 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 +sys·ifaceeq(Iface i1, Iface i2, bool ret) +{ + ret = ifaceeq(i1, i2); + FLUSH(&ret); +} + +// efaceeq(i1 any, i2 any) (ret bool) +void +sys·efaceeq(Eface e1, Eface e2, bool ret) +{ + ret = efaceeq(e1, e2); + FLUSH(&ret); +} + +// ifacethash(i1 any) (ret uint32); +void +sys·ifacethash(Iface i1, uint32 ret) +{ + Itype *im; + Sigt *st; + + ret = 0; + im = i1.type; + if(im != nil) { + st = im->sigt; + if(st != nil) + ret = st->thash; + } + FLUSH(&ret); +} + +// efacethash(e1 any) (ret uint32) +void +sys·efacethash(Eface e1, uint32 ret) +{ + Sigt *st; + + ret = 0; + st = e1.type; + if(st != nil) + ret = st->thash; + FLUSH(&ret); +} + +void +sys·printiface(Iface i) +{ + printiface(i); +} + +void +sys·printeface(Eface e) +{ + printeface(e); +} + +void +unsafe·Reflect(Eface i, uint64 retit, String rettype, bool retindir) +{ + int32 wid; + + if(i.type == nil) { + retit = 0; + rettype = emptystring; + retindir = false; + } else { + retit = (uint64)i.data; + rettype = gostring(i.type->name); + wid = i.type->width; + retindir = wid > sizeof(i.data); + } + FLUSH(&retit); + FLUSH(&rettype); + FLUSH(&retindir); +} + +extern Sigt *gotypesigs[]; +extern int32 ngotypesigs; + + +// The reflection library can ask to unreflect on a type +// that has never been used, so we don't have a signature for it. +// For concreteness, suppose a program does +// +// type T struct{ x []int } +// var t T; +// v := reflect.NewValue(v); +// vv := v.Field(0); +// if s, ok := vv.Interface().(string) { +// print("first field is string"); +// } +// +// vv.Interface() returns the result of sys.Unreflect with +// a typestring of "[]int". If []int is not used with interfaces +// in the rest of the program, there will be no signature in gotypesigs +// for "[]int", so we have to invent one. The requirements +// on the fake signature are: +// +// (1) any interface conversion using the signature will fail +// (2) calling unsafe.Reflect() returns the args to unreflect +// (3) the right algorithm type is used, for == and map insertion +// +// (1) is ensured by the fact that we allocate a new Sigt, +// so it will necessarily be != any Sigt in gotypesigs. +// (2) is ensured by storing the type string in the signature +// and setting the width to force the correct value of the bool indir. +// (3) is ensured by sniffing the type string. +// +// Note that (1) is correct behavior: if the program had tested +// for .([]int) instead of .(string) above, then there would be a +// signature with type string "[]int" in gotypesigs, and unreflect +// wouldn't call fakesigt. + +static Sigt* fake[1009]; +static int32 nfake; + +enum +{ + SizeofInt = 4, + SizeofFloat = 4, +}; + +// Table of prefixes of names of comparable types. +static struct { + int8 *s; + int8 n; + int8 alg; + int8 w; +} cmp[] = +{ + // basic types + "int", 3+1, AMEM, SizeofInt, // +1 is NUL + "uint", 4+1, AMEM, SizeofInt, + "int8", 4+1, AMEM, 1, + "uint8", 5+1, AMEM, 1, + "int16", 5+1, AMEM, 2, + "uint16", 6+1, AMEM, 2, + "int32", 5+1, AMEM, 4, + "uint32", 6+1, AMEM, 4, + "int64", 5+1, AMEM, 8, + "uint64", 6+1, AMEM, 8, + "uintptr", 7+1, AMEM, sizeof(uintptr), + "float", 5+1, AMEM, SizeofFloat, + "float32", 7+1, AMEM, 4, + "float64", 7+1, AMEM, 8, + "bool", 4+1, AMEM, sizeof(bool), + + // string compare is special + "string", 6+1, ASTRING, sizeof(String), + + // generic types, identified by prefix + "*", 1, AMEM, sizeof(uintptr), + "chan ", 5, AMEM, sizeof(uintptr), + "func(", 5, AMEM, sizeof(uintptr), + "map[", 4, AMEM, sizeof(uintptr), +}; + +static Sigt* +fakesigt(String type, bool indir) +{ + Sigt *sigt; + uint32 h; + int32 i, locked; + + h = 0; + for(i=0; ilink) { + // don't need to compare indir. + // same type string but different indir will have + // different hashes. + if(mcmp(sigt->name, type.str, type.len) == 0) + if(sigt->name[type.len] == '\0') { + if(locked) + unlock(&ifacelock); + return sigt; + } + } + } + + sigt = malloc(sizeof(*sigt)); + sigt->name = malloc(type.len + 1); + mcpy(sigt->name, type.str, type.len); + + sigt->alg = AFAKE; + sigt->width = 1; // small width + if(indir) + sigt->width = 2*sizeof(niliface.data); // big width + + // AFAKE is like ANOEQ; check whether the type + // should have a more capable algorithm. + for(i=0; iname, (byte*)cmp[i].s, cmp[i].n) == 0) { + sigt->alg = cmp[i].alg; + sigt->width = cmp[i].w; + break; + } + } + + sigt->link = fake[h]; + fake[h] = sigt; + + unlock(&ifacelock); + return sigt; +} + +static int32 +cmpstringchars(String a, uint8 *b) +{ + int32 i; + byte c1, c2; + + for(i=0;; i++) { + c1 = 0; + if(i < a.len) + c1 = a.str[i]; + c2 = b[i]; + if(c1 < c2) + return -1; + if(c1 > c2) + return +1; + if(c1 == 0) + return 0; + } +} + +static Sigt* +findtype(String type, bool indir) +{ + int32 i, lo, hi, m; + + lo = 0; + hi = ngotypesigs; + while(lo < hi) { + m = lo + (hi - lo)/2; + i = cmpstringchars(type, gotypesigs[m]->name); + if(i == 0) + return gotypesigs[m]; + if(i < 0) + hi = m; + else + lo = m+1; + } + return fakesigt(type, indir); +} + + +void +unsafe·Unreflect(uint64 it, String type, bool indir, Eface ret) +{ + Sigt *sigt; + + ret = nileface; + + if(cmpstring(type, emptystring) == 0) + goto out; + + if(type.len > 10 && mcmp(type.str, (byte*)"interface ", 10) == 0) { + printf("unsafe.Unreflect: cannot put %S in interface\n", type); + throw("unsafe.Unreflect"); + } + + // if we think the type should be indirect + // and caller does not, play it safe, return nil. + sigt = findtype(type, indir); + if(indir != (sigt->width > sizeof(ret.data))) + goto out; + + ret.type = sigt; + ret.data = (void*)it; + +out: + FLUSH(&ret); +} + diff --git a/src/pkg/runtime/linux/386/defs.h b/src/pkg/runtime/linux/386/defs.h new file mode 100755 index 000000000..112fc7b09 --- /dev/null +++ b/src/pkg/runtime/linux/386/defs.h @@ -0,0 +1,136 @@ +// godefs -f -m32 -f -I/home/rsc/pub/linux-2.6/arch/x86/include -f -I/home/rsc/pub/linux-2.6/include 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, + SA_RESTART = 0x10000000, + SA_ONSTACK = 0x8000000, + SA_RESTORER = 0x4000000, + SA_SIGINFO = 0x4, +}; + +// 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 _anon_[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 { + byte _u[4]; + uint32 sa_mask; + uint32 sa_flags; + void *sa_restorer; +}; + +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; +}; +#pragma pack off diff --git a/src/pkg/runtime/linux/386/rt0.s b/src/pkg/runtime/linux/386/rt0.s new file mode 100755 index 000000000..7717c37e8 --- /dev/null +++ b/src/pkg/runtime/linux/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_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..7dfca6bb4 --- /dev/null +++ b/src/pkg/runtime/linux/386/signal.c @@ -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 "runtime.h" +#include "defs.h" +#include "signals.h" +#include "os.h" + +void +dumpregs(Sigcontext *r) +{ + printf("eax %X\n", r->eax); + printf("ebx %X\n", r->ebx); + printf("ecx %X\n", r->ecx); + printf("edx %X\n", r->edx); + printf("edi %X\n", r->edi); + printf("esi %X\n", r->esi); + printf("ebp %X\n", r->ebp); + printf("esp %X\n", r->esp); + printf("eip %X\n", r->eip); + printf("eflags %X\n", r->eflags); + printf("cs %X\n", r->cs); + printf("fs %X\n", r->fs); + printf("gs %X\n", r->gs); +} + +/* + * This assembler routine takes the args from registers, puts them on the stack, + * and calls sighandler(). + */ +extern void sigtramp(void); +extern void sigignore(void); // just returns +extern void sigreturn(void); // calls sigreturn + +void +sighandler(int32 sig, Siginfo* info, void* context) +{ + Ucontext *uc; + Sigcontext *sc; + + if(panicking) // traceback already printed + exit(2); + panicking = 1; + + uc = context; + sc = &uc->uc_mcontext; + + if(sig < 0 || sig >= NSIG) + printf("Signal %d\n", sig); + else + printf("%s\n", sigtab[sig].name); + + printf("Faulting address: %p\n", *(void**)info->_sifields); + printf("pc=%X\n", sc->eip); + printf("\n"); + + if(gotraceback()){ + traceback((void*)sc->eip, (void*)sc->esp, m->curg); + tracebackothers(m->curg); + dumpregs(sc); + } + + breakpoint(); + exit(2); +} + +void +signalstack(byte *p, int32 n) +{ + Sigaltstack st; + + st.ss_sp = p; + st.ss_size = n; + st.ss_flags = 0; + sigaltstack(&st, nil); +} + +void +initsig(void) +{ + static Sigaction sa; + + int32 i; + sa.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESTORER; + sa.sa_mask = 0xFFFFFFFFFFFFFFFFULL; + sa.sa_restorer = (void*)sigreturn; + for(i = 0; igsignal + MOVL AX, 0(FS) // g = m->gsignal + JMP sighandler(SB) + +TEXT sigignore(SB),7,$0 + RET + +TEXT sigreturn(SB),7,$0 + MOVL 4(FS), BP // m + MOVL 32(BP), BP // m->curg + MOVL BP, 0(FS) // g = m->curg + MOVL $173, AX // rt_sigreturn + INT $0x80 + INT $3 // not reached + RET + +TEXT sys·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 2(PC) + INT $3 + RET + +// int64 futex(int32 *uaddr, int32 op, int32 val, +// struct timespec *timeout, int32 *uaddr2, int32 val2); +TEXT 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 + +// int64 clone(int32 flags, void *stack, M *m, G *g, void (*fn)(void)); +TEXT clone(SB),7,$0 + MOVL $120, AX // clone + MOVL flags+4(SP), BX + MOVL stack+8(SP), CX + + // Copy m, g, fn off parent stack for use by child. + SUBL $12, CX + MOVL m+12(SP), DX + MOVL DX, 0(CX) + MOVL g+16(SP), DX + MOVL DX, 4(CX) + MOVL fn+20(SP), DX + MOVL DX, 8(CX) + + MOVL $120, AX + INT $0x80 + + // In parent, return. + CMPL AX, $0 + JEQ 2(PC) + RET + + // In child, set up new stack, etc. + MOVL 0(CX), BX // m + MOVL 12(AX), AX // fs (= m->cret) + MOVW AX, FS + MOVL 8(CX), DX // fn + ADDL $12, CX + MOVL CX, SP + + // fn is now on top of stack. + + // initialize m->procid to Linux tid + MOVL $224, AX + INT $0x80 + MOVL AX, 20(BX) + + // call fn + CALL DX + + // It shouldn't return; if it does, exit. + MOVL $111, DI + MOVL $1, AX + INT $0x80 + JMP -3(PC) // keep exiting + +TEXT 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 + +// // fake the per-goroutine and per-mach registers +// LEAL m0(SB), + +// TODO(rsc): move to linux.s +// +// 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 setldt(SB),7,$32 + // set up user_desc + LEAL 16(SP), AX // struct user_desc + MOVL entry+0(FP), BX // entry + MOVL BX, 0(AX) + MOVL address+4(FP), BX // base address + MOVL BX, 4(AX) + MOVL limit+8(FP), BX // limit + MOVL BX, 8(AX) + MOVL $(SEG_32BIT|USEABLE|CONTENTS_DATA), 12(AX) // flag bits + + // call modify_ldt + MOVL $123, 0(SP) // syscall - modify_ldt + MOVL $1, 4(SP) // func = 1 (write) + MOVL AX, 8(SP) // user_desc + MOVL $16, 12(SP) // sizeof(user_desc) + CALL syscall(SB) + 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..43b047523 --- /dev/null +++ b/src/pkg/runtime/linux/amd64/defs.h @@ -0,0 +1,175 @@ +// 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, + SA_RESTART = 0x10000000, + SA_ONSTACK = 0x8000000, + SA_RESTORER = 0x4000000, + SA_SIGINFO = 0x4, +}; + +// 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 pad0[4]; + byte _sifields[112]; +}; +#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 Sigaltstack Sigaltstack; +struct Sigaltstack { + void *ss_sp; + int32 ss_flags; + byte pad0[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..55be5bcee --- /dev/null +++ b/src/pkg/runtime/linux/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_linux(SB),7,$-8 + MOVQ $_rt0_amd64(SB), AX + 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..55215176d --- /dev/null +++ b/src/pkg/runtime/linux/amd64/signal.c @@ -0,0 +1,112 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "runtime.h" +#include "defs.h" +#include "signals.h" +#include "os.h" + +void +dumpregs(Sigcontext *r) +{ + printf("rax %X\n", r->rax); + printf("rbx %X\n", r->rbx); + printf("rcx %X\n", r->rcx); + printf("rdx %X\n", r->rdx); + printf("rdi %X\n", r->rdi); + printf("rsi %X\n", r->rsi); + printf("rbp %X\n", r->rbp); + printf("rsp %X\n", r->rsp); + printf("r8 %X\n", r->r8 ); + printf("r9 %X\n", r->r9 ); + printf("r10 %X\n", r->r10); + printf("r11 %X\n", r->r11); + printf("r12 %X\n", r->r12); + printf("r13 %X\n", r->r13); + printf("r14 %X\n", r->r14); + printf("r15 %X\n", r->r15); + printf("rip %X\n", r->rip); + printf("rflags %X\n", r->eflags); + printf("cs %X\n", (uint64)r->cs); + printf("fs %X\n", (uint64)r->fs); + printf("gs %X\n", (uint64)r->gs); +} + +/* + * This assembler routine takes the args from registers, puts them on the stack, + * and calls sighandler(). + */ +extern void sigtramp(void); +extern void sigignore(void); // just returns +extern void sigreturn(void); // calls sigreturn + +void +sighandler(int32 sig, Siginfo* info, void* context) +{ + Ucontext *uc; + Mcontext *mc; + Sigcontext *sc; + + if(panicking) // traceback already printed + exit(2); + panicking = 1; + + uc = context; + mc = &uc->uc_mcontext; + sc = (Sigcontext*)mc; // same layout, more conveient names + + if(sig < 0 || sig >= NSIG) + printf("Signal %d\n", sig); + else + printf("%s\n", sigtab[sig].name); + + printf("Faulting address: %p\n", *(void**)info->_sifields); + printf("PC=%X\n", sc->rip); + printf("\n"); + + if(gotraceback()){ + traceback((void*)sc->rip, (void*)sc->rsp, (void*)sc->r15); + tracebackothers((void*)sc->r15); + dumpregs(sc); + } + + breakpoint(); + exit(2); +} + +void +signalstack(byte *p, int32 n) +{ + Sigaltstack st; + + st.ss_sp = p; + st.ss_size = n; + st.ss_flags = 0; + sigaltstack(&st, nil); +} + +void +initsig(void) +{ + static Sigaction sa; + + int32 i; + sa.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESTORER; + sa.sa_mask = 0xFFFFFFFFFFFFFFFFULL; + sa.sa_restorer = (void*)sigreturn; + for(i = 0; igsignal + MOVQ DI,0(SP) + MOVQ SI,8(SP) + MOVQ DX,16(SP) + CALL sighandler(SB) + RET + +TEXT sigignore(SB),7,$0 + RET + +TEXT sigreturn(SB),7,$0 + MOVL $15, AX // rt_sigreturn + SYSCALL + INT $3 // not reached + +TEXT sys·mmap(SB),7,$0-32 + MOVQ 8(SP), DI + MOVQ $0, SI + MOVL 16(SP), SI + MOVL 20(SP), DX + MOVL 24(SP), R10 + MOVL 28(SP), R8 + MOVL 32(SP), R9 + + MOVL $9, AX // syscall entry + SYSCALL + CMPQ AX, $0xfffffffffffff001 + JLS 2(PC) + CALL notok(SB) + RET + +TEXT notok(SB),7,$0 + MOVQ $0xf1, BP + MOVQ BP, (BP) + RET + +TEXT sys·memclr(SB),7,$0-16 + MOVQ 8(SP), DI // arg 1 addr + MOVL 16(SP), CX // arg 2 count (cannot be zero) + ADDL $7, CX + SHRL $3, CX + MOVQ $0, AX + CLD + REP + STOSQ + RET + +TEXT sys·getcallerpc+0(SB),7,$0 + MOVQ x+0(FP),AX // addr of first arg + MOVQ -8(AX),AX // get calling pc + RET + +TEXT sys·setcallerpc+0(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 + +// int64 futex(int32 *uaddr, int32 op, int32 val, +// struct timespec *timeout, int32 *uaddr2, int32 val2); +TEXT 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 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 m+24(SP), R8 + MOVQ g+32(SP), R9 + MOVQ fn+40(SP), R12 + + MOVL $56, AX + SYSCALL + + // In parent, return. + CMPQ AX, $0 + JEQ 2(PC) + RET + + // In child, set up new stack + MOVQ SI, SP + MOVQ R8, R14 // m + MOVQ R9, R15 // g + + // Initialize m->procid to Linux tid + MOVL $186, AX // gettid + SYSCALL + MOVQ AX, 24(R14) + + // Call fn + CALL R12 + + // It shouldn't return. If it does, exi + MOVL $111, DI + MOVL $60, AX + SYSCALL + JMP -3(PC) // keep exiting + +TEXT sigaltstack(SB),7,$-8 + MOVQ new+8(SP), DI + MOVQ old+16(SP), SI + MOVQ $131, AX + SYSCALL + CMPQ AX, $0xfffffffffffff001 + JLS 2(PC) + CALL notok(SB) + 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..caad66989 --- /dev/null +++ b/src/pkg/runtime/linux/arm/defs.h @@ -0,0 +1,27 @@ +// godefs -carm-gcc -f -I/usr/local/google/src/linux-2.6.28/arch/arm/include -f -I/usr/local/google/src/linux-2.6.28/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, + SA_RESTART = 0x10000000, + SA_ONSTACK = 0x8000000, + SA_RESTORER = 0x4000000, + SA_SIGINFO = 0x4, +}; + +// Types +#pragma pack on + +typedef struct Timespec Timespec; +struct Timespec { + int32 tv_sec; + int32 tv_nsec; +}; +#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..024547ddd --- /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..024018d5a --- /dev/null +++ b/src/pkg/runtime/linux/arm/signal.c @@ -0,0 +1,4 @@ +// Copyright 2009 The Go 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/linux/arm/sys.s b/src/pkg/runtime/linux/arm/sys.s new file mode 100644 index 000000000..f5db32305 --- /dev/null +++ b/src/pkg/runtime/linux/arm/sys.s @@ -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. + +// +// System calls and other sys.stuff for arm, Linux +// + +TEXT write(SB),7,$0 + MOVW 4(SP), R0 + MOVW 8(SP), R1 + MOVW 12(SP), R2 + SWI $0x00900004 // syscall write + RET + diff --git a/src/pkg/runtime/linux/defs.c b/src/pkg/runtime/linux/defs.c new file mode 100644 index 000000000..35fa02953 --- /dev/null +++ b/src/pkg/runtime/linux/defs.c @@ -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. + +/* + * 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 +#include +#include + +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, + + $SA_RESTART = SA_RESTART, + $SA_ONSTACK = SA_ONSTACK, + $SA_RESTORER = SA_RESTORER, + $SA_SIGINFO = SA_SIGINFO, +}; + +typedef struct timespec $Timespec; +typedef struct timeval $Timeval; +typedef struct sigaction $Sigaction; +typedef siginfo_t $Siginfo; diff --git a/src/pkg/runtime/linux/defs1.c b/src/pkg/runtime/linux/defs1.c new file mode 100644 index 000000000..0fe3506ad --- /dev/null +++ b/src/pkg/runtime/linux/defs1.c @@ -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. + +/* + * Input to godefs + godefs -f -m64 defs.c >amd64/defs.h + godefs -f -m64 defs1.c >>amd64/defs.h + */ + +#include + +typedef __sigset_t $Usigset; +typedef struct _libc_fpxreg $Fpxreg; +typedef struct _libc_xmmreg $Xmmreg; +typedef struct _libc_fpstate $Fpstate; +typedef struct _libc_fpreg $Fpreg; +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..aa0331a37 --- /dev/null +++ b/src/pkg/runtime/linux/defs2.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. + +/* + * 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 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 +#include +#include +#include + +/* +#include +#include +#include +*/ + +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, + + $SA_RESTART = SA_RESTART, + $SA_ONSTACK = SA_ONSTACK, + $SA_RESTORER = SA_RESTORER, + $SA_SIGINFO = SA_SIGINFO, +}; + +typedef struct _fpreg $Fpreg; +typedef struct _fpxreg $Fpxreg; +typedef struct _xmmreg $Xmmreg; +typedef struct _fpstate $Fpstate; +typedef struct timespec $Timespec; +typedef struct timeval $Timeval; +typedef struct sigaction $Sigaction; +typedef siginfo_t $Siginfo; +typedef struct sigaltstack $Sigaltstack; +typedef struct sigcontext $Sigcontext; +typedef struct ucontext $Ucontext; + diff --git a/src/pkg/runtime/linux/defs_arm.c b/src/pkg/runtime/linux/defs_arm.c new file mode 100644 index 000000000..eaec05154 --- /dev/null +++ b/src/pkg/runtime/linux/defs_arm.c @@ -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. + +/* + * Input to godefs + godefs -carm-gcc -f -I/usr/local/google/src/linux-2.6.28/arch/arm/include -f + -I/usr/local/google/src/linux-2.6.28/include defs_arm.c >arm/defs.h + + * Another input file for ARM defs.h + */ + +#include +#include +#include +#include + +/* +#include +#include +#include +*/ + +#include + +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, + + $SA_RESTART = SA_RESTART, + $SA_ONSTACK = SA_ONSTACK, + $SA_RESTORER = SA_RESTORER, + $SA_SIGINFO = SA_SIGINFO +}; + + + + +//typedef struct _fpreg $Fpreg; +//typedef struct _fpxreg $Fpxreg; +//typedef struct _xmmreg $Xmmreg; +//typedef struct _fpstate $Fpstate; +typedef struct timespec $Timespec; +//typedef struct timeval $Timeval; +// typedef struct sigaction $Sigaction; +// typedef siginfo_t $Siginfo; +// typedef struct sigaltstack $Sigaltstack; +// typedef struct sigcontext $Sigcontext; +// typedef struct ucontext $Ucontext; diff --git a/src/pkg/runtime/linux/os.h b/src/pkg/runtime/linux/os.h new file mode 100644 index 000000000..c61619367 --- /dev/null +++ b/src/pkg/runtime/linux/os.h @@ -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. + +// Linux-specific system calls +int64 futex(uint32*, int32, uint32, Timespec*, uint32*, uint32); +int64 clone(int32, void*, M*, G*, void(*)(void)); + +struct Sigaction; +void rt_sigaction(int64, struct Sigaction*, void*, uint64); diff --git a/src/pkg/runtime/linux/signals.h b/src/pkg/runtime/linux/signals.h new file mode 100644 index 000000000..8f1112b99 --- /dev/null +++ b/src/pkg/runtime/linux/signals.h @@ -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. + +#define C SigCatch +#define I SigIgnore +#define R SigRestart + +static SigTab sigtab[] = { + /* 0 */ 0, "SIGNONE: no trap", + /* 1 */ 0, "SIGHUP: terminal line hangup", + /* 2 */ 0, "SIGINT: interrupt", + /* 3 */ C, "SIGQUIT: quit", + /* 4 */ C, "SIGILL: illegal instruction", + /* 5 */ C, "SIGTRAP: trace trap", + /* 6 */ C, "SIGABRT: abort", + /* 7 */ C, "SIGBUS: bus error", + /* 8 */ C, "SIGFPE: floating-point exception", + /* 9 */ 0, "SIGKILL: kill", + /* 10 */ 0, "SIGUSR1: user-defined signal 1", + /* 11 */ C, "SIGSEGV: segmentation violation", + /* 12 */ 0, "SIGUSR2: user-defined signal 2", + /* 13 */ I, "SIGPIPE: write to broken pipe", + /* 14 */ 0, "SIGALRM: alarm clock", + /* 15 */ 0, "SIGTERM: termination", + /* 16 */ 0, "SIGSTKFLT: stack fault", + /* 17 */ I+R, "SIGCHLD: child status has changed", + /* 18 */ 0, "SIGCONT: continue", + /* 19 */ 0, "SIGSTOP: stop, unblockable", + /* 20 */ 0, "SIGTSTP: keyboard stop", + /* 21 */ 0, "SIGTTIN: background read from tty", + /* 22 */ 0, "SIGTTOU: background write to tty", + /* 23 */ 0, "SIGURG: urgent condition on socket", + /* 24 */ 0, "SIGXCPU: cpu limit exceeded", + /* 25 */ 0, "SIGXFSZ: file size limit exceeded", + /* 26 */ 0, "SIGVTALRM: virtual alarm clock", + /* 27 */ 0, "SIGPROF: profiling alarm clock", + /* 28 */ I+R, "SIGWINCH: window size change", + /* 29 */ 0, "SIGIO: i/o now possible", + /* 30 */ 0, "SIGPWR: power failure restart", + /* 31 */ C, "SIGSYS: bad system call", +}; +#undef C +#undef I +#undef R + +#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..cc9ba161b --- /dev/null +++ b/src/pkg/runtime/linux/thread.c @@ -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. + +#include "runtime.h" +#include "defs.h" +#include "signals.h" +#include "os.h" + +// 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 one thread sleeping on addr. +// Futexsleep is allowed to wake up spuriously. + +enum +{ + 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) +{ + int64 ret; + + ret = futex(addr, FUTEX_WAIT, val, &longtime, nil, 0); + if(ret >= 0 || ret == -EAGAIN || ret == -EINTR) + return; + + prints("futexsleep addr="); + sys·printpointer(addr); + prints(" val="); + sys·printint(val); + prints(" returned "); + sys·printint(ret); + prints("\n"); + *(int32*)0x1005 = 0x1005; +} + +// If any procs are sleeping on addr, wake up at least one. +static void +futexwakeup(uint32 *addr) +{ + int64 ret; + + ret = futex(addr, FUTEX_WAKE, 1, 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. + + prints("futexwakeup addr="); + sys·printpointer(addr); + prints(" returned "); + sys·printint(ret); + prints("\n"); + *(int32*)0x1006 = 0x1006; +} + + +// Lock and unlock. +// +// The lock state is a single 32-bit word that holds +// a 31-bit count of threads waiting for the lock +// and a single bit (the low bit) saying whether the lock is held. +// The uncontended case runs entirely in user space. +// When contention is detected, we defer to the kernel (futex). +// +// A reminder: compare-and-swap cas(addr, old, new) does +// if(*addr == old) { *addr = new; return 1; } +// else return 0; +// but atomically. + +static void +futexlock(Lock *l) +{ + uint32 v; + +again: + v = l->key; + if((v&1) == 0){ + if(cas(&l->key, v, v|1)){ + // Lock wasn't held; we grabbed it. + return; + } + goto again; + } + + // Lock was held; try to add ourselves to the waiter count. + if(!cas(&l->key, v, v+2)) + goto again; + + // We're accounted for, now sleep in the kernel. + // + // We avoid the obvious lock/unlock race because + // the kernel won't put us to sleep if l->key has + // changed underfoot and is no longer v+2. + // + // We only really care that (v&1) == 1 (the lock is held), + // and in fact there is a futex variant that could + // accomodate that check, but let's not get carried away.) + futexsleep(&l->key, v+2); + + // We're awake: remove ourselves from the count. + for(;;){ + v = l->key; + if(v < 2) + throw("bad lock key"); + if(cas(&l->key, v, v-2)) + break; + } + + // Try for the lock again. + goto again; +} + +static void +futexunlock(Lock *l) +{ + uint32 v; + + // Atomically get value and clear lock bit. +again: + v = l->key; + if((v&1) == 0) + throw("unlock of unlocked lock"); + if(!cas(&l->key, v, v&~1)) + goto again; + + // If there were waiters, wake one. + if(v & ~1) + futexwakeup(&l->key); +} + +void +lock(Lock *l) +{ + if(m->locks < 0) + throw("lock count"); + m->locks++; + futexlock(l); +} + +void +unlock(Lock *l) +{ + m->locks--; + if(m->locks < 0) + throw("lock count"); + futexunlock(l); +} + + +// One-time notifications. +// +// Since the lock/unlock implementation already +// takes care of sleeping in the kernel, we just reuse it. +// (But it's a weird use, so it gets its own interface.) +// +// We use a lock to represent the event: +// unlocked == event has happened. +// Thus the lock starts out locked, and to wait for the +// event you try to lock the lock. To signal the event, +// you unlock the lock. + +void +noteclear(Note *n) +{ + n->lock.key = 0; // memset(n, 0, sizeof *n) + futexlock(&n->lock); +} + +void +notewakeup(Note *n) +{ + futexunlock(&n->lock); +} + +void +notesleep(Note *n) +{ + futexlock(&n->lock); + futexunlock(&n->lock); // Let other sleepers find out too. +} + + +// 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 +newosproc(M *m, G *g, void *stk, void (*fn)(void)) +{ + int64 ret; + int32 flags; + + /* + * note: strace gets confused if we use CLONE_PTRACE here. + */ + flags = CLONE_PARENT /* getppid doesn't change in child */ + | 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 */ + ; + + if(0){ + prints("newosproc stk="); + sys·printpointer(stk); + prints(" m="); + sys·printpointer(m); + prints(" g="); + sys·printpointer(g); + prints(" fn="); + sys·printpointer(fn); + prints(" clone="); + sys·printpointer(clone); + prints("\n"); + } + + ret = clone(flags, stk, m, g, fn); + if(ret < 0) + *(int32*)123 = 123; +} + +void +osinit(void) +{ +} + +// Called to initialize a new m (including the bootstrap m). +void +minit(void) +{ + // Initialize signal handling. + m->gsignal = malg(32*1024); // OS X wants >=8K, Linux >=2K + signalstack(m->gsignal->stackguard, 32*1024); +} diff --git a/src/pkg/runtime/malloc.c b/src/pkg/runtime/malloc.c new file mode 100644 index 000000000..81cdfb300 --- /dev/null +++ b/src/pkg/runtime/malloc.c @@ -0,0 +1,308 @@ +// Copyright 2009 The Go 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. +// TODO(rsc): solve "stack overflow during malloc" problem. + +#include "runtime.h" +#include "malloc.h" +#include "defs.h" + +MHeap mheap; +MStats mstats; + +// 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* +malloc(uintptr size) +{ + int32 sizeclass; + MCache *c; + uintptr npages; + MSpan *s; + void *v; + uint32 *ref; + + if(m->mallocing) + throw("malloc/free - deadlock"); + m->mallocing = 1; + + if(size == 0) + size = 1; + + if(size <= MaxSmallSize) { + // Allocate from mcache free lists. + sizeclass = SizeToClass(size); + size = class_to_size[sizeclass]; + c = m->mcache; + v = MCache_Alloc(c, sizeclass, size); + if(v == nil) + throw("out of memory"); + mstats.alloc += size; + } else { + // TODO(rsc): Report tracebacks for very large allocations. + + // Allocate directly from heap. + npages = size >> PageShift; + if((size & PageMask) != 0) + npages++; + s = MHeap_Alloc(&mheap, npages, 0); + if(s == nil) + throw("out of memory"); + mstats.alloc += npages<start << PageShift); + } + + // setup for mark sweep + if(!mlookup(v, nil, nil, &ref)) { + printf("malloc %D; mlookup failed\n", (uint64)size); + throw("malloc mlookup"); + } + *ref = RefNone; + + m->mallocing = 0; + return v; +} + +void* +mallocgc(uintptr size) +{ + void *v; + + v = malloc(size); + if(mstats.inuse_pages > mstats.next_gc) + gc(0); + return v; +} + +// Free the object whose base pointer is v. +void +free(void *v) +{ + int32 sizeclass, size; + uintptr page, tmp; + MSpan *s; + MCache *c; + uint32 *ref; + + if(v == nil) + return; + + if(m->mallocing) + throw("malloc/free - deadlock"); + m->mallocing = 1; + + if(!mlookup(v, nil, nil, &ref)) + throw("free mlookup"); + *ref = RefFree; + + // Find size class for v. + page = (uintptr)v >> PageShift; + sizeclass = MHeapMapCache_GET(&mheap.mapcache, page, tmp); + if(sizeclass == 0) { + // Missed in cache. + s = MHeap_Lookup(&mheap, page); + if(s == nil) + throw("free - invalid pointer"); + sizeclass = s->sizeclass; + if(sizeclass == 0) { + // Large object. + mstats.alloc -= s->npages<npages<mcache; + size = class_to_size[sizeclass]; + sys_memclr(v, size); + mstats.alloc -= size; + MCache_Free(c, v, sizeclass, size); + +out: + m->mallocing = 0; +} + +int32 +mlookup(void *v, byte **base, uintptr *size, uint32 **ref) +{ + uintptr n, nobj, i; + byte *p; + MSpan *s; + + s = MHeap_LookupMaybe(&mheap, (uintptr)v>>PageShift); + if(s == nil) { + if(base) + *base = nil; + if(size) + *size = 0; + if(ref) + *ref = 0; + return 0; + } + + p = (byte*)((uintptr)s->start<sizeclass == 0) { + // Large object. + if(base) + *base = p; + if(size) + *size = s->npages<gcref0; + return 1; + } + + if((byte*)v >= (byte*)s->gcref) { + // pointers into the gc ref counts + // do not count as pointers. + return 0; + } + + n = class_to_size[s->sizeclass]; + i = ((byte*)v - p)/n; + if(base) + *base = p + i*n; + if(size) + *size = n; + nobj = (s->npages << PageShift) / (n + RefcountOverhead); + if((byte*)s->gcref < p || (byte*)(s->gcref+nobj) > p+(s->npages<state, s, p, s->sizeclass, (uint64)nobj, (uint64)n, (uint64)s->npages); + printf("s->base sizeclass %d v=%p base=%p gcref=%p blocksize=%D nobj=%D size=%D end=%p end=%p\n", + s->sizeclass, v, p, s->gcref, (uint64)s->npages<gcref + nobj, p+(s->npages<gcref[i]; + + return 1; +} + +MCache* +allocmcache(void) +{ + return FixAlloc_Alloc(&mheap.cachealloc); +} + +void +mallocinit(void) +{ + InitSizes(); + MHeap_Init(&mheap, SysAlloc); + m->mcache = allocmcache(); + + // See if it works. + free(malloc(1)); +} + +void* +SysAlloc(uintptr n) +{ + mstats.sys += n; + return sys_mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0); +} + +void +SysUnused(void *v, uintptr n) +{ + USED(v); + USED(n); + // TODO(rsc): call madvise MADV_DONTNEED +} + +void +SysFree(void *v, uintptr n) +{ + USED(v); + USED(n); + // TODO(rsc): call munmap +} + +// Runtime stubs. + +extern void *oldmal(uint32); + +void* +mal(uint32 n) +{ +//return oldmal(n); + void *v; + + v = mallocgc(n); + + if(0) { + byte *p; + uint32 i; + p = v; + for(i=0; i %p: byte %d is non-zero\n", n, v, i); + throw("mal"); + } + } + } + +//printf("mal %d %p\n", n, v); // |checkmal to check for overlapping returns. + return v; +} + +// 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). +struct { + Lock; + FixAlloc; +} stacks; + +void* +stackalloc(uint32 n) +{ + void *v; + uint32 *ref; + +//return oldmal(n); + if(m->mallocing) { + lock(&stacks); + if(stacks.size == 0) + FixAlloc_Init(&stacks, n, SysAlloc, nil, nil); + if(stacks.size != n) { + printf("stackalloc: in malloc, size=%D want %d", (uint64)stacks.size, n); + throw("stackalloc"); + } + v = FixAlloc_Alloc(&stacks); + unlock(&stacks); + return v; + } + v = malloc(n); + if(!mlookup(v, nil, nil, &ref)) + throw("stackalloc mlookup"); + *ref = RefStack; + return v; +} + +void +stackfree(void *v) +{ +//return; + + if(m->mallocing) { + lock(&stacks); + FixAlloc_Free(&stacks, v); + unlock(&stacks); + return; + } + free(v); +} diff --git a/src/pkg/runtime/malloc.h b/src/pkg/runtime/malloc.h new file mode 100644 index 000000000..5b657a495 --- /dev/null +++ b/src/pkg/runtime/malloc.h @@ -0,0 +1,308 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Memory allocator, based on tcmalloc. +// http://goog-perftools.sourceforge.net/doc/tcmalloc.html + +// The main allocator works in runs of pages. +// Small allocation sizes (up to and including 32 kB) are +// rounded to one of about 100 size classes, each of which +// has its own free list of objects of exactly that size. +// Any free page of memory can be split into a set of objects +// of one size class, which are then managed using free list +// allocators. +// +// The allocator's data structures are: +// +// FixAlloc: a free-list allocator for fixed-size objects, +// used to manage storage used by the allocator. +// MHeap: the malloc heap, managed at page (4096-byte) granularity. +// MSpan: a run of pages managed by the MHeap. +// MHeapMap: a mapping from page IDs to MSpans. +// MHeapMapCache: a small cache of MHeapMap mapping page IDs +// to size classes for pages used for small objects. +// 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. +// +// This C code was written with an eye toward translating to Go +// in the future. Methods have the form Type_Method(Type *t, ...). + + +typedef struct FixAlloc FixAlloc; +typedef struct MCentral MCentral; +typedef struct MHeap MHeap; +typedef struct MHeapMap MHeapMap; +typedef struct MHeapMapCache MHeapMapCache; +typedef struct MSpan MSpan; +typedef struct MStats MStats; +typedef struct MLink MLink; + +enum +{ + PageShift = 12, + PageSize = 1<> PageShift + +enum +{ + // Tunable constants. + NumSizeClasses = 67, // Number of size classes (must match msize.c) + MaxSmallSize = 32<<10, + + FixAllocChunk = 128<<10, // Chunk size for FixAlloc + MaxMCacheListLen = 256, // Maximum objects on MCacheList + MaxMCacheSize = 2<<20, // Maximum bytes in one MCache + MaxMHeapList = 1<<(20 - PageShift), // Maximum page length for fixed-size list in MHeap. + HeapAllocChunk = 1<<20, // Chunk size for heap growth +}; + +#ifdef _64BIT +#include "mheapmap64.h" +#else +#include "mheapmap32.h" +#endif + +// A generic linked list of blocks. (Typically the block is bigger than sizeof(MLink).) +struct MLink +{ + MLink *next; +}; + +// SysAlloc obtains a large chunk of memory from the operating system, +// typically on the order of a hundred kilobytes or a megabyte. +// +// SysUnused notifies the operating system that the contents +// of the memory region are no longer needed and can be reused +// for other purposes. The program reserves the right to start +// accessing those pages in the future. +// +// SysFree returns it unconditionally; this is only used if +// an out-of-memory error has been detected midway through +// an allocation. It is okay if SysFree is a no-op. + +void* SysAlloc(uintptr nbytes); +void SysFree(void *v, uintptr nbytes); +void SysUnused(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; +}; + +void FixAlloc_Init(FixAlloc *f, uintptr size, void *(*alloc)(uintptr), void (*first)(void*, byte*), void *arg); +void* FixAlloc_Alloc(FixAlloc *f); +void FixAlloc_Free(FixAlloc *f, void *p); + + +// Statistics. +// Shared with Go: if you edit this structure, also edit ../malloc/malloc.go. +struct MStats +{ + uint64 alloc; + uint64 sys; + uint64 stacks; + uint64 inuse_pages; // protected by mheap.Lock + uint64 next_gc; // protected by mheap.Lock + bool enablegc; +}; +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 SizeToClass(int32); +extern int32 class_to_size[NumSizeClasses]; +extern int32 class_to_allocnpages[NumSizeClasses]; +extern int32 class_to_transfercount[NumSizeClasses]; +extern void 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; +}; + +void* MCache_Alloc(MCache *c, int32 sizeclass, uintptr size); +void MCache_Free(MCache *c, void *p, int32 sizeclass, uintptr size); + + +// An MSpan is a run of pages. +enum +{ + MSpanInUse = 0, + MSpanFree, + MSpanListHead, + MSpanDead, +}; +struct MSpan +{ + MSpan *next; // in a span linked list + MSpan *prev; // in a span linked list + MSpan *allnext; // in the list of all spans + PageID start; // starting page number + uintptr npages; // number of pages in span + MLink *freelist; // list of free objects + uint32 ref; // number of allocated objects in this span + uint32 sizeclass; // size class + uint32 state; // MSpanInUse etc + union { + uint32 *gcref; // sizeclass > 0 + uint32 gcref0; // sizeclass == 0 + }; +}; + +void MSpan_Init(MSpan *span, PageID start, uintptr npages); + +// Every MSpan is in one doubly-linked list, +// either one of the MHeap's free lists or one of the +// MCentral's span lists. We use empty MSpan structures as list heads. +void MSpanList_Init(MSpan *list); +bool MSpanList_IsEmpty(MSpan *list); +void MSpanList_Insert(MSpan *list, MSpan *span); +void MSpanList_Remove(MSpan *span); // from whatever list it is in + + +// Central list of free objects of a given size. +struct MCentral +{ + Lock; + int32 sizeclass; + MSpan nonempty; + MSpan empty; + int32 nfree; +}; + +void MCentral_Init(MCentral *c, int32 sizeclass); +int32 MCentral_AllocList(MCentral *c, int32 n, MLink **first); +void MCentral_FreeList(MCentral *c, int32 n, MLink *first); + +// Main malloc heap. +// The heap itself is the "free[]" and "large" arrays, +// but all the other global data is here too. +struct MHeap +{ + Lock; + MSpan free[MaxMHeapList]; // free lists of given length + MSpan large; // free lists length >= MaxMHeapList + MSpan *allspans; + + // span lookup + MHeapMap map; + MHeapMapCache mapcache; + + // 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 mheap; + +void MHeap_Init(MHeap *h, void *(*allocator)(uintptr)); +MSpan* MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass); +void MHeap_Free(MHeap *h, MSpan *s); +MSpan* MHeap_Lookup(MHeap *h, PageID p); +MSpan* MHeap_LookupMaybe(MHeap *h, PageID p); + +int32 mlookup(void *v, byte **base, uintptr *size, uint32 **ref); +void gc(int32 force); + +enum +{ + RefcountOverhead = 4, // one uint32 per object + + RefFree = 0, // must be zero + RefManual, // manual allocation - don't free + RefStack, // stack segment - don't free and don't scan for pointers + RefNone, // no references + RefSome, // some references +}; + diff --git a/src/pkg/runtime/malloc_go.cgo b/src/pkg/runtime/malloc_go.cgo new file mode 100644 index 000000000..6dcdaece2 --- /dev/null +++ b/src/pkg/runtime/malloc_go.cgo @@ -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 malloc +#include "runtime.h" +#include "malloc.h" + +func Alloc(n uintptr) (p *byte) { + p = malloc(n); +} + +func Free(p *byte) { + free(p); +} + +func Lookup(p *byte) (base *byte, size uintptr) { + mlookup(p, &base, &size, nil); +} + +func GetStats() (s *MStats) { + s = &mstats; +} + +func GC() { + gc(1); +} + diff --git a/src/pkg/runtime/mcache.c b/src/pkg/runtime/mcache.c new file mode 100644 index 000000000..ae2594023 --- /dev/null +++ b/src/pkg/runtime/mcache.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. + +// Per-thread (in Go, per-M) malloc cache for small objects. +// +// See malloc.h for an overview. + +#include "runtime.h" +#include "malloc.h" + +void* +MCache_Alloc(MCache *c, int32 sizeclass, uintptr size) +{ + MCacheList *l; + MLink *first, *v; + int32 n; + + // Allocate from list. + l = &c->list[sizeclass]; + if(l->list == nil) { + // Replenish using central lists. + n = MCentral_AllocList(&mheap.central[sizeclass], + class_to_transfercount[sizeclass], &first); + l->list = first; + l->nlist = n; + c->size += n*size; + } + v = l->list; + l->list = v->next; + l->nlist--; + if(l->nlist < l->nlistmin) + l->nlistmin = l->nlist; + c->size -= size; + + // v is zeroed except for the link pointer + // that we used above; zero that. + v->next = nil; + 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; inext; + l->list = *lp; + *lp = nil; + l->nlist -= n; + if(l->nlist < l->nlistmin) + l->nlistmin = l->nlist; + c->size -= n*class_to_size[sizeclass]; + + // Return them to central free list. + MCentral_FreeList(&mheap.central[sizeclass], n, first); +} + +void +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; + + if(l->nlist >= MaxMCacheListLen) { + // Release a chunk back. + ReleaseN(c, l, class_to_transfercount[sizeclass], sizeclass); + } + + if(c->size >= MaxMCacheSize) { + // Scavenge. + for(i=0; ilist[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; + } + } +} + diff --git a/src/pkg/runtime/mcentral.c b/src/pkg/runtime/mcentral.c new file mode 100644 index 000000000..5c9f720c0 --- /dev/null +++ b/src/pkg/runtime/mcentral.c @@ -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. + +// 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 +MCentral_Init(MCentral *c, int32 sizeclass) +{ + c->sizeclass = sizeclass; + MSpanList_Init(&c->nonempty); + 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 +MCentral_AllocList(MCentral *c, int32 n, MLink **pfirst) +{ + MLink *first, *last, *v; + int32 i; + + + lock(c); + // Replenish central list if empty. + if(MSpanList_IsEmpty(&c->nonempty)) { + if(!MCentral_Grow(c)) { + 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; inext = v; + last = v; + } + last->next = nil; + c->nfree -= i; + + 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(MSpanList_IsEmpty(&c->nonempty)) + return nil; + s = c->nonempty.next; + s->ref++; + v = s->freelist; + s->freelist = v->next; + if(s->freelist == nil) { + MSpanList_Remove(s); + MSpanList_Insert(&c->empty, s); + } + 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 +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); + + lock(c); + for(v=start; v; v=next) { + next = v->next; + MCentral_Free(c, v); + } + unlock(c); +} + +// Helper: free one object back into the central free list. +static void +MCentral_Free(MCentral *c, void *v) +{ + MSpan *s; + PageID page; + MLink *p, *next; + + // Find span for v. + page = (uintptr)v >> PageShift; + s = MHeap_Lookup(&mheap, page); + if(s == nil || s->ref == 0) + throw("invalid free"); + + // Move to nonempty if necessary. + if(s->freelist == nil) { + MSpanList_Remove(s); + 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) { + MSpanList_Remove(s); + // Freed blocks are zeroed except for the link pointer. + // Zero the link pointers so that the page is all zero. + for(p=s->freelist; p; p=next) { + next = p->next; + p->next = nil; + } + s->freelist = nil; + c->nfree -= (s->npages << PageShift) / class_to_size[c->sizeclass]; + unlock(c); + MHeap_Free(&mheap, s); + lock(c); + } +} + +// Fetch a new span from the heap and +// carve into objects for the free list. +static bool +MCentral_Grow(MCentral *c) +{ + int32 i, n, npages, size; + MLink **tailp, *v; + byte *p; + MSpan *s; + + unlock(c); + npages = class_to_allocnpages[c->sizeclass]; + s = MHeap_Alloc(&mheap, npages, c->sizeclass); + if(s == nil) { + // TODO(rsc): Log out of memory + lock(c); + return false; + } + + // Carve span into sequence of blocks. + tailp = &s->freelist; + p = (byte*)(s->start << PageShift); + size = class_to_size[c->sizeclass]; + n = (npages << PageShift) / (size + RefcountOverhead); + s->gcref = (uint32*)(p + size*n); + for(i=0; inext; + p += size; + } + *tailp = nil; + + lock(c); + c->nfree += n; + MSpanList_Insert(&c->nonempty, s); + return true; +} diff --git a/src/pkg/runtime/mem.c b/src/pkg/runtime/mem.c new file mode 100644 index 000000000..7ed299eb0 --- /dev/null +++ b/src/pkg/runtime/mem.c @@ -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. + +#include "runtime.h" +#include "defs.h" + +// Stubs for memory management. +// In a separate file so they can be overridden during testing of gc. + +enum +{ + NHUNK = 20<<20, +}; + +// Convenient wrapper around mmap. +static void* +brk(uint32 n) +{ + byte *v; + + v = sys_mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, 0, 0); + m->mem.nmmap += n; + return v; +} + +// Allocate n bytes of memory. Note that this gets used +// to allocate new stack segments, so at each call to a function +// you have to ask yourself "would it be okay to call mal recursively +// right here?" The answer is yes unless we're in the middle of +// editing the malloc state in m->mem. +void* +oldmal(uint32 n) +{ + byte* v; + + // round to keep everything 64-bit aligned + n = rnd(n, 8); + + // be careful. calling any function might invoke + // mal to allocate more stack. + if(n > NHUNK) { + v = brk(n); + } else { + // allocate a new hunk if this one is too small + if(n > m->mem.nhunk) { + // here we're in the middle of editing m->mem + // (we're about to overwrite m->mem.hunk), + // so we can't call brk - it might call mal to grow the + // stack, and the recursive call would allocate a new + // hunk, and then once brk returned we'd immediately + // overwrite that hunk with our own. + // (the net result would be a memory leak, not a crash.) + // so we have to call sys_mmap directly - it is written + // in assembly and tagged not to grow the stack. + m->mem.hunk = + sys_mmap(nil, NHUNK, PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_ANON|MAP_PRIVATE, 0, 0); + m->mem.nhunk = NHUNK; + m->mem.nmmap += NHUNK; + } + v = m->mem.hunk; + m->mem.hunk += n; + m->mem.nhunk -= n; + } + m->mem.nmal += n; + return v; +} + +void +sys_mal(uint32 n, uint8 *ret) +{ + ret = mal(n); + FLUSH(&ret); +} diff --git a/src/pkg/runtime/mfixalloc.c b/src/pkg/runtime/mfixalloc.c new file mode 100644 index 000000000..dd4f3f251 --- /dev/null +++ b/src/pkg/runtime/mfixalloc.c @@ -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. + +// 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 +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; +} + +void* +FixAlloc_Alloc(FixAlloc *f) +{ + void *v; + + if(f->list) { + v = f->list; + f->list = *(void**)f->list; + return v; + } + if(f->nchunk < f->size) { + f->chunk = f->alloc(FixAllocChunk); + if(f->chunk == nil) + 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; + return v; +} + +void +FixAlloc_Free(FixAlloc *f, void *p) +{ + *(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..d58d6ce44 --- /dev/null +++ b/src/pkg/runtime/mgc0.c @@ -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. + +// Garbage collector -- step 0. +// +// Stop the world, mark and sweep garbage collector. +// NOT INTENDED FOR PRODUCTION USE. +// +// A mark and sweep collector provides a way to exercise +// and test the memory allocator and the stack walking machinery +// without also needing to get reference counting +// exactly right. + +#include "runtime.h" +#include "malloc.h" + +enum { + Debug = 0 +}; + +extern byte etext[]; +extern byte end[]; + +enum { + PtrSize = sizeof(void*) +}; + +static void +scanblock(int32 depth, byte *b, int64 n) +{ + int32 off; + void *obj; + uintptr size; + uint32 *ref; + void **vp; + int64 i; + + if(Debug) + printf("%d scanblock %p %D\n", depth, b, n); + off = (uint32)(uintptr)b & (PtrSize-1); + if(off) { + b += PtrSize - off; + n -= PtrSize - off; + } + + vp = (void**)b; + n /= PtrSize; + for(i=0; isched.SP; + stk = (Stktop*)g->stackbase; + while(stk) { + scanblock(0, sp, (byte*)stk - sp); + sp = stk->oldsp; + stk = (Stktop*)stk->oldbase; + } +} + +static void +mark(void) +{ + G *gp; + + // mark data+bss + scanblock(0, etext, end - etext); + + // mark stacks + for(gp=allg; gp!=nil; gp=gp->alllink) { + switch(gp->status){ + default: + printf("unexpected G.status %d\n", gp->status); + throw("mark - bad status"); + case Gdead: + break; + case Grunning: + if(gp != g) + throw("mark - world not stopped"); + scanstack(gp); + break; + case Grunnable: + case Gsyscall: + case Gwaiting: + scanstack(gp); + break; + } + } +} + +static void +sweepspan(MSpan *s) +{ + int32 i, n, npages, size; + byte *p; + + if(s->state != MSpanInUse) + return; + + p = (byte*)(s->start << PageShift); + if(s->sizeclass == 0) { + // Large block. + switch(s->gcref0) { + default: + throw("bad 'ref count'"); + case RefFree: + case RefManual: + case RefStack: + break; + case RefNone: + if(Debug) + printf("free %D at %p\n", (uint64)s->npages<gcref0 = RefNone; // set up for next mark phase + break; + } + return; + } + + // Chunk full of small blocks. + // Must match computation in MCentral_Grow. + size = class_to_size[s->sizeclass]; + npages = class_to_allocnpages[s->sizeclass]; + n = (npages << PageShift) / (size + RefcountOverhead); + for(i=0; igcref[i]) { + default: + throw("bad 'ref count'"); + case RefFree: + case RefManual: + case RefStack: + break; + case RefNone: + if(Debug) + printf("free %d at %p\n", size, p+i*size); + free(p + i*size); + break; + case RefSome: + s->gcref[i] = RefNone; // set up for next mark phase + break; + } + } +} + +static void +sweep(void) +{ + MSpan *s; + + // Sweep all the spans. + for(s = mheap.allspans; s != nil; s = s->allnext) + sweepspan(s); +} + +// 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; + +void +gc(int32 force) +{ + byte *p; + + // 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 || panicking) + return; + + if(gcpercent == -2) { // first time through + p = getenv("GOGC"); + if(p == nil || p[0] == '\0') + gcpercent = 100; + else if(strcmp(p, (byte*)"off") == 0) + gcpercent = -1; + else + gcpercent = atoi(p); + } + if(gcpercent < 0) + return; + + semacquire(&gcsema); + gosave(&g->sched); // update g's stack pointer for scanstack + stoptheworld(); + if(mheap.Lock.key != 0) + throw("mheap locked during gc"); + if(force || mstats.inuse_pages >= mstats.next_gc) { + mark(); + sweep(); + mstats.next_gc = mstats.inuse_pages+mstats.inuse_pages*gcpercent/100; + } + starttheworld(); + gosave(&g->sched); // update g's stack pointer for debugging + semrelease(&gcsema); +} diff --git a/src/pkg/runtime/mheap.c b/src/pkg/runtime/mheap.c new file mode 100644 index 000000000..d0cf2237b --- /dev/null +++ b/src/pkg/runtime/mheap.c @@ -0,0 +1,333 @@ +// Copyright 2009 The Go 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 +MHeap_Init(MHeap *h, void *(*alloc)(uintptr)) +{ + uint32 i; + + FixAlloc_Init(&h->spanalloc, sizeof(MSpan), alloc, RecordSpan, h); + FixAlloc_Init(&h->cachealloc, sizeof(MCache), alloc, nil, nil); + MHeapMap_Init(&h->map, alloc); + // h->mapcache needs no init + for(i=0; ifree); i++) + MSpanList_Init(&h->free[i]); + MSpanList_Init(&h->large); + for(i=0; icentral); i++) + MCentral_Init(&h->central[i], i); +} + +// Allocate a new span of npage pages from the heap +// and record its size class in the HeapMap and HeapMapCache. +MSpan* +MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass) +{ + MSpan *s; + + lock(h); + s = MHeap_AllocLocked(h, npage, sizeclass); + if(s != nil) + mstats.inuse_pages += npage; + unlock(h); + return s; +} + +static MSpan* +MHeap_AllocLocked(MHeap *h, uintptr npage, int32 sizeclass) +{ + uintptr n; + MSpan *s, *t; + + // Try in fixed-size lists up to max. + for(n=npage; n < nelem(h->free); n++) { + if(!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) + throw("MHeap_AllocLocked - MSpan not free"); + if(s->npages < npage) + throw("MHeap_AllocLocked - bad npages"); + MSpanList_Remove(s); + s->state = MSpanInUse; + + if(s->npages > npage) { + // Trim extra and put it back in the heap. + t = FixAlloc_Alloc(&h->spanalloc); + MSpan_Init(t, s->start + npage, s->npages - npage); + s->npages = npage; + MHeapMap_Set(&h->map, t->start - 1, s); + MHeapMap_Set(&h->map, t->start, t); + MHeapMap_Set(&h->map, t->start + t->npages - 1, t); + t->state = MSpanInUse; + MHeap_FreeLocked(h, t); + } + + // If span is being used for small objects, cache size class. + // No matter what, cache span info, because gc needs to be + // able to map interior pointer to containing span. + s->sizeclass = sizeclass; + for(n=0; nmap, s->start+n, s); + if(sizeclass == 0) { + uintptr tmp; + + // If there are entries for this span, invalidate them, + // but don't blow out cache entries about other spans. + for(n=0; nmapcache, s->start+n, tmp) != 0) + MHeapMapCache_SET(&h->mapcache, s->start+n, 0); + } else { + // Save cache entries for this span. + // If there's a size class, there aren't that many pages. + for(n=0; nmapcache, s->start+n, sizeclass); + } + + return s; +} + +// Allocate a span of exactly npage pages from the list of large spans. +static MSpan* +MHeap_AllocLarge(MHeap *h, uintptr npage) +{ + return BestFit(&h->large, npage, nil); +} + +// Search list for smallest span with >= npage pages. +// If there are multiple smallest spans, take the one +// with the earliest starting address. +static MSpan* +BestFit(MSpan *list, uintptr npage, MSpan *best) +{ + MSpan *s; + + for(s=list->next; s != list; s=s->next) { + if(s->npages < npage) + continue; + if(best == nil + || s->npages < best->npages + || (s->npages == best->npages && s->start < best->start)) + best = s; + } + return best; +} + +// Try to add at least npage pages of memory to the heap, +// returning whether it worked. +static bool +MHeap_Grow(MHeap *h, uintptr npage) +{ + uintptr ask; + void *v; + MSpan *s; + + // Ask for a big chunk, to reduce the number of mappings + // the operating system needs to track; also amortizes + // the overhead of an operating system mapping. + ask = npage< (npage<map, ((uintptr)v>>PageShift) - 1, (ask>>PageShift) + 2)) { + SysFree(v, ask); + return false; + } + + // Create a fake "in use" span and free it, so that the + // right coalescing happens. + s = FixAlloc_Alloc(&h->spanalloc); + MSpan_Init(s, (uintptr)v>>PageShift, ask>>PageShift); + MHeapMap_Set(&h->map, s->start, s); + MHeapMap_Set(&h->map, s->start + s->npages - 1, s); + s->state = MSpanInUse; + MHeap_FreeLocked(h, s); + return true; +} + +// Look up the span at the given page number. +// Page number is guaranteed to be in map +// and is guaranteed to be start or end of span. +MSpan* +MHeap_Lookup(MHeap *h, PageID p) +{ + return MHeapMap_Get(&h->map, p); +} + +// Look up the span at the given page number. +// Page number is *not* guaranteed to be in map +// and may be anywhere in the span. +// Map entries for the middle of a span are only +// valid for allocated spans. Free spans may have +// other garbage in their middles, so we have to +// check for that. +MSpan* +MHeap_LookupMaybe(MHeap *h, PageID p) +{ + MSpan *s; + + s = MHeapMap_GetMaybe(&h->map, p); + if(s == nil || p < s->start || p - s->start >= s->npages) + return nil; + if(s->state != MSpanInUse) + return nil; + return s; +} + +// Free the span back into the heap. +void +MHeap_Free(MHeap *h, MSpan *s) +{ + lock(h); + mstats.inuse_pages -= s->npages; + MHeap_FreeLocked(h, s); + unlock(h); +} + +static void +MHeap_FreeLocked(MHeap *h, MSpan *s) +{ + MSpan *t; + + if(s->state != MSpanInUse || s->ref != 0) { + printf("MHeap_FreeLocked - span %p ptr %p state %d ref %d\n", s, s->start<state, s->ref); + throw("MHeap_FreeLocked - invalid free"); + } + s->state = MSpanFree; + MSpanList_Remove(s); + + // Coalesce with earlier, later spans. + if((t = MHeapMap_Get(&h->map, s->start - 1)) != nil && t->state != MSpanInUse) { + s->start = t->start; + s->npages += t->npages; + MHeapMap_Set(&h->map, s->start, s); + MSpanList_Remove(t); + t->state = MSpanDead; + FixAlloc_Free(&h->spanalloc, t); + } + if((t = MHeapMap_Get(&h->map, s->start + s->npages)) != nil && t->state != MSpanInUse) { + s->npages += t->npages; + MHeapMap_Set(&h->map, s->start + s->npages - 1, s); + MSpanList_Remove(t); + t->state = MSpanDead; + FixAlloc_Free(&h->spanalloc, t); + } + + // Insert s into appropriate list. + if(s->npages < nelem(h->free)) + MSpanList_Insert(&h->free[s->npages], s); + else + MSpanList_Insert(&h->large, s); + + // TODO(rsc): IncrementalScavenge() to return memory to OS. +} + +// Initialize a new span with the given start and npages. +void +MSpan_Init(MSpan *span, PageID start, uintptr npages) +{ + 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 +MSpanList_Init(MSpan *list) +{ + list->state = MSpanListHead; + list->next = list; + list->prev = list; +} + +void +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 +MSpanList_IsEmpty(MSpan *list) +{ + return list->next == list; +} + +void +MSpanList_Insert(MSpan *list, MSpan *span) +{ + if(span->next != nil || span->prev != nil) + throw("MSpanList_Insert"); + span->next = list->next; + span->prev = list; + span->next->prev = span; + span->prev->next = span; +} diff --git a/src/pkg/runtime/mheapmap32.c b/src/pkg/runtime/mheapmap32.c new file mode 100644 index 000000000..420ca2d83 --- /dev/null +++ b/src/pkg/runtime/mheapmap32.c @@ -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. + +// Heap map, 32-bit version +// See malloc.h and mheap.c for overview. + +#include "runtime.h" +#include "malloc.h" + +// 3-level radix tree mapping page ids to Span*. +void +MHeapMap_Init(MHeapMap *m, void *(*allocator)(size_t)) +{ + m->allocator = allocator; +} + +MSpan* +MHeapMap_Get(MHeapMap *m, PageID k) +{ + int32 i1, i2; + + i2 = k & MHeapMap_Level2Mask; + k >>= MHeapMap_Level2Bits; + i1 = k & MHeapMap_Level1Mask; + k >>= MHeapMap_Level1Bits; + if(k != 0) + throw("MHeapMap_Get"); + + return m->p[i1]->s[i2]; +} + +MSpan* +MHeapMap_GetMaybe(MHeapMap *m, PageID k) +{ + int32 i1, i2; + MHeapMapNode2 *p2; + + i2 = k & MHeapMap_Level2Mask; + k >>= MHeapMap_Level2Bits; + i1 = k & MHeapMap_Level1Mask; + k >>= MHeapMap_Level1Bits; + if(k != 0) + throw("MHeapMap_Get"); + + p2 = m->p[i1]; + if(p2 == nil) + return nil; + return p2->s[i2]; +} + +void +MHeapMap_Set(MHeapMap *m, PageID k, MSpan *s) +{ + int32 i1, i2; + + i2 = k & MHeapMap_Level2Mask; + k >>= MHeapMap_Level2Bits; + i1 = k & MHeapMap_Level1Mask; + k >>= MHeapMap_Level1Bits; + if(k != 0) + throw("MHeapMap_Set"); + + m->p[i1]->s[i2] = s; +} + +// Allocate the storage required for entries [k, k+1, ..., k+len-1] +// so that Get and Set calls need not check for nil pointers. +bool +MHeapMap_Preallocate(MHeapMap *m, PageID k, uintptr len) +{ + uintptr end; + int32 i1; + MHeapMapNode2 *p2; + + end = k+len; + while(k < end) { + if((k >> MHeapMap_TotalBits) != 0) + return false; + i1 = (k >> MHeapMap_Level2Bits) & MHeapMap_Level1Mask; + + // first-level pointer + if(m->p[i1] == nil) { + p2 = m->allocator(sizeof *p2); + if(p2 == nil) + return false; + sys_memclr((byte*)p2, sizeof *p2); + m->p[i1] = p2; + } + + // advance key past this leaf node + k = ((k >> MHeapMap_Level2Bits) + 1) << MHeapMap_Level2Bits; + } + return true; +} + diff --git a/src/pkg/runtime/mheapmap32.h b/src/pkg/runtime/mheapmap32.h new file mode 100644 index 000000000..0a16ccd10 --- /dev/null +++ b/src/pkg/runtime/mheapmap32.h @@ -0,0 +1,76 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Free(v) must be able to determine the MSpan containing v. +// The MHeapMap is a 2-level radix tree mapping page numbers to MSpans. + +typedef struct MHeapMapNode2 MHeapMapNode2; + +enum +{ + // 32 bit address - 12 bit page size = 20 bits to map + MHeapMap_Level1Bits = 10, + MHeapMap_Level2Bits = 10, + + MHeapMap_TotalBits = + MHeapMap_Level1Bits + + MHeapMap_Level2Bits, + + MHeapMap_Level1Mask = (1<array[(key) & HMASK] = (key) | ((uintptr)(value) << KBITS)) + +#define MHeapMapCache_GET(cache, key, tmp) \ + (tmp = (cache)->array[(key) & HMASK], \ + (tmp & KMASK) == (key) ? (tmp >> KBITS) : 0) diff --git a/src/pkg/runtime/mheapmap64.c b/src/pkg/runtime/mheapmap64.c new file mode 100644 index 000000000..1886ba529 --- /dev/null +++ b/src/pkg/runtime/mheapmap64.c @@ -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. + +// Heap map, 64-bit version +// See malloc.h and mheap.c for overview. + +#include "runtime.h" +#include "malloc.h" + +// 3-level radix tree mapping page ids to Span*. +void +MHeapMap_Init(MHeapMap *m, void *(*allocator)(size_t)) +{ + m->allocator = allocator; +} + +MSpan* +MHeapMap_Get(MHeapMap *m, PageID k) +{ + int32 i1, i2, i3; + + i3 = k & MHeapMap_Level3Mask; + k >>= MHeapMap_Level3Bits; + i2 = k & MHeapMap_Level2Mask; + k >>= MHeapMap_Level2Bits; + i1 = k & MHeapMap_Level1Mask; + k >>= MHeapMap_Level1Bits; + if(k != 0) + throw("MHeapMap_Get"); + + return m->p[i1]->p[i2]->s[i3]; +} + +MSpan* +MHeapMap_GetMaybe(MHeapMap *m, PageID k) +{ + int32 i1, i2, i3; + MHeapMapNode2 *p2; + MHeapMapNode3 *p3; + + i3 = k & MHeapMap_Level3Mask; + k >>= MHeapMap_Level3Bits; + i2 = k & MHeapMap_Level2Mask; + k >>= MHeapMap_Level2Bits; + i1 = k & MHeapMap_Level1Mask; + k >>= MHeapMap_Level1Bits; + if(k != 0) + throw("MHeapMap_Get"); + + p2 = m->p[i1]; + if(p2 == nil) + return nil; + p3 = p2->p[i2]; + if(p3 == nil) + return nil; + return p3->s[i3]; +} + +void +MHeapMap_Set(MHeapMap *m, PageID k, MSpan *s) +{ + int32 i1, i2, i3; + + i3 = k & MHeapMap_Level3Mask; + k >>= MHeapMap_Level3Bits; + i2 = k & MHeapMap_Level2Mask; + k >>= MHeapMap_Level2Bits; + i1 = k & MHeapMap_Level1Mask; + k >>= MHeapMap_Level1Bits; + if(k != 0) + throw("MHeapMap_Set"); + + m->p[i1]->p[i2]->s[i3] = s; +} + +// Allocate the storage required for entries [k, k+1, ..., k+len-1] +// so that Get and Set calls need not check for nil pointers. +bool +MHeapMap_Preallocate(MHeapMap *m, PageID k, uintptr len) +{ + uintptr end; + int32 i1, i2; + MHeapMapNode2 *p2; + MHeapMapNode3 *p3; + + end = k+len; + while(k < end) { + if((k >> MHeapMap_TotalBits) != 0) + return false; + i2 = (k >> MHeapMap_Level3Bits) & MHeapMap_Level2Mask; + i1 = (k >> (MHeapMap_Level3Bits + MHeapMap_Level2Bits)) & MHeapMap_Level1Mask; + + // first-level pointer + if((p2 = m->p[i1]) == nil) { + p2 = m->allocator(sizeof *p2); + if(p2 == nil) + return false; + sys_memclr((byte*)p2, sizeof *p2); + m->p[i1] = p2; + } + + // second-level pointer + if(p2->p[i2] == nil) { + p3 = m->allocator(sizeof *p3); + if(p3 == nil) + return false; + sys_memclr((byte*)p3, sizeof *p3); + p2->p[i2] = p3; + } + + // advance key past this leaf node + k = ((k >> MHeapMap_Level3Bits) + 1) << MHeapMap_Level3Bits; + } + return true; +} + diff --git a/src/pkg/runtime/mheapmap64.h b/src/pkg/runtime/mheapmap64.h new file mode 100644 index 000000000..127b773f7 --- /dev/null +++ b/src/pkg/runtime/mheapmap64.h @@ -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. + +// Free(v) must be able to determine the MSpan containing v. +// The MHeapMap is a 3-level radix tree mapping page numbers to MSpans. +// +// NOTE(rsc): On a 32-bit platform (= 20-bit page numbers), +// we can swap in a 2-level radix tree. +// +// NOTE(rsc): We use a 3-level tree because tcmalloc does, but +// having only three levels requires approximately 1 MB per node +// in the tree, making the minimum map footprint 3 MB. +// Using a 4-level tree would cut the minimum footprint to 256 kB. +// On the other hand, it's just virtual address space: most of +// the memory is never going to be touched, thus never paged in. + +typedef struct MHeapMapNode2 MHeapMapNode2; +typedef struct MHeapMapNode3 MHeapMapNode3; + +enum +{ + // 64 bit address - 12 bit page size = 52 bits to map + MHeapMap_Level1Bits = 18, + MHeapMap_Level2Bits = 18, + MHeapMap_Level3Bits = 16, + + MHeapMap_TotalBits = + MHeapMap_Level1Bits + + MHeapMap_Level2Bits + + MHeapMap_Level3Bits, + + MHeapMap_Level1Mask = (1<array[(key) & HMASK] = (key) | ((uintptr)(value) << KBITS)) + +#define MHeapMapCache_GET(cache, key, tmp) \ + (tmp = (cache)->array[(key) & HMASK], \ + (tmp & KMASK) == (key) ? (tmp >> KBITS) : 0) diff --git a/src/pkg/runtime/msize.c b/src/pkg/runtime/msize.c new file mode 100644 index 000000000..25e22637d --- /dev/null +++ b/src/pkg/runtime/msize.c @@ -0,0 +1,165 @@ +// Copyright 2009 The Go 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 class_to_size[NumSizeClasses]; +int32 class_to_allocnpages[NumSizeClasses]; +int32 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 +SizeToClass(int32 size) +{ + if(size > MaxSmallSize) + throw("SizeToClass - invalid size"); + if(size > 1024-8) + return size_to_class128[(size-1024+127) >> 7]; + return size_to_class8[(size+7)>>3]; +} + +void +InitSizes(void) +{ + int32 align, sizeclass, size, osize, nextsize, n; + uint32 i; + uintptr allocsize, npages; + + // Initialize the class_to_size table (and choose class sizes in the process). + class_to_size[0] = 0; + 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) + throw("InitSizes - bug"); + + // Make the allocnpages big enough that + // the leftover is less than 1/8 of the total, + // so wasted space is at most 12.5%. + allocsize = PageSize; + osize = size + RefcountOverhead; + while(allocsize%osize > (allocsize/8)) + allocsize += PageSize; + npages = allocsize >> PageShift; + + // If the previous sizeclass chose the same + // allocation size and fit the same number of + // objects into the page, we might as well + // use just this size instead of having two + // different sizes. + if(sizeclass > 1 + && npages == class_to_allocnpages[sizeclass-1] + && allocsize/osize == allocsize/(class_to_size[sizeclass-1]+RefcountOverhead)) { + class_to_size[sizeclass-1] = size; + continue; + } + + class_to_allocnpages[sizeclass] = npages; + class_to_size[sizeclass] = size; + sizeclass++; + } + if(sizeclass != NumSizeClasses) { + printf("sizeclass=%d NumSizeClasses=%d\n", sizeclass, NumSizeClasses); + throw("InitSizes - bad NumSizeClasses"); + } + + // Initialize the size_to_class tables. + nextsize = 0; + for (sizeclass = 1; sizeclass < NumSizeClasses; sizeclass++) { + for(; nextsize < 1024 && nextsize <= class_to_size[sizeclass]; nextsize+=8) + size_to_class8[nextsize/8] = sizeclass; + if(nextsize >= 1024) + for(; nextsize <= class_to_size[sizeclass]; nextsize += 128) + size_to_class128[(nextsize-1024)/128] = sizeclass; + } + + // Double-check SizeToClass. + if(0) { + for(n=0; n < MaxSmallSize; n++) { + sizeclass = SizeToClass(n); + if(sizeclass < 1 || sizeclass >= NumSizeClasses || class_to_size[sizeclass] < n) { + printf("size=%d sizeclass=%d class_to_size=%d\n", n, sizeclass, class_to_size[sizeclass]); + printf("incorrect SizeToClass"); + goto dump; + } + if(sizeclass > 1 && class_to_size[sizeclass-1] >= n) { + printf("size=%d sizeclass=%d class_to_size=%d\n", n, sizeclass, class_to_size[sizeclass]); + printf("SizeToClass too big"); + goto dump; + } + } + } + + // Initialize the class_to_transfercount table. + for(sizeclass = 1; sizeclass < NumSizeClasses; sizeclass++) { + n = 64*1024 / class_to_size[sizeclass]; + if(n < 2) + n = 2; + if(n > 32) + n = 32; + class_to_transfercount[sizeclass] = n; + } + return; + +dump: + if(1){ + printf("NumSizeClasses=%d\n", NumSizeClasses); + printf("class_to_size:"); + for(sizeclass=0; sizeclass%d(%d)\n", i*8, size_to_class8[i], class_to_size[size_to_class8[i]]); + printf("\n"); + printf("size_to_class128:"); + for(i=0; i%d(%d)\n", i*128, size_to_class128[i], class_to_size[size_to_class128[i]]); + printf("\n"); + } + throw("InitSizes failed"); +} diff --git a/src/pkg/runtime/print.c b/src/pkg/runtime/print.c new file mode 100644 index 000000000..5295e338d --- /dev/null +++ b/src/pkg/runtime/print.c @@ -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. + +#include "runtime.h" + + +void +dump(byte *p, int32 n) +{ + int32 i; + + for(i=0; i>4)); + sys·printpointer((byte*)(p[i]&0xf)); + if((i&15) == 15) + prints("\n"); + else + prints(" "); + } + if(n & 15) + prints("\n"); +} + +void +prints(int8 *s) +{ + sys·write(1, s, findnull((byte*)s)); +} + +// Very simple printf. Only for debugging prints. +// Do not add to this without checking with Rob. +void +printf(int8 *s, ...) +{ + int8 *p, *lp; + byte *arg, *narg; + + lp = p = s; + arg = (byte*)(&s+1); + for(; *p; p++) { + if(*p != '%') + continue; + if(p > lp) + sys·write(1, lp, p-lp); + p++; + narg = nil; + switch(*p) { + case 'd': // 32-bit + case 'x': + narg = arg + 4; + break; + case 'D': // 64-bit + case 'X': + if(sizeof(uintptr) == 8 && ((uint32)(uint64)arg)&4) + arg += 4; + narg = arg + 8; + break; + case 'p': // pointer-sized + case 's': + if(sizeof(uintptr) == 8 && ((uint32)(uint64)arg)&4) + arg += 4; + narg = arg + sizeof(uintptr); + break; + case 'S': // pointer-aligned but bigger + if(sizeof(uintptr) == 8 && ((uint32)(uint64)arg)&4) + arg += 4; + narg = arg + sizeof(String); + break; + } + switch(*p) { + case 'd': + sys·printint(*(int32*)arg); + break; + case 'D': + sys·printint(*(int64*)arg); + break; + case 'x': + sys·printhex(*(int32*)arg); + break; + case 'X': + sys·printhex(*(int64*)arg); + break; + case 'p': + sys·printpointer(*(void**)arg); + break; + case 's': + prints(*(int8**)arg); + break; + case 'S': + sys·printstring(*(String*)arg); + break; + } + arg = narg; + lp = p+1; + } + if(p > lp) + sys·write(1, lp, p-lp); +} + + +void +sys·printpc(void *p) +{ + prints("PC="); + sys·printhex((uint64)sys·getcallerpc(p)); +} + +void +sys·printbool(bool v) +{ + if(v) { + sys·write(1, (byte*)"true", 4); + return; + } + sys·write(1, (byte*)"false", 5); +} + +void +sys·printfloat(float64 v) +{ + byte buf[20]; + int32 e, s, i, n; + float64 h; + + if(isNaN(v)) { + sys·write(1, "NaN", 3); + return; + } + if(isInf(v, 0)) { + sys·write(1, "+Inf", 4); + return; + } + if(isInf(v, -1)) { + sys·write(1, "+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= 10) { + e++; + v /= 10; + } + } + + // format +d.dddd+edd + buf[0] = '+'; + if(s) + buf[0] = '-'; + for(i=0; i0; i--) { + buf[i] = v%10 + '0'; + if(v < 10) + break; + v = v/10; + } + sys·write(1, buf+i, nelem(buf)-i); +} + +void +sys·printint(int64 v) +{ + if(v < 0) { + sys·write(1, "-", 1); + v = -v; + } + sys·printuint(v); +} + +void +sys·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'; + sys·write(1, buf+i, nelem(buf)-i); +} + +void +sys·printpointer(void *p) +{ + sys·printhex((uint64)p); +} + +void +sys·printstring(String v) +{ + extern int32 maxstring; + + if(v.len > maxstring) { + sys·write(1, "[invalid string]", 16); + return; + } + if(v.len > 0) + sys·write(1, v.str, v.len); +} + +void +sys·printsp(void) +{ + sys·write(1, " ", 1); +} + +void +sys·printnl(void) +{ + sys·write(1, "\n", 1); +} diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c new file mode 100644 index 000000000..1d065e6d2 --- /dev/null +++ b/src/pkg/runtime/proc.c @@ -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. + +#include "runtime.h" +#include "malloc.h" + +typedef struct Sched Sched; + +M m0; +G g0; // idle goroutine for m0 + +static int32 debug = 0; +static Lock debuglock; + +// 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 gs +// and no waiting ms, ready() will start a new m running in a new +// OS thread, so that all ready gs can run simultaneously, up to a limit. +// For now, ms never go away. +// +// The default maximum number of ms is one: go runs single-threaded. +// This is because some locking details have to be worked ou +// (select in particular is not locked properly) and because the low-level +// code hasn't been written yet for OS X. Setting the environmen +// variable $gomaxprocs changes sched.mmax for now. +// +// Even a program that can run without deadlock in a single process +// might use more ms if given the chance. For example, the prime +// sieve will use as many ms as there are primes (up to sched.mmax), +// allowing different stages of the pipeline to execute in parallel. +// We could revisit this choice, only kicking off new ms for blocking +// system calls, but that would limit the amount of parallel computation +// 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 gs (status == Gdead) + + G *ghead; // gs waiting to run + G *gtail; + int32 gwait; // number of gs waiting to run + int32 gcount; // number of gs that are alive + + M *mhead; // ms waiting for work + int32 mwait; // number of ms waiting for work + int32 mcount; // number of ms that have been created + int32 mcpu; // number of ms executing on cpu + int32 mcpumax; // max number of ms allowed on cpu + int32 gomaxprocs; + int32 msyscall; // number of ms in system calls + + int32 predawn; // running initialization, don't run new gs. + + Note stopped; // one g can wait here for ms to stop + int32 waitstop; // after setting this flag +}; + +Sched sched; + +// 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(void); +static void gfput(G*); // put/get on gfree +static G* gfget(void); +static void matchmg(void); // match ms to gs +static void readylocked(G*); // ready, but sched is locked + +// Scheduler loop. +static void scheduler(void); + +// The bootstrap sequence is: +// +// call osinit +// call schedinit +// make & queue new G +// call mstart +// +// The new G does: +// +// call main·init_function +// call initdone +// call main·main +void +schedinit(void) +{ + int32 n; + byte *p; + + mallocinit(); + goargs(); + + // Allocate internal symbol table representation now, + // so that we don't need to call malloc when we crash. + findfunc(0); + + sched.gomaxprocs = 1; + p = getenv("GOMAXPROCS"); + if(p != nil && (n = atoi(p)) != 0) + sched.gomaxprocs = n; + sched.mcpumax = sched.gomaxprocs; + sched.mcount = 1; + sched.predawn = 1; +} + +// Called after main·init_function; main·main will be called on return. +void +initdone(void) +{ + // Let's go. + sched.predawn = 0; + mstats.enablegc = 1; + + // If main·init_function started other goroutines, + // kick off new ms to handle them, like ready + // would have, had it not been pre-dawn. + lock(&sched); + matchmg(); + unlock(&sched); +} + +void +goexit(void) +{ + if(debug > 1){ + lock(&debuglock); + printf("goexit goid=%d\n", g->goid); + unlock(&debuglock); + } + g->status = Gmoribund; + gosched(); +} + +void +tracebackothers(G *me) +{ + G *g; + + for(g = allg; g != nil; g = g->alllink) { + if(g == me || g->status == Gdead) + continue; + printf("\ngoroutine %d:\n", g->goid); + traceback(g->sched.PC, g->sched.SP+sizeof(uintptr), g); // gogo adjusts SP by one word + } +} + +// Put on `g' queue. Sched must be locked. +static void +gput(G *g) +{ + g->schedlink = nil; + if(sched.ghead == nil) + sched.ghead = g; + else + sched.gtail->schedlink = g; + sched.gtail = g; + sched.gwait++; +} + +// Get from `g' queue. Sched must be locked. +static G* +gget(void) +{ + G *g; + + g = sched.ghead; + if(g){ + sched.ghead = g->schedlink; + if(sched.ghead == nil) + sched.gtail = nil; + sched.gwait--; + } + return g; +} + +// Put on `m' list. Sched must be locked. +static void +mput(M *m) +{ + m->schedlink = sched.mhead; + sched.mhead = m; + sched.mwait++; +} + +// Get from `m' list. Sched must be locked. +static M* +mget(void) +{ + M *m; + + m = sched.mhead; + if(m){ + sched.mhead = m->schedlink; + sched.mwait--; + } + return m; +} + +// Put on gfree list. Sched must be locked. +static void +gfput(G *g) +{ + g->schedlink = sched.gfree; + sched.gfree = g; +} + +// Get from gfree list. Sched must be locked. +static G* +gfget(void) +{ + G *g; + + g = sched.gfree; + if(g) + sched.gfree = g->schedlink; + return g; +} + +// Mark g ready to run. +void +ready(G *g) +{ + lock(&sched); + readylocked(g); + unlock(&sched); +} + +// 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) + throw("bad g->status in ready"); + g->status = Grunnable; + + gput(g); + if(!sched.predawn) + matchmg(); +} + +// Get the next goroutine that m should run. +// Sched must be locked on entry, is unlocked on exit. +// Makes sure that at most $GOMAXPROCS gs are +// running on cpus (not in system calls) at any given time. +static G* +nextgandunlock(void) +{ + G *gp; + + // On startup, each m is assigned a nextg and + // has already been accounted for in mcpu. + if(m->nextg != nil) { + gp = m->nextg; + m->nextg = nil; + unlock(&sched); + if(debug > 1) { + lock(&debuglock); + printf("m%d nextg found g%d\n", m->id, gp->goid); + unlock(&debuglock); + } + return gp; + } + + // Otherwise, look for work. + if(sched.mcpu < sched.mcpumax && (gp=gget()) != nil) { + sched.mcpu++; + unlock(&sched); + if(debug > 1) { + lock(&debuglock); + printf("m%d nextg got g%d\n", m->id, gp->goid); + unlock(&debuglock); + } + return gp; + } + + // Otherwise, sleep. + mput(m); + if(sched.mcpu == 0 && sched.msyscall == 0) + throw("all goroutines are asleep - deadlock!"); + m->nextg = nil; + noteclear(&m->havenextg); + if(sched.waitstop && sched.mcpu <= sched.mcpumax) { + sched.waitstop = 0; + notewakeup(&sched.stopped); + } + unlock(&sched); + + notesleep(&m->havenextg); + if((gp = m->nextg) == nil) + throw("bad m->nextg in nextgoroutine"); + m->nextg = nil; + if(debug > 1) { + lock(&debuglock); + printf("m%d nextg woke g%d\n", m->id, gp->goid); + unlock(&debuglock); + } + return gp; +} + +// TODO(rsc): Remove. This is only temporary, +// for the mark and sweep collector. +void +stoptheworld(void) +{ + lock(&sched); + sched.mcpumax = 1; + while(sched.mcpu > 1) { + noteclear(&sched.stopped); + sched.waitstop = 1; + unlock(&sched); + notesleep(&sched.stopped); + lock(&sched); + } + unlock(&sched); +} + +// TODO(rsc): Remove. This is only temporary, +// for the mark and sweep collector. +void +starttheworld(void) +{ + lock(&sched); + sched.mcpumax = sched.gomaxprocs; + matchmg(); + unlock(&sched); +} + +// Called to start an M. +void +mstart(void) +{ + if(m->mcache == nil) + m->mcache = allocmcache(); + minit(); + scheduler(); +} + +// Kick of new ms 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) +{ + M *m; + G *g; + + if(debug > 1 && sched.ghead != nil) { + lock(&debuglock); + printf("matchmg mcpu=%d mcpumax=%d gwait=%d\n", sched.mcpu, sched.mcpumax, sched.gwait); + unlock(&debuglock); + } + + while(sched.mcpu < sched.mcpumax && (g = gget()) != nil){ + sched.mcpu++; + if((m = mget()) != nil){ + if(debug > 1) { + lock(&debuglock); + printf("wakeup m%d g%d\n", m->id, g->goid); + unlock(&debuglock); + } + m->nextg = g; + notewakeup(&m->havenextg); + }else{ + m = malloc(sizeof(M)); + m->g0 = malg(8192); + m->nextg = g; + m->id = sched.mcount++; + if(debug) { + lock(&debuglock); + printf("alloc m%d g%d\n", m->id, g->goid); + unlock(&debuglock); + } + newosproc(m, m->g0, m->g0->stackbase, mstart); + } + } +} + +// Scheduler loop: find g to run, run it, repeat. +static void +scheduler(void) +{ + G* gp; + + lock(&sched); + if(gosave(&m->sched)){ + // Jumped here via gosave/gogo, so didn't + // execute lock(&sched) above. + lock(&sched); + + if(sched.predawn) + throw("init sleeping"); + + // Just finished running m->curg. + gp = m->curg; + gp->m = nil; + sched.mcpu--; + if(debug > 1) { + lock(&debuglock); + printf("m%d sched g%d status %d\n", m->id, gp->goid, gp->status); + unlock(&debuglock); + } + switch(gp->status){ + case Grunnable: + case Gdead: + // Shouldn't have been running! + throw("bad gp->status in sched"); + case Grunning: + gp->status = Grunnable; + gput(gp); + break; + case Gmoribund: + gp->status = Gdead; + if(--sched.gcount == 0) + exit(0); + break; + } + if(gp->readyonstop){ + gp->readyonstop = 0; + readylocked(gp); + } + } + + // Find (or wait for) g to run. Unlocks sched. + gp = nextgandunlock(); + gp->readyonstop = 0; + gp->status = Grunning; + if(debug > 1) { + lock(&debuglock); + printf("m%d run g%d at %p\n", m->id, gp->goid, gp->sched.PC); + traceback(gp->sched.PC, gp->sched.SP+8, gp); + unlock(&debuglock); + } + m->curg = gp; + gp->m = m; + g = gp; + gogo(&gp->sched); +} + +// 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. +void +gosched(void) +{ + if(g == m->g0) + throw("gosched of g0"); + if(gosave(&g->sched) == 0){ + g = m->g0; + gogo(&m->sched); + } +} + +// 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, not +// from the low-level system calls used by the runtime. +// The "arguments" are syscall.Syscall's stack frame +void +sys·entersyscall(uint64 callerpc, int64 trap) +{ + USED(callerpc); + + if(debug > 1) { + lock(&debuglock); + printf("m%d g%d enter syscall %D\n", m->id, g->goid, trap); + unlock(&debuglock); + } + lock(&sched); + g->status = Gsyscall; + sched.mcpu--; + sched.msyscall++; + if(sched.gwait != 0) + matchmg(); + if(sched.waitstop && sched.mcpu <= sched.mcpumax) { + sched.waitstop = 0; + notewakeup(&sched.stopped); + } + unlock(&sched); + // leave SP around for gc and traceback + gosave(&g->sched); +} + +// 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 +sys·exitsyscall(void) +{ + if(debug > 1) { + lock(&debuglock); + printf("m%d g%d exit syscall mcpu=%d mcpumax=%d\n", m->id, g->goid, sched.mcpu, sched.mcpumax); + unlock(&debuglock); + } + + lock(&sched); + g->status = Grunning; + sched.msyscall--; + sched.mcpu++; + // Fast path - if there's room for this m, we're done. + if(sched.mcpu <= sched.mcpumax) { + unlock(&sched); + return; + } + unlock(&sched); + + // Slow path - all the cpus are taken. + // The scheduler will ready g and put this m to sleep. + // When the scheduler takes g awa from m, + // it will undo the sched.mcpu++ above. + gosched(); +} + +/* + * stack layout parameters. + * known to linkers. + * + * 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: + * + * 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 sys.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 sys.morestack(SB) + * + * stack frame size >= StackBig: + * MOVQ m->morearg, $((argsize << 32) | frame) + * CALL sys.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 (sys.deferproc) + * or because they handle the imminent stack overflow (sys.morestack). + * + * for example, sys.deferproc might call malloc, + * which does one of the above checks (without allocating a full frame), + * which might trigger a call to sys.morestack. + * this sequence needs to fit in the bottom section of the stack. + * on amd64, sys.morestack's frame is 40 bytes, and + * sys.deferproc's frame is 56 bytes. that fits well within + * the StackGuard - StackSmall = 128 bytes at the bottom. + * there may be other sequences lurking or yet to be written + * that require more stack. sys.morestack checks to make sure + * the stack has not completely overflowed and should + * catch such sequences. + */ +enum +{ + // byte offset of stack guard (g->stackguard) above bottom of stack. + StackGuard = 256, + + // checked frames are allowed to protrude below the guard by + // this many bytes. this saves an instruction in the checking + // sequence when the stack frame is tiny. + StackSmall = 128, + + // extra space in the frame (beyond the function for which + // the frame is allocated) is assumed not to be much bigger + // than this amount. it may not be used efficiently if it is. + StackBig = 4096, +}; + +void +oldstack(void) +{ + Stktop *top; + uint32 args; + byte *sp; + uintptr oldsp, oldpc, oldbase, oldguard; + +// printf("oldstack m->cret=%p\n", m->cret); + + top = (Stktop*)m->curg->stackbase; + + args = (top->magic>>32) & 0xffffLL; + + sp = (byte*)top; + if(args > 0) { + args = (args+7) & ~7; + sp -= args; + mcpy(top->oldsp+2*sizeof(uintptr), sp, args); + } + + oldsp = (uintptr)top->oldsp + sizeof(uintptr); + oldpc = *(uintptr*)oldsp; + oldbase = (uintptr)top->oldbase; + oldguard = (uintptr)top->oldguard; + + stackfree((byte*)m->curg->stackguard - StackGuard); + + m->curg->stackbase = (byte*)oldbase; + m->curg->stackguard = (byte*)oldguard; + m->morestack.SP = (byte*)oldsp; + m->morestack.PC = (byte*)oldpc; + + // These two lines must happen in sequence; + // once g has been changed, must switch to g's stack + // before calling any non-assembly functions. + // TODO(rsc): Perhaps make the new g a parameter + // to gogoret and setspgoto, so that g is never + // explicitly assigned to without also setting + // the stack pointer. + g = m->curg; + gogoret(&m->morestack, m->cret); +} + +#pragma textflag 7 +void +lessstack(void) +{ + g = m->g0; + setspgoto(m->sched.SP, oldstack, nil); +} + +void +newstack(void) +{ + int32 frame, args; + Stktop *top; + byte *stk, *sp; + void (*fn)(void); + + frame = m->morearg & 0xffffffffLL; + args = (m->morearg>>32) & 0xffffLL; + +// printf("newstack frame=%d args=%d moresp=%p morepc=%p\n", frame, args, m->moresp, *(uintptr*)m->moresp); + + if(frame < StackBig) + frame = StackBig; + frame += 1024; // for more functions, Stktop. + stk = stackalloc(frame); + + top = (Stktop*)(stk+frame-sizeof(*top)); + + top->oldbase = m->curg->stackbase; + top->oldguard = m->curg->stackguard; + top->oldsp = m->moresp; + top->magic = m->morearg; + + m->curg->stackbase = (byte*)top; + m->curg->stackguard = stk + StackGuard; + + sp = (byte*)top; + + if(args > 0) { + // Copy args. There have been two function calls + // since they got pushed, so skip over those return + // addresses. + args = (args+7) & ~7; + sp -= args; + mcpy(sp, m->moresp+2*sizeof(uintptr), args); + } + + g = m->curg; + + // sys.morestack's return address + fn = (void(*)(void))(*(uintptr*)m->moresp); + +// printf("fn=%p\n", fn); + + setspgoto(sp, fn, retfromnewstack); + + *(int32*)345 = 123; // never return +} + +#pragma textflag 7 +void +sys·morestack(uintptr u) +{ + while(g == m->g0) { + // very bad news + *(int32*)0x1001 = 123; + } + + // Morestack's frame is about 0x30 bytes on amd64. + // If that the frame ends below the stack bottom, we've already + // overflowed. Stop right now. + while((byte*)&u - 0x30 < m->curg->stackguard - StackGuard) { + // very bad news + *(int32*)0x1002 = 123; + } + + g = m->g0; + m->moresp = (byte*)(&u-1); + setspgoto(m->sched.SP, newstack, nil); + + *(int32*)0x1003 = 123; // never return +} + +G* +malg(int32 stacksize) +{ + G *g; + byte *stk; + + g = malloc(sizeof(G)); + stk = stackalloc(stacksize + StackGuard); + g->stack0 = stk; + g->stackguard = stk + StackGuard; + g->stackbase = stk + StackGuard + stacksize; + return g; +} + +/* + * 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 +sys·newproc(int32 siz, byte* fn, byte* arg0) +{ + byte *stk, *sp; + G *newg; + +//printf("newproc siz=%d fn=%p", siz, fn); + + siz = (siz+7) & ~7; + if(siz > 1024) + throw("sys·newproc: too many args"); + + lock(&sched); + + if((newg = gfget()) != nil){ + newg->status = Gwaiting; + } else { + newg = malg(4096); + newg->status = Gwaiting; + newg->alllink = allg; + allg = newg; + } + stk = newg->stack0; + + newg->stackguard = stk+StackGuard; + + sp = stk + 4096 - 4*8; + newg->stackbase = sp; + + sp -= siz; + mcpy(sp, (byte*)&arg0, siz); + + sp -= sizeof(uintptr); + *(byte**)sp = (byte*)goexit; + + sp -= sizeof(uintptr); // retpc used by gogo + newg->sched.SP = sp; + newg->sched.PC = fn; + + sched.gcount++; + goidgen++; + newg->goid = goidgen; + + readylocked(newg); + unlock(&sched); + +//printf(" goid=%d\n", newg->goid); +} + +#pragma textflag 7 +void +sys·deferproc(int32 siz, byte* fn, byte* arg0) +{ + Defer *d; + + d = malloc(sizeof(*d) + siz - sizeof(d->args)); + d->fn = fn; + d->sp = (byte*)&arg0; + d->siz = siz; + mcpy(d->args, d->sp, d->siz); + + d->link = g->defer; + g->defer = d; +} + +#pragma textflag 7 +void +sys·deferreturn(uintptr arg0) +{ + Defer *d; + byte *sp, *fn; + uintptr *caller; + + d = g->defer; + if(d == nil) + return; + sp = (byte*)&arg0; + if(d->sp != sp) + return; + mcpy(d->sp, d->args, d->siz); + g->defer = d->link; + fn = d->fn; + free(d); + jmpdefer(fn, sp); + } + +void +runtime·Breakpoint(void) +{ + breakpoint(); +} + +void +runtime·Goexit(void) +{ + goexit(); +} + +void +runtime·Gosched(void) +{ + gosched(); +} + diff --git a/src/pkg/runtime/rune.c b/src/pkg/runtime/rune.c new file mode 100644 index 000000000..652ccdfa6 --- /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< 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: + *rune = Bad; + return 0; + +} + +int32 +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.c b/src/pkg/runtime/runtime.c new file mode 100644 index 000000000..c5ba3e6a5 --- /dev/null +++ b/src/pkg/runtime/runtime.c @@ -0,0 +1,462 @@ +// Copyright 2009 The Go Authors. 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" + +int32 panicking = 0; +int32 maxround = sizeof(uintptr); + +int32 +gotraceback(void) +{ + byte *p; + + p = getenv("GOTRACEBACK"); + if(p == nil || p[0] == '\0') + return 1; // default is on + return atoi(p); +} + +void +sys·panicl(int32 lno) +{ + uint8 *sp; + + if(panicking) { + printf("double panic\n"); + exit(3); + } + panicking++; + + printf("\npanic PC=%X\n", (uint64)(uintptr)&lno); + sp = (uint8*)&lno; + if(gotraceback()){ + traceback(sys·getcallerpc(&lno), sp, g); + tracebackothers(g); + } + breakpoint(); // so we can grab it in a debugger + exit(2); +} + +void +sys·throwindex(void) +{ + throw("index out of range"); +} + +void +sys·throwreturn(void) +{ + throw("no return at end of a typed function"); +} + +void +sys·throwinit(void) +{ + throw("recursive call during initialization"); +} + +void +throw(int8 *s) +{ + printf("throw: %s\n", s); + sys·panicl(-1); + *(int32*)0 = 0; // not reached + exit(1); // even more not reached +} + +void +mcpy(byte *t, byte *f, uint32 n) +{ + while(n > 0) { + *t = *f; + t++; + f++; + n--; + } +} + +int32 +mcmp(byte *s1, byte *s2, uint32 n) +{ + uint32 i; + byte c1, c2; + + for(i=0; i c2) + return +1; + } + return 0; +} + + +void +mmov(byte *t, byte *f, uint32 n) +{ + if(t < f) { + while(n > 0) { + *t = *f; + t++; + f++; + n--; + } + } else { + t += n; + f += n; + while(n > 0) { + t--; + f--; + *t = *f; + n--; + } + } +} + +byte* +mchr(byte *p, byte c, byte *ep) +{ + for(; p < ep; p++) + if(*p == c) + return p; + return nil; +} + +uint32 +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; + +Array os·Args; +Array os·Envs; + +void +args(int32 c, uint8 **v) +{ + argc = c; + argv = v; +} + +void +goargs(void) +{ + String *gargv; + String *genvv; + int32 i, envc; + + for(envc=0; argv[argc+1+envc] != 0; envc++) + ; + + gargv = malloc(argc*sizeof gargv[0]); + genvv = malloc(envc*sizeof genvv[0]); + + for(i=0; i 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; + uint32 i; + + ba = a; + bb = b; + for(i=0; iaddr = addr; + s->g = nil; + + lock(&semlock); + s->prev = semlast; + s->next = nil; + if(semlast) + semlast->next = s; + else + semfirst = s; + semlast = s; + unlock(&semlock); +} + +static void +semdequeue(Sema *s) +{ + lock(&semlock); + if(s->next) + s->next->prev = s->prev; + else + semlast = s->prev; + if(s->prev) + s->prev->next = s->next; + else + semfirst = s->next; + s->prev = nil; + s->next = nil; + unlock(&semlock); +} + +static void +semwakeup(uint32 *addr) +{ + Sema *s; + + lock(&semlock); + for(s=semfirst; s; s=s->next) { + if(s->addr == addr && s->g) { + ready(s->g); + s->g = nil; + break; + } + } + unlock(&semlock); +} + +// Step 1 of sleep: make ourselves available for wakeup. +// TODO(rsc): Maybe we can write a version without +// locks by using cas on s->g. Maybe not: I need to +// think more about whether it would be correct. +static void +semsleep1(Sema *s) +{ + lock(&semlock); + s->g = g; + unlock(&semlock); +} + +// Decided not to go through with it: undo step 1. +static void +semsleepundo1(Sema *s) +{ + lock(&semlock); + if(s->g != nil) { + s->g = nil; // back ourselves out + } else { + // If s->g == nil already, semwakeup + // already readied us. Since we never stopped + // running, readying us just set g->readyonstop. + // Clear it. + if(g->readyonstop == 0) + *(int32*)0x555 = 555; + g->readyonstop = 0; + } + unlock(&semlock); +} + +// Step 2: wait for the wakeup. +static void +semsleep2(Sema *s) +{ + USED(s); + g->status = Gwaiting; + gosched(); +} + +static int32 +cansemacquire(uint32 *addr) +{ + uint32 v; + + while((v = *addr) > 0) + if(cas(addr, v, v-1)) + return 1; + return 0; +} + +// For now has no return value. +// Might return an ok (not interrupted) bool in the future? +void +semacquire(uint32 *addr) +{ + Sema s; + + // Easy case. + if(cansemacquire(addr)) + return; + + // Harder case: + // queue + // try semacquire one more time, sleep if failed + // dequeue + // wake up one more guy to avoid races (TODO(rsc): maybe unnecessary?) + semqueue(addr, &s); + for(;;) { + semsleep1(&s); + if(cansemacquire(addr)) { + semsleepundo1(&s); + break; + } + semsleep2(&s); + } + semdequeue(&s); + semwakeup(addr); +} + +void +semrelease(uint32 *addr) +{ + uint32 v; + + for(;;) { + v = *addr; + if(cas(addr, v, v+1)) + break; + } + semwakeup(addr); +} diff --git a/src/pkg/runtime/sema_go.cgo b/src/pkg/runtime/sema_go.cgo new file mode 100644 index 000000000..eb4082a0d --- /dev/null +++ b/src/pkg/runtime/sema_go.cgo @@ -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 sync +#include "runtime.h" + +func semacquire(addr *uint32) { + semacquire(addr); +} + +func semrelease(addr *uint32) { + semrelease(addr); +} + diff --git a/src/pkg/runtime/string.c b/src/pkg/runtime/string.c new file mode 100644 index 000000000..5bfe8196f --- /dev/null +++ b/src/pkg/runtime/string.c @@ -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. + +#include "runtime.h" + +String emptystring; + +int32 +findnull(byte *s) +{ + int32 l; + + if(s == nil) + return 0; + for(l=0; s[l]!=0; l++) + ; + return l; +} + +int32 maxstring; + +String +gostringsize(int32 l) +{ + String s; + + if(l == 0) + return emptystring; + s.str = mal(l+1); // leave room for NUL for C runtime (e.g., callers of getenv) + s.len = l; + if(l > maxstring) + maxstring = l; + return s; +} + +String +gostring(byte *str) +{ + int32 l; + String s; + + l = findnull(str); + s = gostringsize(l); + mcpy(s.str, str, l); + return s; +} + +void +sys·catstring(String s1, String s2, String s3) +{ + if(s1.len == 0) { + s3 = s2; + goto out; + } + if(s2.len == 0) { + s3 = s1; + goto out; + } + + s3 = gostringsize(s1.len + s2.len); + mcpy(s3.str, s1.str, s1.len); + mcpy(s3.str+s1.len, s2.str, s2.len); + +out: + FLUSH(&s3); +} + +static void +prbounds(int8* s, int32 a, int32 b, int32 c) +{ + prints(s); + prints(" "); + sys·printint(a); + prints("<"); + sys·printint(b); + prints(">"); + sys·printint(c); + prints("\n"); + throw("string bounds"); +} + +uint32 +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 c2) + return +1; + } + if(s1.len < s2.len) + return -1; + if(s1.len > s2.len) + return +1; + return 0; +} + +void +sys·cmpstring(String s1, String s2, int32 v) +{ + v = cmpstring(s1, s2); + FLUSH(&v); +} + +int32 +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; + } +} + +void +sys·slicestring(String si, int32 lindex, int32 hindex, String so) +{ + int32 l; + + if(lindex < 0 || lindex > si.len || + hindex < lindex || hindex > si.len) { + sys·printpc(&si); + prints(" "); + prbounds("slice", lindex, si.len, hindex); + } + + l = hindex-lindex; + so.str = si.str + lindex; + so.len = l; + +// alternate to create a new string +// so = gostringsize(l); +// mcpy(so.str, si.str+lindex, l); + + FLUSH(&so); +} + +void +sys·indexstring(String s, int32 i, byte b) +{ + if(i < 0 || i >= s.len) { + sys·printpc(&s); + prints(" "); + prbounds("index", 0, i, s.len); + } + + b = s.str[i]; + FLUSH(&b); +} + +void +sys·intstring(int64 v, String s) +{ + s = gostringsize(8); + s.len = runetochar(s.str, v); + FLUSH(&s); +} + +void +sys·arraystring(Array b, String s) +{ + s = gostringsize(b.nel); + mcpy(s.str, b.array, s.len); + FLUSH(&s); +} + +void +sys·arraystringi(Array b, String s) +{ + int32 siz1, siz2, i; + int32 *a; + byte dum[8]; + + a = (int32*)b.array; + siz1 = 0; + for(i=0; i= siz1) + break; + siz2 += runetochar(s.str+siz2, a[i]); + } + s.len = siz2; + + FLUSH(&s); +} + +enum +{ + Runeself = 0x80, +}; + +// func stringiter(string, int) (retk int); +void +sys·stringiter(String s, int32 k, int32 retk) +{ + 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 + charntorune(&l, s.str+k, s.len-k); + +out: + FLUSH(&retk); +} + +// func stringiter2(string, int) (retk int, retv any); +void +sys·stringiter2(String s, int32 k, int32 retk, int32 retv) +{ + 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 + charntorune(&retv, s.str+k, s.len-k); + +out: + FLUSH(&retk); + FLUSH(&retv); +} diff --git a/src/pkg/runtime/symtab.c b/src/pkg/runtime/symtab.c new file mode 100644 index 000000000..b4802715e --- /dev/null +++ b/src/pkg/runtime/symtab.c @@ -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. + +// 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" + +// TODO(rsc): Move this *under* the text segment. +// Then define names for these addresses instead of hard-coding magic ones. +#ifdef _64BIT +#define SYMCOUNTS ((int32*)(0x99LL<<32)) // known to 6l +#define SYMDATA ((byte*)(0x99LL<<32) + 8) +#else +#define SYMCOUNTS ((int32*)(0x99LL<<24)) // known to 8l +#define SYMDATA ((byte*)(0x99LL<<24) + 8) +#endif + + +// Return a pointer to a byte array containing the symbol table segment. +void +sys·symdat(Array *symtab, Array *pclntab) +{ + Array *a; + int32 *v; + + v = SYMCOUNTS; + + a = mal(sizeof *a); + a->nel = v[0]; + a->cap = a->nel; + a->array = SYMDATA; + symtab = a; + FLUSH(&symtab); + + a = mal(sizeof *a); + a->nel = v[1]; + a->cap = a->nel; + a->array = SYMDATA + v[0]; + pclntab = a; + FLUSH(&pclntab); +} + +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*)) +{ + int32 *v; + byte *p, *ep, *q; + Sym s; + + v = SYMCOUNTS; + p = SYMDATA; + ep = p + v[0]; + 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 = mchr(p, '\0', ep); + if(q == nil) + break; + p = q+1; + } + q = mchr(p, '\0', ep); + if(q == nil) + break; + s.gotype = p; + p = q+1; + fn(&s); + } +} + +// Symtab walker; accumulates info about functions. + +static Func *func; +static int32 nfunc; + +static byte **fname; +static int32 nfname; + +static void +dofunc(Sym *sym) +{ + Func *f; + + switch(sym->symtype) { + case 't': + case 'T': + if(strcmp(sym->name, (byte*)"etext") == 0) + break; + if(func == nil) { + nfunc++; + break; + } + f = &func[nfunc++]; + f->name = gostring(sym->name); + f->entry = sym->value; + 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) + 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 = findnull(q); + if(p+1+len >= ep) + break; + if(p > buf && p[-1] != '/') + *p++ = '/'; + mcpy(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). +static void +dosrcline(Sym *sym) +{ + static byte srcbuf[1000]; + static String srcstring; + static int32 lno, incstart; + static int32 nf, nhist; + Func *f; + + switch(sym->symtype) { + case 't': + case 'T': + if(strcmp(sym->name, (byte*)"etext") == 0) + break; + f = &func[nf++]; + f->src = srcstring; + f->ln0 += lno; + break; + case 'z': + if(sym->value == 1) { + // entry for main source file for a new object. + makepath(srcbuf, sizeof srcbuf, sym->name+1); + srcstring = gostring(srcbuf); + lno = 0; + nhist = 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; + }else{ + if(--nhist == 0) + lno -= sym->value - incstart; + } + } + } +} + +enum { PcQuant = 1 }; + +// 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 *v; + + // pc/ln table bounds + v = SYMCOUNTS; + p = SYMDATA; + p += v[0]; + ep = p+v[1]; + + f = func; + ef = func + nfunc; + pc = func[0].entry; // text base + f->pcln.array = p; + f->pc0 = pc - PcQuant; + line = 0; + for(; p < ep; p++) { + if(f < ef && pc >= (f+1)->entry) { + f->pcln.nel = p - f->pcln.array; + f->pcln.cap = f->pcln.nel; + f++; + f->pcln.array = p; + f->pc0 = pc; + f->ln0 = line; + } + if(*p == 0) { + // 4 byte add to line + line += (p[1]<<24) | (p[2]<<16) | (p[3]<<8) | p[4]; + p += 4; + } else if(*p <= 64) { + line += *p; + } else if(*p <= 128) { + line -= *p - 64; + } else { + pc += PcQuant*(*p - 129); + } + pc += PcQuant; + } + if(f < ef) { + f->pcln.nel = p - f->pcln.array; + f->pcln.cap = f->pcln.nel; + } +} + + +// Return actual file line number for targetpc in func f. +// (Source file is f->src.) +int32 +funcline(Func *f, uint64 targetpc) +{ + byte *p, *ep; + uintptr pc; + int32 line; + + p = f->pcln.array; + ep = p + f->pcln.nel; + pc = f->pc0; + line = f->ln0; + for(; p < ep; p++) { + if(pc >= targetpc) + return line; + if(*p == 0) { + line += (p[1]<<24) | (p[2]<<16) | (p[3]<<8) | p[4]; + p += 4; + } else if(*p <= 64) { + line += *p; + } else if(*p <= 128) { + line -= *p - 64; + } else { + pc += PcQuant*(*p - 129); + } + pc += PcQuant; + } + return line; +} + +static void +buildfuncs(void) +{ + extern byte etext[]; + + if(func != nil) + return; + // count funcs, fnames + nfunc = 0; + nfname = 0; + walksymtab(dofunc); + + // initialize tables + func = mal((nfunc+1)*sizeof func[0]); + func[nfunc].entry = (uint64)etext; + fname = 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); +} + +Func* +findfunc(uintptr addr) +{ + Func *f; + int32 nf, n; + + if(func == nil) + buildfuncs(); + 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. + prints("findfunc unreachable\n"); + return nil; +} diff --git a/src/pkg/sort/Makefile b/src/pkg/sort/Makefile new file mode 100644 index 000000000..4d193f859 --- /dev/null +++ b/src/pkg/sort/Makefile @@ -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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D= + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + sort.$O\ + + +phases: a1 +_obj$D/sort.a: phases + +a1: $(O1) + $(AR) grc _obj$D/sort.a sort.$O + rm -f $(O1) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/sort.a + +$(O1): newpkg +$(O2): a1 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/sort.a + +packages: _obj$D/sort.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/sort.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/sort.a diff --git a/src/pkg/sort/sort.go b/src/pkg/sort/sort.go new file mode 100644 index 000000000..99ba0a0ef --- /dev/null +++ b/src/pkg/sort/sort.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. + +// The sort package provides primitives for sorting arrays +// and user-defined collections. +package sort + +// SortInterface is the interface that a type, typically a collection, +// must implement for its contents to be sorted in increasing order. +// Its methods require that the elements of the collection be enumerated +// by an integer index. +type SortInterface interface { + // Len is the number of elements in the collection. + Len() int; + // Less returns whether the element with index i is should sort + // before the element with index j. + // TODO(r): should this method be renamed Before? + 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 SortInterface, 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 SortInterface, 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 SortInterface, a, b, n int) { + for i := 0; i < n; i++ { + data.Swap(a+i, b+i); + } +} + +func doPivot(data SortInterface, lo, hi int) (midlo, midhi int) { + m := (lo+hi)/2; + if hi - lo > 40 { + // Tukey's ``Ninther,'' median of three medians of three. + s := (hi - lo) / 8; + medianOfThree(data, lo, lo+s, lo+2*s); + medianOfThree(data, m, m-s, m+s); + medianOfThree(data, hi-1, hi-1-s, hi-1-2*s); + } + medianOfThree(data, lo, m, hi-1); + + // Invariants are: + // data[lo] = pivot (set up by ChoosePivot) + // data[lo <= i < a] = pivot + // data[a <= i < b] < pivot + // data[b <= i < c] is unexamined + // data[c <= i < d] > pivot + // data[d <= i < hi] = pivot + // + // Once b meets c, can swap the "= pivot" sections + // into the middle of the array. + pivot := lo; + a, b, c, d := lo+1, lo+1, hi, hi; + for b < c { + if data.Less(b, pivot) { // data[b] < pivot + b++; + continue; + } + if !data.Less(pivot, b) { // data[b] = pivot + data.Swap(a, b); + a++; + b++; + continue; + } + if data.Less(pivot, c-1) { // data[c-1] > pivot + c--; + continue; + } + if !data.Less(c-1, pivot) { // data[c-1] = pivot + data.Swap(c-1, d-1); + c--; + d--; + continue; + } + // data[b] > pivot; data[c-1] < pivot + data.Swap(b, c-1); + b++; + c--; + } + + n := min(b-a, a-lo); + swapRange(data, lo, b-n, n); + + n = min(hi-d, d-c); + swapRange(data, c, hi-n, n); + + return lo+b-a, hi-(d-c); +} + +func quickSort(data SortInterface, a, b int) { + if b - a > 7 { + mlo, mhi := doPivot(data, a, b); + quickSort(data, a, mlo); + quickSort(data, mhi, b); + } else if b - a > 1 { + insertionSort(data, a, b); + } +} + +func Sort(data SortInterface) { + quickSort(data, 0, data.Len()); +} + + +func IsSorted(data SortInterface) bool { + n := data.Len(); + for i := n - 1; i > 0; i-- { + if data.Less(i, i - 1) { + return false; + } + } + return true; +} + + +// Convenience types for common cases + +// IntArray attaches the methods of SortInterface to []int, sorting in increasing order. +type IntArray []int + +func (p IntArray) Len() int { return len(p); } +func (p IntArray) Less(i, j int) bool { return p[i] < p[j]; } +func (p IntArray) Swap(i, j int) { p[i], p[j] = p[j], p[i]; } + + +// FloatArray attaches the methods of SortInterface to []float, sorting in increasing order. +type FloatArray []float + +func (p FloatArray) Len() int { return len(p); } +func (p FloatArray) Less(i, j int) bool { return p[i] < p[j]; } +func (p FloatArray) Swap(i, j int) { p[i], p[j] = p[j], p[i]; } + + +// StringArray attaches the methods of SortInterface to []string, sorting in increasing order. +type StringArray []string + +func (p StringArray) Len() int { return len(p); } +func (p StringArray) Less(i, j int) bool { return p[i] < p[j]; } +func (p StringArray) Swap(i, j int) { p[i], p[j] = p[j], p[i]; } + + +// Convenience wrappers for common cases + +// SortInts sorts an array of ints in increasing order. +func SortInts(a []int) { Sort(IntArray(a)); } +// SortFloats sorts an array of floats in increasing order. +func SortFloats(a []float) { Sort(FloatArray(a)); } +// SortStrings sorts an array of strings in increasing order. +func SortStrings(a []string) { Sort(StringArray(a)); } + + +// IntsAreSorted tests whether an array of ints is sorted in increasing order. +func IntsAreSorted(a []int) bool { return IsSorted(IntArray(a)); } +// FloatsAreSorted tests whether an array of floats is sorted in increasing order. +func FloatsAreSorted(a []float) bool { return IsSorted(FloatArray(a)); } +// StringsAreSorted tests whether an array of strings is sorted in increasing order. +func StringsAreSorted(a []string) bool { return IsSorted(StringArray(a)); } diff --git a/src/pkg/sort/sort_test.go b/src/pkg/sort/sort_test.go new file mode 100644 index 000000000..1747daca6 --- /dev/null +++ b/src/pkg/sort/sort_test.go @@ -0,0 +1,229 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package sort + +import ( + "fmt"; + "rand"; + "sort"; + "testing"; +) + + +var ints = [...]int{74, 59, 238, -784, 9845, 959, 905, 0, 0, 42, 7586, -5467984, 7586} +var floats = [...]float{74.3, 59.0, 238.2, -784.0, 2.3, 9845.768, -959.7485, 905, 7.8, 7.8} +var strings = [...]string{"", "Hello", "foo", "bar", "foo", "f00", "%*&^*&^&", "***"} + +func TestSortIntArray(t *testing.T) { + data := ints; + a := IntArray(&data); + sort.Sort(a); + if !sort.IsSorted(a) { + t.Errorf("sorted %v", ints); + t.Errorf(" got %v", data); + } +} + +func TestSortFloatArray(t *testing.T) { + data := floats; + a := FloatArray(&data); + sort.Sort(a); + if !sort.IsSorted(a) { + t.Errorf("sorted %v", floats); + t.Errorf(" got %v", data); + } +} + +func TestSortStringArray(t *testing.T) { + data := strings; + a := StringArray(&data); + sort.Sort(a); + if !sort.IsSorted(a) { + t.Errorf("sorted %v", strings); + t.Errorf(" got %v", data); + } +} + +func TestSortInts(t *testing.T) { + data := ints; + sort.SortInts(&data); + if !sort.IntsAreSorted(&data) { + t.Errorf("sorted %v", ints); + t.Errorf(" got %v", data); + } +} + +func TestSortFloats(t *testing.T) { + data := floats; + sort.SortFloats(&data); + if !sort.FloatsAreSorted(&data) { + t.Errorf("sorted %v", floats); + t.Errorf(" got %v", data); + } +} + +func TestSortStrings(t *testing.T) { + data := strings; + sort.SortStrings(&data); + if !sort.StringsAreSorted(&data) { + t.Errorf("sorted %v", strings); + t.Errorf(" got %v", data); + } +} + +func TestSortLarge_Random(t *testing.T) { + data := make([]int, 1000000); + for i := 0; i < len(data); i++ { + data[i] = rand.Intn(100); + } + if sort.IntsAreSorted(data) { + t.Fatalf("terrible rand.rand"); + } + sort.SortInts(data); + if !sort.IntsAreSorted(data) { + t.Errorf("sort didn't sort - 1M ints"); + } +} + +const ( + _Sawtooth = iota; + _Rand; + _Stagger; + _Plateau; + _Shuffle; + _NDist; +) + +const ( + _Copy = iota; + _Reverse; + _ReverseFirstHalf; + _ReverseSecondHalf; + _Sorted; + _Dither; + _NMode; +) + +type testingData struct { + desc string; + t *testing.T; + data []int; + maxswap int; // number of swaps allowed + nswap int; +} + +func (d *testingData) Len() int { return len(d.data); } +func (d *testingData) Less(i, j int) bool { return d.data[i] < d.data[j]; } +func (d *testingData) Swap(i, j int) { + if d.nswap >= d.maxswap { + d.t.Errorf("%s: used %d swaps sorting array of %d", d.desc, d.nswap, len(d.data)); + d.t.FailNow(); + } + d.nswap++; + d.data[i], d.data[j] = d.data[j], d.data[i]; +} + +func lg(n int) int { + i := 0; + for 1<Makefile + +D= + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + atoi.$O\ + decimal.$O\ + itoa.$O\ + quote.$O\ + +O2=\ + ftoa.$O\ + +O3=\ + atof.$O\ + + +phases: a1 a2 a3 +_obj$D/strconv.a: phases + +a1: $(O1) + $(AR) grc _obj$D/strconv.a atoi.$O decimal.$O itoa.$O quote.$O + rm -f $(O1) + +a2: $(O2) + $(AR) grc _obj$D/strconv.a ftoa.$O + rm -f $(O2) + +a3: $(O3) + $(AR) grc _obj$D/strconv.a atof.$O + rm -f $(O3) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/strconv.a + +$(O1): newpkg +$(O2): a1 +$(O3): a2 +$(O4): a3 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/strconv.a + +packages: _obj$D/strconv.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/strconv.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/strconv.a diff --git a/src/pkg/strconv/atof.go b/src/pkg/strconv/atof.go new file mode 100644 index 000000000..c257b2a33 --- /dev/null +++ b/src/pkg/strconv/atof.go @@ -0,0 +1,372 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// decimal to binary floating point conversion. +// Algorithm: +// 1) Store input in multiprecision decimal. +// 2) Multiply/divide decimal by powers of two until in range [0.5, 1) +// 3) Multiply by 2^precision and round to get mantissa. + +// The strconv package implements conversions to and from +// string representations of basic data types. +package strconv + +import ( + "math"; + "os"; + "strconv"; +) + +var optimize = true // can change for testing + +// 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' { + 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<>= 1; + exp++; + if exp-flt.bias >= 1< 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. +// +// If s is not syntactically well-formed, Atof32 returns err = 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 = os.ERANGE. +func Atof32(s string) (f float32, err os.Error) { + neg, d, trunc, ok := stringToDecimal(s); + if !ok { + return 0, 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 = 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) { + neg, d, trunc, ok := stringToDecimal(s); + if !ok { + return 0, 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 = os.ERANGE; + } + return f, err +} + +// Atof is like Atof32 or Atof64, depending on the size of float. +func Atof(s string) (f float, err os.Error) { + if FloatSize == 32 { + f1, err1 := Atof32(s); + return float(f1), err1; + } + f1, err1 := Atof64(s); + return float(f1), err1; +} + diff --git a/src/pkg/strconv/atof_test.go b/src/pkg/strconv/atof_test.go new file mode 100644 index 000000000..6782f274a --- /dev/null +++ b/src/pkg/strconv/atof_test.go @@ -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. + +package strconv +import ( + "fmt"; + "os"; + "strconv"; + "testing" +) + +type atofTest struct { + in string; + out string; + err os.Error; +} + +var atoftests = []atofTest { + atofTest{ "", "0", os.EINVAL }, + atofTest{ "1", "1", nil }, + atofTest{ "+1", "1", nil }, + atofTest{ "1x", "0", os.EINVAL }, + atofTest{ "1.1.", "0", os.EINVAL }, + atofTest{ "1e23", "1e+23", nil }, + atofTest{ "100000000000000000000000", "1e+23", nil }, + atofTest{ "1e-100", "1e-100", nil }, + atofTest{ "123456700", "1.234567e+08", nil }, + atofTest{ "99999999999999974834176", "9.999999999999997e+22", nil }, + atofTest{ "100000000000000000000001", "1.0000000000000001e+23", nil }, + atofTest{ "100000000000000008388608", "1.0000000000000001e+23", nil }, + atofTest{ "100000000000000016777215", "1.0000000000000001e+23", nil }, + atofTest{ "100000000000000016777216", "1.0000000000000003e+23", nil }, + atofTest{ "-1", "-1", nil }, + atofTest{ "-0", "-0", nil }, + atofTest{ "1e-20", "1e-20", nil }, + atofTest{ "625e-3", "0.625", nil }, + + // largest float64 + atofTest{ "1.7976931348623157e308", "1.7976931348623157e+308", nil }, + atofTest{ "-1.7976931348623157e308", "-1.7976931348623157e+308", nil }, + // next float64 - too large + atofTest{ "1.7976931348623159e308", "+Inf", os.ERANGE }, + atofTest{ "-1.7976931348623159e308", "-Inf", os.ERANGE }, + // the border is ...158079 + // borderline - okay + atofTest{ "1.7976931348623158e308", "1.7976931348623157e+308", nil }, + atofTest{ "-1.7976931348623158e308", "-1.7976931348623157e+308", nil }, + // borderline - too large + atofTest{ "1.797693134862315808e308", "+Inf", os.ERANGE }, + atofTest{ "-1.797693134862315808e308", "-Inf", os.ERANGE }, + + // a little too large + atofTest{ "1e308", "1e+308", nil }, + atofTest{ "2e308", "+Inf", os.ERANGE }, + atofTest{ "1e309", "+Inf", os.ERANGE }, + + // way too large + atofTest{ "1e310", "+Inf", os.ERANGE }, + atofTest{ "-1e310", "-Inf", os.ERANGE }, + atofTest{ "1e400", "+Inf", os.ERANGE }, + atofTest{ "-1e400", "-Inf", os.ERANGE }, + atofTest{ "1e400000", "+Inf", os.ERANGE }, + atofTest{ "-1e400000", "-Inf", os.ERANGE }, + + // denormalized + atofTest{ "1e-305", "1e-305", nil }, + atofTest{ "1e-306", "1e-306", nil }, + atofTest{ "1e-307", "1e-307", nil }, + atofTest{ "1e-308", "1e-308", nil }, + atofTest{ "1e-309", "1e-309", nil }, + atofTest{ "1e-310", "1e-310", nil }, + atofTest{ "1e-322", "1e-322", nil }, + // smallest denormal + atofTest{ "5e-324", "5e-324", nil }, + // too small + atofTest{ "4e-324", "0", nil }, + // way too small + atofTest{ "1e-350", "0", nil }, + atofTest{ "1e-400000", "0", nil }, + + // try to overflow exponent + atofTest{ "1e-4294967296", "0", nil }, + atofTest{ "1e+4294967296", "+Inf", os.ERANGE }, + atofTest{ "1e-18446744073709551616", "0", nil }, + atofTest{ "1e+18446744073709551616", "+Inf", os.ERANGE }, + + // Parse errors + atofTest{ "1e", "0", os.EINVAL }, + atofTest{ "1e-", "0", os.EINVAL }, + atofTest{ ".e-1", "0", os.EINVAL }, +} + +func testAtof(t *testing.T, opt bool) { + oldopt := strconv.optimize; + strconv.optimize = opt; + for i := 0; i < len(atoftests); i++ { + test := &atoftests[i]; + out, err := strconv.Atof64(test.in); + outs := strconv.Ftoa64(out, 'g', -1); + if outs != test.out || err != test.err { + t.Errorf("strconv.Atof64(%v) = %v, %v want %v, %v\n", + test.in, out, err, test.out, test.err); + } + + if float64(float32(out)) == out { + out32, err := strconv.Atof32(test.in); + outs := strconv.Ftoa32(out32, 'g', -1); + if outs != test.out || err != test.err { + t.Errorf("strconv.Atof32(%v) = %v, %v want %v, %v # %v\n", + test.in, out32, err, test.out, test.err, out); + } + } + + if FloatSize == 64 || float64(float32(out)) == out { + outf, err := strconv.Atof(test.in); + outs := strconv.Ftoa(outf, 'g', -1); + if outs != test.out || err != test.err { + t.Errorf("strconv.Ftoa(%v) = %v, %v want %v, %v # %v\n", + test.in, outf, err, test.out, test.err, out); + } + } + } + strconv.optimize = oldopt; +} + +func TestAtof(t *testing.T) { + testAtof(t, true); +} + +func TestAtofSlow(t *testing.T) { + testAtof(t, false); +} diff --git a/src/pkg/strconv/atoi.go b/src/pkg/strconv/atoi.go new file mode 100644 index 000000000..a5d896a05 --- /dev/null +++ b/src/pkg/strconv/atoi.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 strconv +import "os" + +func computeIntsize() uint { + siz := uint(8); + for 1<= 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. +// +// Btoui64 returns err == os.EINVAL if b is out of +// range or s is empty or contains invalid digits. +// It returns err == os.ERANGE if the value corresponding +// to s cannot be represented by a uint64. +func Btoui64(s string, b int) (n uint64, err os.Error) { + if b < 2 || b > 36 || len(s) < 1 { + return 0, os.EINVAL; + } + + n = 0; + cutoff := cutoff64(b); + + for i := 0; i < len(s); i++ { + var v byte; + switch { + case '0' <= s[i] && s[i] <= '9': + v = s[i] - '0'; + case 'a' <= s[i] && s[i] <= 'z': + v = s[i] - 'a' + 10; + case 'A' <= s[i] && s[i] <= 'Z': + v = s[i] - 'A' + 10; + default: + return 0, os.EINVAL; + } + if int(v) >= b { + return 0, os.EINVAL; + } + + if n >= cutoff { + // n*b overflows + return 1<<64-1, os.ERANGE; + } + n *= uint64(b); + + n1 := n+uint64(v); + if n1 < n { + // n+v overflows + return 1<<64-1, os.ERANGE; + } + n = n1; + } + + return n, nil; +} + +// Atoui64 interprets a string s as an unsigned decimal, octal, or +// hexadecimal number and returns the corresponding value n. +// The default base is decimal. Strings beginning with 0x are +// hexadecimal; strings beginning with 0 are octal. +// +// 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) { + // Empty string bad. + if len(s) == 0 { + return 0, os.EINVAL + } + + // Look for octal, hex prefix. + if s[0] == '0' && len(s) > 1 { + if s[1] == 'x' || s[1] == 'X' { + // hex + return Btoui64(s[2:len(s)], 16); + } + // octal + return Btoui64(s[1:len(s)], 8); + } + // decimal + return Btoui64(s, 10); +} + + +// Atoi64 is like Atoui64 but allows signed numbers and +// returns its result in an int64. +func Atoi64(s string) (i int64, err os.Error) { + // Empty string bad. + if len(s) == 0 { + return 0, os.EINVAL + } + + // Pick off leading sign. + neg := false; + if s[0] == '+' { + s = s[1:len(s)] + } else if s[0] == '-' { + neg = true; + s = s[1:len(s)] + } + + // Convert unsigned and check range. + var un uint64; + un, err = Atoui64(s); + if err != nil && err != os.ERANGE { + return 0, err + } + if !neg && un >= 1<<63 { + return 1<<63-1, os.ERANGE + } + if neg && un > 1<<63 { + return -1<<63, os.ERANGE + } + n := int64(un); + if neg { + n = -n + } + return n, nil +} + +// 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 != os.ERANGE { + return 0, e1 + } + i = uint(i1); + if uint64(i) != i1 { + // TODO: return uint(^0), os.ERANGE. + i1 = 1<<64-1; + return uint(i1), 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 != os.ERANGE { + return 0, e1 + } + i = int(i1); + if int64(i) != i1 { + if i1 < 0 { + return -1<<(intsize-1), os.ERANGE + } + return 1<<(intsize-1) - 1, 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..e4a9f955d --- /dev/null +++ b/src/pkg/strconv/atoi_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 strconv + +import ( + "fmt"; + "os"; + "strconv"; + "testing" +) + +type atoui64Test struct { + in string; + out uint64; + err os.Error; +} + +var atoui64tests = []atoui64Test { + atoui64Test{"", 0, os.EINVAL}, + atoui64Test{"0", 0, nil}, + atoui64Test{"1", 1, nil}, + atoui64Test{"12345", 12345, nil}, + atoui64Test{"012345", 012345, nil}, + atoui64Test{"0x12345", 0x12345, nil}, + atoui64Test{"0X12345", 0x12345, nil}, + atoui64Test{"12345x", 0, os.EINVAL}, + atoui64Test{"98765432100", 98765432100, nil}, + atoui64Test{"18446744073709551615", 1<<64-1, nil}, + atoui64Test{"18446744073709551616", 1<<64-1, os.ERANGE}, + atoui64Test{"18446744073709551620", 1<<64-1, os.ERANGE}, + atoui64Test{"0xFFFFFFFFFFFFFFFF", 1<<64-1, nil}, + atoui64Test{"0x10000000000000000", 1<<64-1, os.ERANGE}, + atoui64Test{"01777777777777777777777", 1<<64-1, nil}, + atoui64Test{"01777777777777777777778", 0, os.EINVAL}, + atoui64Test{"02000000000000000000000", 1<<64-1, os.ERANGE}, + atoui64Test{"0200000000000000000000", 1<<61, nil}, +} + +type atoi64Test struct { + in string; + out int64; + err os.Error; +} + +var atoi64test = []atoi64Test { + atoi64Test{"", 0, os.EINVAL}, + atoi64Test{"0", 0, nil}, + atoi64Test{"-0", 0, nil}, + atoi64Test{"1", 1, nil}, + atoi64Test{"-1", -1, nil}, + atoi64Test{"12345", 12345, nil}, + atoi64Test{"-12345", -12345, nil}, + atoi64Test{"012345", 012345, nil}, + atoi64Test{"-012345", -012345, nil}, + atoi64Test{"0x12345", 0x12345, nil}, + atoi64Test{"-0X12345", -0x12345, nil}, + atoi64Test{"12345x", 0, os.EINVAL}, + atoi64Test{"-12345x", 0, os.EINVAL}, + atoi64Test{"98765432100", 98765432100, nil}, + atoi64Test{"-98765432100", -98765432100, nil}, + atoi64Test{"9223372036854775807", 1<<63-1, nil}, + atoi64Test{"-9223372036854775807", -(1<<63-1), nil}, + atoi64Test{"9223372036854775808", 1<<63-1, os.ERANGE}, + atoi64Test{"-9223372036854775808", -1<<63, nil}, + atoi64Test{"9223372036854775809", 1<<63-1, os.ERANGE}, + atoi64Test{"-9223372036854775809", -1<<63, os.ERANGE}, +} + +type atoui32Test struct { + in string; + out uint32; + err os.Error; +} + +var atoui32tests = []atoui32Test { + atoui32Test{"", 0, os.EINVAL}, + atoui32Test{"0", 0, nil}, + atoui32Test{"1", 1, nil}, + atoui32Test{"12345", 12345, nil}, + atoui32Test{"012345", 012345, nil}, + atoui32Test{"0x12345", 0x12345, nil}, + atoui32Test{"0X12345", 0x12345, nil}, + atoui32Test{"12345x", 0, os.EINVAL}, + atoui32Test{"987654321", 987654321, nil}, + atoui32Test{"4294967295", 1<<32-1, nil}, + atoui32Test{"4294967296", 1<<32-1, os.ERANGE}, +} + +type atoi32Test struct { + in string; + out int32; + err os.Error; +} + +var atoi32tests = []atoi32Test { + atoi32Test{"", 0, os.EINVAL}, + atoi32Test{"0", 0, nil}, + atoi32Test{"-0", 0, nil}, + atoi32Test{"1", 1, nil}, + atoi32Test{"-1", -1, nil}, + atoi32Test{"12345", 12345, nil}, + atoi32Test{"-12345", -12345, nil}, + atoi32Test{"012345", 012345, nil}, + atoi32Test{"-012345", -012345, nil}, + atoi32Test{"0x12345", 0x12345, nil}, + atoi32Test{"-0X12345", -0x12345, nil}, + atoi32Test{"12345x", 0, os.EINVAL}, + atoi32Test{"-12345x", 0, os.EINVAL}, + atoi32Test{"987654321", 987654321, nil}, + atoi32Test{"-987654321", -987654321, nil}, + atoi32Test{"2147483647", 1<<31-1, nil}, + atoi32Test{"-2147483647", -(1<<31-1), nil}, + atoi32Test{"2147483648", 1<<31-1, os.ERANGE}, + atoi32Test{"-2147483648", -1<<31, nil}, + atoi32Test{"2147483649", 1<<31-1, os.ERANGE}, + atoi32Test{"-2147483649", -1<<31, os.ERANGE}, +} + +func TestAtoui64(t *testing.T) { + for i := 0; i < len(atoui64tests); i++ { + test := &atoui64tests[i]; + out, err := strconv.Atoui64(test.in); + if test.out != out || test.err != err { + t.Errorf("strconv.Atoui64(%v) = %v, %v want %v, %v\n", + test.in, out, err, test.out, test.err); + } + } +} + +func TestAtoi64(t *testing.T) { + for i := 0; i < len(atoi64test); i++ { + test := &atoi64test[i]; + out, err := strconv.Atoi64(test.in); + if test.out != out || test.err != err { + t.Errorf("strconv.Atoi64(%v) = %v, %v want %v, %v\n", + test.in, out, err, test.out, test.err); + } + } +} + +func TestAtoui(t *testing.T) { + switch intsize { + case 32: + for i := 0; i < len(atoui32tests); i++ { + test := &atoui32tests[i]; + out, err := strconv.Atoui(test.in); + if test.out != uint32(out) || test.err != err { + t.Errorf("strconv.Atoui(%v) = %v, %v want %v, %v\n", + test.in, out, err, test.out, test.err); + } + } + case 64: + for i := 0; i < len(atoui64tests); i++ { + test := &atoui64tests[i]; + out, err := strconv.Atoui(test.in); + if test.out != uint64(out) || test.err != err { + t.Errorf("strconv.Atoui(%v) = %v, %v want %v, %v\n", + test.in, out, err, test.out, test.err); + } + } + } +} + +func TestAtoi(t *testing.T) { + switch intsize { + case 32: + for i := 0; i < len(atoi32tests); i++ { + test := &atoi32tests[i]; + out, err := strconv.Atoi(test.in); + if test.out != int32(out) || test.err != err { + t.Errorf("strconv.Atoi(%v) = %v, %v want %v, %v\n", + test.in, out, err, test.out, test.err); + } + } + case 64: + for i := 0; i < len(atoi64test); i++ { + test := &atoi64test[i]; + out, err := strconv.Atoi(test.in); + if test.out != int64(out) || test.err != err { + t.Errorf("strconv.Atoi(%v) = %v, %v want %v, %v\n", + test.in, out, err, test.out, test.err); + } + } + } +} + diff --git a/src/pkg/strconv/decimal.go b/src/pkg/strconv/decimal.go new file mode 100644 index 000000000..38d9c47fb --- /dev/null +++ b/src/pkg/strconv/decimal.go @@ -0,0 +1,392 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// 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 + +import "bytes" + +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; +func (a *decimal) Assign(v uint64); +func (a *decimal) Shift(k int) *decimal; +func (a *decimal) Round(nd int) *decimal; +func (a *decimal) RoundUp(nd int) *decimal; +func (a *decimal) RoundDown(nd int) *decimal; +func (a *decimal) RoundedInteger() uint64; + + +func digitZero(dst []byte) int; + +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 += bytes.Copy(buf[w:w+a.nd], a.d[0:a.nd]); + + case a.dp < a.nd: + // decimal point in middle of digits + w += bytes.Copy(buf[w:w+a.dp], a.d[0:a.dp]); + buf[w] = '.'; + w++; + w += bytes.Copy(buf[w:w+a.nd-a.dp], a.d[a.dp:a.nd]); + + default: + // zeros fill space between digits and decimal point + w += bytes.Copy(buf[w:w+a.nd], a.d[0:a.nd]); + w += digitZero(buf[w:w+a.dp-a.nd]); + } + return string(buf[0:w]); +} + +func copy(dst []byte, src []byte) int { + for i := 0; i < len(dst); i++ { + dst[i] = src[i]; + } + return len(dst); +} + +func digitZero(dst []byte) int { + for i := 0; i < len(dst); i++ { + dst[i] = '0'; + } + return len(dst); +} + +// trim trailing zeros from number. +// (They are meaningless; the decimal point is tracked +// independent of the number of digits.) +func trim(a *decimal) { + for a.nd > 0 && a.d[a.nd-1] == '0' { + a.nd--; + } + if a.nd == 0 { + a.dp = 0; + } +} + +// Assign v to a. +func (a *decimal) Assign(v uint64) { + var buf [50]byte; + + // Write reversed decimal in buf. + n := 0; + for v > 0 { + v1 := v/10; + v -= 10*v1; + buf[n] = byte(v + '0'); + n++; + v = v1; + } + + // Reverse again to produce forward decimal in a.d. + a.nd = 0; + for n--; n>=0; n-- { + a.d[a.nd] = buf[n]; + a.nd++; + } + a.dp = a.nd; + trim(a); +} + +func newDecimal(i uint64) *decimal { + a := new(decimal); + a.Assign(i); + return a; +} + +// Maximum shift that we can do in one pass without overflow. +// Signed int has 31 bits, and we have to be able to accomodate 9<>k == 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< 0 { + dig := n>>k; + n -= dig<= 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; + } + + if w != 0 { + // TODO: Remove - has no business panicking. + panicln("strconv: bad leftShift", w); + } + 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 (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. +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..bc82861bd --- /dev/null +++ b/src/pkg/strconv/decimal_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 strconv + +import ( + "fmt"; + "strconv"; + "testing"; +) + +type shiftTest struct { + i uint64; + shift int; + out string; +} + +var shifttests = []shiftTest { + shiftTest{ 0, -100, "0" }, + shiftTest{ 0, 100, "0" }, + shiftTest{ 1, 100, "1267650600228229401496703205376" }, + shiftTest{ 1, -100, + "0.00000000000000000000000000000078886090522101180541" + "17285652827862296732064351090230047702789306640625" }, + shiftTest{ 12345678, 8, "3160493568" }, + shiftTest{ 12345678, -8, "48225.3046875" }, + shiftTest{ 195312, 9, "99999744" }, + shiftTest{ 1953125, 9, "1000000000" }, +} + +func TestDecimalShift(t *testing.T) { + ok := true; + for i := 0; i < len(shifttests); i++ { + test := &shifttests[i]; + s := strconv.newDecimal(test.i).Shift(test.shift).String(); + if s != test.out { + t.Errorf("Decimal %v << %v = %v, want %v\n", + test.i, test.shift, s, test.out); + } + } +} + +type roundTest struct { + i uint64; + nd int; + down, round, up string; + int uint64; +} + +var roundtests = []roundTest { + roundTest{ 0, 4, "0", "0", "0", 0 }, + roundTest{ 12344999, 4, "12340000", "12340000", "12350000", 12340000 }, + roundTest{ 12345000, 4, "12340000", "12340000", "12350000", 12340000 }, + roundTest{ 12345001, 4, "12340000", "12350000", "12350000", 12350000 }, + roundTest{ 23454999, 4, "23450000", "23450000", "23460000", 23450000 }, + roundTest{ 23455000, 4, "23450000", "23460000", "23460000", 23460000 }, + roundTest{ 23455001, 4, "23450000", "23460000", "23460000", 23460000 }, + + roundTest{ 99994999, 4, "99990000", "99990000", "100000000", 99990000 }, + roundTest{ 99995000, 4, "99990000", "100000000", "100000000", 100000000 }, + roundTest{ 99999999, 4, "99990000", "100000000", "100000000", 100000000 }, + + roundTest{ 12994999, 4, "12990000", "12990000", "13000000", 12990000 }, + roundTest{ 12995000, 4, "12990000", "13000000", "13000000", 13000000 }, + roundTest{ 12999999, 4, "12990000", "13000000", "13000000", 13000000 }, +} + +func TestDecimalRound(t *testing.T) { + for i := 0; i < len(roundtests); i++ { + test := &roundtests[i]; + s := strconv.newDecimal(test.i).RoundDown(test.nd).String(); + if s != test.down { + t.Errorf("Decimal %v RoundDown %d = %v, want %v\n", + test.i, test.nd, s, test.down); + } + s = strconv.newDecimal(test.i).Round(test.nd).String(); + if s != test.round { + t.Errorf("Decimal %v Round %d = %v, want %v\n", + test.i, test.nd, s, test.down); + } + s = strconv.newDecimal(test.i).RoundUp(test.nd).String(); + if s != test.up { + t.Errorf("Decimal %v RoundUp %d = %v, want %v\n", + test.i, test.nd, s, test.up); + } + } +} + +type roundIntTest struct { + i uint64; + shift int; + int uint64; +} + +var roundinttests = []roundIntTest { + roundIntTest{ 0, 100, 0 }, + roundIntTest{ 512, -8, 2 }, + roundIntTest{ 513, -8, 2 }, + roundIntTest{ 640, -8, 2 }, + roundIntTest{ 641, -8, 3 }, + roundIntTest{ 384, -8, 2 }, + roundIntTest{ 385, -8, 2 }, + roundIntTest{ 383, -8, 1 }, + roundIntTest{ 1, 100, 1<<64-1 }, + roundIntTest{ 1000, 0, 1000 }, +} + +func TestDecimalRoundedInteger(t *testing.T) { + for i := 0; i < len(roundinttests); i++ { + test := roundinttests[i]; + // TODO: should be able to use int := here. + int1 := strconv.newDecimal(test.i).Shift(test.shift).RoundedInteger(); + if int1 != test.int { + t.Errorf("Decimal %v >> %v RoundedInteger = %v, want %v\n", + test.i, test.shift, int1, test.int); + } + } +} diff --git a/src/pkg/strconv/fp_test.go b/src/pkg/strconv/fp_test.go new file mode 100644 index 000000000..60d7ce6cf --- /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 +import ( + "bufio"; + "fmt"; + "io"; + "os"; + "strconv"; + "strings"; + "testing"; +) + +func pow2(i int) float64 { + switch { + case i < 0: + return 1 / pow2(-i); + case i == 0: + return 1; + case i == 1: + return 2; + } + return pow2(i/2) * pow2(i-i/2); +} + +// Wrapper around strconv.Atof64. Handles dddddp+ddd (binary exponent) +// itself, passes the rest on to strconv.Atof64. +func myatof64(s string) (f float64, ok bool) { + a := strings.Split(s, "p"); + if len(a) == 2 { + n, err := strconv.Atoi64(a[0]); + if err != nil { + return 0, false; + } + e, err1 := strconv.Atoi(a[1]); + if err1 != nil { + println("bad e", a[1]); + return 0, false; + } + v := float64(n); + // We expect that v*pow2(e) fits in a float64, + // but pow2(e) by itself may not. Be careful. + if e <= -1000 { + v *= pow2(-1000); + e += 1000; + for e < 0 { + v /= 2; + e++; + } + return v, true; + } + if e >= 1000 { + v *= pow2(1000); + e -= 1000; + for e > 0 { + v *= 2; + e--; + } + return v, true; + } + return v*pow2(e), true; + } + f1, err := strconv.Atof64(s); + if err != nil { + return 0, false; + } + return f1, true; +} + +// Wrapper around strconv.Atof32. Handles dddddp+ddd (binary exponent) +// itself, passes the rest on to strconv.Atof32. +func myatof32(s string) (f float32, ok bool) { + a := strings.Split(s, "p"); + if len(a) == 2 { + n, err := strconv.Atoi(a[0]); + if err != nil { + println("bad n", a[0]); + return 0, false; + } + e, err1 := strconv.Atoi(a[1]); + if err1 != nil { + println("bad p", a[1]); + return 0, false; + } + return float32(float64(n)*pow2(e)), true; + } + f1, err1 := strconv.Atof32(s); + if err1 != nil { + return 0, false; + } + return f1, true; +} + +func TestFp(t *testing.T) { + f, err := os.Open("testfp.txt", os.O_RDONLY, 0); + if err != nil { + panicln("testfp: open testfp.txt:", err.String()); + } + defer f.Close(); + + b := bufio.NewReader(f); + + lineno := 0; + for { + line, err2 := b.ReadLineString('\n', false); + if err2 == io.ErrEOF { + break; + } + if err2 != nil { + panicln("testfp: read testfp.txt:", err2.String()); + } + lineno++; + if len(line) == 0 || line[0] == '#' { + continue + } + a := strings.Split(line, " "); + if len(a) != 4 { + t.Error("testfp.txt:", lineno, ": wrong field count\n"); + 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); + } +//else print("testfp.txt:", lineno, ": worked! ", s, "\n"); + } +} diff --git a/src/pkg/strconv/ftoa.go b/src/pkg/strconv/ftoa.go new file mode 100644 index 000000000..b17115175 --- /dev/null +++ b/src/pkg/strconv/ftoa.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. + +// 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"; + "strconv"; +) + +// TODO: move elsewhere? +type floatInfo struct { + mantbits uint; + expbits uint; + bias int; +} +var float32info = floatInfo{ 23, 8, -127 } +var float64info = floatInfo{ 52, 11, -1023 } + +func fmtB(neg bool, mant uint64, exp int, flt *floatInfo) string +func fmtE(neg bool, d *decimal, prec int) string +func fmtF(neg bool, d *decimal, prec int) string +func genericFtoa(bits uint64, fmt byte, prec int, flt *floatInfo) string +func max(a, b int) int +func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) + +func floatsize() int { + // Figure out whether float is float32 or float64. + // 1e-35 is representable in both, but 1e-70 + // is too small for a float32. + var f float = 1e-35; + if f*f == 0 { + return 32; + } + return 64; +} + +// Floatsize gives the size of the float type, either 32 or 64. +var FloatSize = floatsize() + +// 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), +// 'f' (-ddd.dddd, no exponent), or +// 'g' ('e' for large exponents, 'f' otherwise). +// +// The precision prec controls the number of digits +// (excluding the exponent) printed by the 'e', 'f', and 'g' formats. +// For 'e' and 'f' it is the number of digits after the decimal point. +// For 'g' it is the total number of digits. +// 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); +} + +// Ftoa behaves as Ftoa32 or Ftoa64, depending on the size of the float type. +func Ftoa(f float, fmt byte, prec int) string { + if FloatSize == 32 { + return Ftoa32(float32(f), fmt, prec); + } + return Ftoa64(float64(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< d.nd { + prec = 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. + eprec := prec; + if shortest { + eprec = 6 + } + exp := d.dp - 1; + if exp < -4 || exp >= eprec { + return fmtE(neg, d, prec - 1); + } + 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: Unless exp == minexp, if the number of digits in d + // is less than 17, it seems unlikely that it could not 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< 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] = 'e'; + 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:len(buf)]); +} + +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..0f0baa514 --- /dev/null +++ b/src/pkg/strconv/ftoa_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 strconv + +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 { + ftoaTest{ 1, 'e', 5, "1.00000e+00" }, + ftoaTest{ 1, 'f', 5, "1.00000" }, + ftoaTest{ 1, 'g', 5, "1" }, + ftoaTest{ 1, 'g', -1, "1" }, + ftoaTest{ 20, 'g', -1, "20" }, + ftoaTest{ 1234567.8, 'g', -1, "1.2345678e+06" }, + ftoaTest{ 200000, 'g', -1, "200000" }, + ftoaTest{ 2000000, 'g', -1, "2e+06" }, + + ftoaTest{ 0, 'e', 5, "0.00000e+00" }, + ftoaTest{ 0, 'f', 5, "0.00000" }, + ftoaTest{ 0, 'g', 5, "0" }, + ftoaTest{ 0, 'g', -1, "0" }, + + ftoaTest{ -1, 'e', 5, "-1.00000e+00" }, + ftoaTest{ -1, 'f', 5, "-1.00000" }, + ftoaTest{ -1, 'g', 5, "-1" }, + ftoaTest{ -1, 'g', -1, "-1" }, + + ftoaTest{ 12, 'e', 5, "1.20000e+01" }, + ftoaTest{ 12, 'f', 5, "12.00000" }, + ftoaTest{ 12, 'g', 5, "12" }, + ftoaTest{ 12, 'g', -1, "12" }, + + ftoaTest{ 123456700, 'e', 5, "1.23457e+08" }, + ftoaTest{ 123456700, 'f', 5, "123456700.00000" }, + ftoaTest{ 123456700, 'g', 5, "1.2346e+08" }, + ftoaTest{ 123456700, 'g', -1, "1.234567e+08" }, + + ftoaTest{ 1.2345e6, 'e', 5, "1.23450e+06" }, + ftoaTest{ 1.2345e6, 'f', 5, "1234500.00000" }, + ftoaTest{ 1.2345e6, 'g', 5, "1.2345e+06" }, + + ftoaTest{ 1e23, 'e', 17, "9.99999999999999916e+22" }, + ftoaTest{ 1e23, 'f', 17, "99999999999999991611392.00000000000000000" }, + ftoaTest{ 1e23, 'g', 17, "9.9999999999999992e+22" }, + + ftoaTest{ 1e23, 'e', -1, "1e+23" }, + ftoaTest{ 1e23, 'f', -1, "100000000000000000000000" }, + ftoaTest{ 1e23, 'g', -1, "1e+23" }, + + ftoaTest{ below1e23, 'e', 17, "9.99999999999999748e+22" }, + ftoaTest{ below1e23, 'f', 17, "99999999999999974834176.00000000000000000" }, + ftoaTest{ below1e23, 'g', 17, "9.9999999999999975e+22" }, + + ftoaTest{ below1e23, 'e', -1, "9.999999999999997e+22" }, + ftoaTest{ below1e23, 'f', -1, "99999999999999970000000" }, + ftoaTest{ below1e23, 'g', -1, "9.999999999999997e+22" }, + + ftoaTest{ above1e23, 'e', 17, "1.00000000000000008e+23" }, + ftoaTest{ above1e23, 'f', 17, "100000000000000008388608.00000000000000000" }, + ftoaTest{ above1e23, 'g', 17, "1.0000000000000001e+23" }, + + ftoaTest{ above1e23, 'e', -1, "1.0000000000000001e+23" }, + ftoaTest{ above1e23, 'f', -1, "100000000000000010000000" }, + ftoaTest{ above1e23, 'g', -1, "1.0000000000000001e+23" }, + + ftoaTest{ fdiv(5e-304, 1e20), 'g', -1, "5e-324" }, + ftoaTest{ fdiv(-5e-304, 1e20), 'g', -1, "-5e-324" }, + + ftoaTest{ 32, 'g', -1, "32" }, + ftoaTest{ 32, 'g', 0, "3e+01" }, + + ftoaTest{ 100, 'x', -1, "%x" }, + + ftoaTest{ math.NaN(), 'g', -1, "NaN" }, + ftoaTest{ -math.NaN(), 'g', -1, "NaN" }, + ftoaTest{ math.Inf(0), 'g', -1, "+Inf" }, + ftoaTest{ math.Inf(-1), 'g', -1, "-Inf" }, + ftoaTest{ -math.Inf(0), 'g', -1, "-Inf" }, + + ftoaTest{ -1, 'b', -1, "-4503599627370496p-52" }, +} + +func TestFtoa(t *testing.T) { + if strconv.FloatSize != 32 { + panic("floatsize: ", strconv.FloatSize); + } + for i := 0; i < len(ftoatests); i++ { + test := &ftoatests[i]; + s := strconv.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); + } + if float64(float32(test.f)) == test.f && test.fmt != 'b' { + s := strconv.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); + } + } + } +} diff --git a/src/pkg/strconv/itoa.go b/src/pkg/strconv/itoa.go new file mode 100644 index 000000000..7f693ea8c --- /dev/null +++ b/src/pkg/strconv/itoa.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 strconv + +// Itob64 returns the string representation of i in the given base. +func Itob64(i int64, base uint) string { + if i == 0 { + return "0" + } + + u := uint64(i); + if i < 0 { + u = -u; + } + + // Assemble decimal in reverse order. + var buf [32]byte; + j := len(buf); + b := uint64(base); + for u > 0 { + j--; + buf[j] = "0123456789abcdefghijklmnopqrstuvwxyz"[u%b]; + u /= b; + } + + if i < 0 { // add sign + j--; + buf[j] = '-' + } + + return string(buf[j:len(buf)]) +} + +// Itoa64 returns the decimal string representation of i. +func Itoa64(i int64) string { + return Itob64(i, 10); +} + +// 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); +} diff --git a/src/pkg/strconv/itoa_test.go b/src/pkg/strconv/itoa_test.go new file mode 100644 index 000000000..34caf9a32 --- /dev/null +++ b/src/pkg/strconv/itoa_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 strconv + +import ( + "fmt"; + "os"; + "strconv"; + "testing"; +) + +type itob64Test struct { + in int64; + base uint; + out string; +} + +var itob64tests = []itob64Test { + itob64Test{ 0, 10, "0" }, + itob64Test{ 1, 10, "1" }, + itob64Test{ -1, 10, "-1" }, + itob64Test{ 12345678, 10, "12345678" }, + itob64Test{ -987654321, 10, "-987654321" }, + itob64Test{ 1<<31-1, 10, "2147483647" }, + itob64Test{ -1<<31+1, 10, "-2147483647" }, + itob64Test{ 1<<31, 10, "2147483648" }, + itob64Test{ -1<<31, 10, "-2147483648" }, + itob64Test{ 1<<31+1, 10, "2147483649" }, + itob64Test{ -1<<31-1, 10, "-2147483649" }, + itob64Test{ 1<<32-1, 10, "4294967295" }, + itob64Test{ -1<<32+1, 10, "-4294967295" }, + itob64Test{ 1<<32, 10, "4294967296" }, + itob64Test{ -1<<32, 10, "-4294967296" }, + itob64Test{ 1<<32+1, 10, "4294967297" }, + itob64Test{ -1<<32-1, 10, "-4294967297" }, + itob64Test{ 1<<50, 10, "1125899906842624" }, + itob64Test{ 1<<63-1, 10, "9223372036854775807" }, + itob64Test{ -1<<63+1, 10, "-9223372036854775807" }, + itob64Test{ -1<<63, 10, "-9223372036854775808" }, + + itob64Test{ 0, 2, "0" }, + itob64Test{ 10, 2, "1010" }, + itob64Test{ -1, 2, "-1" }, + itob64Test{ 1<<15, 2, "1000000000000000" }, + + itob64Test{ -8, 8, "-10" }, + itob64Test{ 057635436545, 8, "57635436545" }, + itob64Test{ 1<<24, 8, "100000000" }, + + itob64Test{ 16, 16, "10" }, + itob64Test{ -0x123456789abcdef, 16, "-123456789abcdef" }, + itob64Test{ 1<<63-1, 16, "7fffffffffffffff" }, + + itob64Test{ 16, 17, "g" }, + itob64Test{ 25, 25, "10" }, + itob64Test{ (((((17*35+24)*35+21)*35+34)*35+12)*35+24)*35+32, 35, "holycow" }, + itob64Test{ (((((17*36+24)*36+21)*36+34)*36+12)*36+24)*36+32, 36, "holycow" }, +} + +func TestItoa(t *testing.T) { + for i := 0; i < len(itob64tests); i++ { + test := itob64tests[i]; + + s := strconv.Itob64(test.in, test.base); + if s != test.out { + t.Errorf("strconv.Itob64(%v, %v) = %v want %v\n", + test.in, test.base, s, test.out); + } + + if int64(int(test.in)) == test.in { + s := strconv.Itob(int(test.in), test.base); + if s != test.out { + t.Errorf("strconv.Itob(%v, %v) = %v want %v\n", + test.in, test.base, s, test.out); + } + } + + if test.base == 10 { + s := strconv.Itoa64(test.in); + if s != test.out { + t.Errorf("strconv.Itoa64(%v) = %v want %v\n", + test.in, s, test.out); + } + + if int64(int(test.in)) == test.in { + s := strconv.Itoa(int(test.in)); + if s != test.out { + t.Errorf("strconv.Itoa(%v) = %v want %v\n", + test.in, s, test.out); + } + } + } + } +} + +// TODO: Use once there is a strconv.uitoa +type uitoa64Test struct { + in uint64; + out string; +} + +// TODO: should be able to call this atoui64tests. +var uitoa64tests = []uitoa64Test { + uitoa64Test{ 1<<63-1, "9223372036854775807" }, + uitoa64Test{ 1<<63, "9223372036854775808" }, + uitoa64Test{ 1<<63+1, "9223372036854775809" }, + uitoa64Test{ 1<<64-2, "18446744073709551614" }, + uitoa64Test{ 1<<64-1, "18446744073709551615" }, +} diff --git a/src/pkg/strconv/quote.go b/src/pkg/strconv/quote.go new file mode 100644 index 000000000..8d7900d1d --- /dev/null +++ b/src/pkg/strconv/quote.go @@ -0,0 +1,229 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strconv + +import ( + "os"; + "utf8"; +) + +const lowerhex = "0123456789abcdef" + +// Quote returns a double-quoted Go string literal +// representing s. The returned string s uses Go escape +// sequences (\t, \n, \xFF, \u0100) for control characters +// and non-ASCII characters. +func Quote(s string) string { + // TODO(rsc): String accumulation could be more efficient. + t := `"`; + for ; len(s) > 0; s = s[1:len(s)] { + switch c := s[0]; { + case c == '"': + t += `\"`; + case c == '\\': + t += `\\`; + case ' ' <= c && c <= '~': + t += string(c); + case c == '\a': + t += `\a`; + case c == '\b': + t += `\b`; + case c == '\f': + t += `\f`; + case c == '\n': + t += `\n`; + case c == '\r': + t += `\r`; + case c == '\t': + t += `\t`; + case c == '\v': + t += `\v`; + + case c < utf8.RuneSelf: + t += `\x` + string(lowerhex[c>>4]) + string(lowerhex[c&0xF]); + + case utf8.FullRuneInString(s): + r, size := utf8.DecodeRuneInString(s); + if r == utf8.RuneError && size == 1 { + goto EscX; + } + s = s[size-1:len(s)]; // next iteration will slice off 1 more + if r < 0x10000 { + t += `\u`; + for j:=uint(0); j<4; j++ { + t += string(lowerhex[(r>>(12-4*j))&0xF]); + } + } else { + t += `\U`; + for j:=uint(0); j<8; j++ { + t += string(lowerhex[(r>>(28-4*j))&0xF]); + } + } + + default: + EscX: + t += `\x`; + t += string(lowerhex[c>>4]); + t += string(lowerhex[c&0xF]); + } + } + t += `"`; + return t; +} + +// 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; +} + +func unquoteChar(s string, q byte) (t, ns string, err os.Error) { + err = os.EINVAL; // assume error for easy return + + // easy cases + switch c := s[0]; { + case c >= utf8.RuneSelf: + r, size := utf8.DecodeRuneInString(s); + return s[0:size], s[size:len(s)], nil; + case c == q: + return; + case c != '\\': + return s[0:1], s[1:len(s)], nil; + } + + // hard case: c is backslash + if len(s) <= 1 { + return; + } + c := s[1]; + s = s[2:len(s)]; + + switch c { + case 'a': + return "\a", s, nil; + case 'b': + return "\b", s, nil; + case 'f': + return "\f", s, nil; + case 'n': + return "\n", s, nil; + case 'r': + return "\r", s, nil; + case 't': + return "\t", s, nil; + case 'v': + return "\v", s, nil; + 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 { + return; + } + for j := 0; j < n; j++ { + x, ok := unhex(s[j]); + if !ok { + return; + } + v = v<<4 | x; + } + s = s[n:len(s)]; + if c == 'x' { + // single-byte string, possibly not UTF-8 + return string([]byte{byte(v)}), s, nil; + } + if v > utf8.RuneMax { + return; + } + return string(v), s, nil; + case '0', '1', '2', '3', '4', '5', '6', '7': + v := int(c) - '0'; + if len(s) < 2 { + 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:len(s)]; + if v > 255 { + return; + } + return string(v), s, nil; + + case '\\', q: + return string(c), s, nil; + } + 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) { + err = os.EINVAL; // assume error for easy return + n := len(s); + if n < 2 { + return; + } + quote := s[0]; + if quote != s[n-1] { + return; + } + s = s[1:n-1]; + + if quote == '`' { + return s, nil; + } + if quote != '"' && quote != '\'' { + return; + } + + // TODO(rsc): String accumulation could be more efficient. + var c, tt string; + var err1 os.Error; + for len(s) > 0 { + if c, s, err1 = unquoteChar(s, quote); err1 != nil { + err = err1; + return; + } + tt += c; + if quote == '\'' && len(s) != 0 { + // single-quoted must be single character + return; + } + } + return tt, nil +} diff --git a/src/pkg/strconv/quote_test.go b/src/pkg/strconv/quote_test.go new file mode 100644 index 000000000..0fc01ebae --- /dev/null +++ b/src/pkg/strconv/quote_test.go @@ -0,0 +1,170 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strconv + +import ( + "os"; + "strconv"; + "testing"; +) + +type quoteTest struct { + in string; + out string; +} + +var quotetests = []quoteTest { + quoteTest{ "\a\b\f\r\n\t\v", `"\a\b\f\r\n\t\v"` }, + quoteTest{ "\\", `"\\"` }, + quoteTest{ "abc\xffdef", `"abc\xffdef"` }, + quoteTest{ "\u263a", `"\u263a"` }, + quoteTest{ "\U0010ffff", `"\U0010ffff"` }, + quoteTest{ "\x04", `"\x04"` }, +} + +func TestQuote(t *testing.T) { + for i := 0; i < len(quotetests); i++ { + tt := quotetests[i]; + if out := Quote(tt.in); out != tt.out { + t.Errorf("Quote(%s) = %s, want %s", tt.in, out, tt.out); + } + } +} + +type canBackquoteTest struct { + in string; + out bool; +} + +var canbackquotetests = []canBackquoteTest { + canBackquoteTest{ "`", false }, + canBackquoteTest{ string(0), false }, + canBackquoteTest{ string(1), false }, + canBackquoteTest{ string(2), false }, + canBackquoteTest{ string(3), false }, + canBackquoteTest{ string(4), false }, + canBackquoteTest{ string(5), false }, + canBackquoteTest{ string(6), false }, + canBackquoteTest{ string(7), false }, + canBackquoteTest{ string(8), false }, + canBackquoteTest{ string(9), true }, // \t + canBackquoteTest{ string(10), false }, + canBackquoteTest{ string(11), false }, + canBackquoteTest{ string(12), false }, + canBackquoteTest{ string(13), false }, + canBackquoteTest{ string(14), false }, + canBackquoteTest{ string(15), false }, + canBackquoteTest{ string(16), false }, + canBackquoteTest{ string(17), false }, + canBackquoteTest{ string(18), false }, + canBackquoteTest{ string(19), false }, + canBackquoteTest{ string(20), false }, + canBackquoteTest{ string(21), false }, + canBackquoteTest{ string(22), false }, + canBackquoteTest{ string(23), false }, + canBackquoteTest{ string(24), false }, + canBackquoteTest{ string(25), false }, + canBackquoteTest{ string(26), false }, + canBackquoteTest{ string(27), false }, + canBackquoteTest{ string(28), false }, + canBackquoteTest{ string(29), false }, + canBackquoteTest{ string(30), false }, + canBackquoteTest{ string(31), false }, + canBackquoteTest{ `' !"#$%&'()*+,-./:;<=>?@[\]^_{|}~`, true }, + canBackquoteTest{ `0123456789`, true }, + canBackquoteTest{ `ABCDEFGHIJKLMNOPQRSTUVWXYZ`, true }, + canBackquoteTest{ `abcdefghijklmnopqrstuvwxyz`, true }, + canBackquoteTest{ `☺`, true }, +} + +func TestCanBackquote(t *testing.T) { + for i := 0; i < len(canbackquotetests); i++ { + tt := canbackquotetests[i]; + if out := CanBackquote(tt.in); out != tt.out { + t.Errorf("CanBackquote(%q) = %v, want %v", tt.in, out, tt.out); + } + } +} + +var unquotetests = []quoteTest { + quoteTest{ `""`, "" }, + quoteTest{ `"a"`, "a" }, + quoteTest{ `"abc"`, "abc" }, + quoteTest{ `"☺"`, "☺" }, + quoteTest{ `"hello world"`, "hello world" }, + quoteTest{ `"\xFF"`, "\xFF" }, + quoteTest{ `"\377"`, "\377" }, + quoteTest{ `"\u1234"`, "\u1234" }, + quoteTest{ `"\U00010111"`, "\U00010111" }, + quoteTest{ `"\U0001011111"`, "\U0001011111" }, + quoteTest{ `"\a\b\f\n\r\t\v\\\""`, "\a\b\f\n\r\t\v\\\"" }, + quoteTest{ `"'"`, "'" }, + + quoteTest{ `'a'`, "a" }, + quoteTest{ `'☹'`, "☹" }, + quoteTest{ `'\a'`, "\a" }, + quoteTest{ `'\x10'`, "\x10" }, + quoteTest{ `'\377'`, "\377" }, + quoteTest{ `'\u1234'`, "\u1234" }, + quoteTest{ `'\U00010111'`, "\U00010111" }, + quoteTest{ `'\t'`, "\t" }, + quoteTest{ `' '`, " " }, + quoteTest{ `'\''`, "'" }, + quoteTest{ `'"'`, "\"" }, + + quoteTest{ "``", `` }, + quoteTest{ "`a`", `a` }, + quoteTest{ "`abc`", `abc` }, + quoteTest{ "`☺`", `☺` }, + quoteTest{ "`hello world`", `hello world` }, + quoteTest{ "`\\xFF`", `\xFF` }, + quoteTest{ "`\\377`", `\377` }, + quoteTest{ "`\\`", `\` }, + quoteTest{ "` `", ` ` }, + quoteTest{ "` `", ` ` }, +} + +var misquoted = []string { + ``, + `"`, + `"a`, + `"'`, + `b"`, + `"\"`, + `'\'`, + `'ab'`, + `"\x1!"`, + `"\U12345678"`, + `"\z"`, + "`", + "`xxx", + "`\"", + `"\'"`, + `'\"'`, +} + +func TestUnquote(t *testing.T) { + for i := 0; i < len(unquotetests); i++ { + tt := unquotetests[i]; + if out, err := Unquote(tt.in); err != nil && out != tt.out { + t.Errorf("Unquote(%s) = %q, %s want %q, nil", tt.in, out, err, tt.out); + } + } + + // run the quote tests too, backward + for i := 0; i < len(quotetests); i++ { + tt := quotetests[i]; + if in, err := Unquote(tt.out); in != tt.in { + t.Errorf("Unquote(%s) = %q, %s, want %q, nil", tt.out, in, err, tt.in); + } + } + + for i := 0; i < len(misquoted); i++ { + s := misquoted[i]; + if out, err := Unquote(s); out != "" || err != os.EINVAL { + t.Errorf("Unquote(%q) = %q, %s want %q, %s", 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..b6660cfc7 --- /dev/null +++ b/src/pkg/strings/Makefile @@ -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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D= + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + strings.$O\ + + +phases: a1 +_obj$D/strings.a: phases + +a1: $(O1) + $(AR) grc _obj$D/strings.a strings.$O + rm -f $(O1) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/strings.a + +$(O1): newpkg +$(O2): a1 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/strings.a + +packages: _obj$D/strings.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/strings.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/strings.a diff --git a/src/pkg/strings/strings.go b/src/pkg/strings/strings.go new file mode 100644 index 000000000..2e3dc0215 --- /dev/null +++ b/src/pkg/strings/strings.go @@ -0,0 +1,178 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// A package of simple functions to manipulate strings. +package strings + +import "utf8" + +// Explode splits s into an array of UTF-8 sequences, one per Unicode character (still strings). +// Invalid UTF-8 sequences become correct encodings of U+FFF8. +func Explode(s string) []string { + a := make([]string, utf8.RuneCountInString(s)); + var size, rune int; + i := 0; + for len(s) > 0 { + rune, size = utf8.DecodeRuneInString(s); + s = s[size:len(s)]; + a[i] = string(rune); + i++; + } + 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]; + n := 0; + for i := 0; i+len(sep) <= len(s); i++ { + if s[i] == c && (len(sep) == 1 || 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 string) 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 || s[i:i+n] == sep) { + return i + } + } + return -1 +} + +// Split returns the array representing the substrings of s separated by string sep. Adjacent +// occurrences of sep produce empty substrings. If sep is empty, it is the same as Explode. +func Split(s, sep string) []string { + if sep == "" { + return Explode(s) + } + c := sep[0]; + start := 0; + n := Count(s, sep)+1; + a := make([]string, n); + na := 0; + for i := 0; i+len(sep) <= len(s); i++ { + if s[i] == c && (len(sep) == 1 || s[i:i+len(sep)] == sep) { + a[na] = s[start:i]; + na++; + start = i+len(sep); + i += len(sep)-1 + } + } + a[na] = s[start:len(s)]; + return a +} + +// Join concatenates the elements of a to create a single string. The separator string +// sep is placed between elements in the resulting string. +func Join(a []string, sep string) string { + if len(a) == 0 { + return "" + } + if len(a) == 1 { + return a[0] + } + n := len(sep) * (len(a)-1); + for i := 0; i < len(a); i++ { + n += len(a[i]) + } + + b := make([]byte, n); + bp := 0; + for i := 0; i < len(a); i++ { + s := a[i]; + for j := 0; j < len(s); j++ { + b[bp] = s[j]; + bp++ + } + if i + 1 < len(a) { + s = sep; + for j := 0; j < len(s); j++ { + b[bp] = s[j]; + bp++ + } + } + } + return string(b) +} + +// HasPrefix tests whether the string s begins with prefix. +func HasPrefix(s, prefix string) bool { + return len(s) >= len(prefix) && s[0:len(prefix)] == prefix +} + +// HasSuffix tests whether the string s ends with suffix. +func HasSuffix(s, suffix string) bool { + return len(s) >= len(suffix) && s[len(s)-len(suffix):len(s)] == suffix +} + +// Upper returns a copy of the string s, with all low ASCII lowercase letters +// converted to uppercase. +// TODO: full Unicode support +func UpperASCII(s string) string { + // Note, we can work byte-by-byte because UTF-8 multibyte characters + // don't use any low ASCII byte values. + b := make([]byte, len(s)); + for i := 0; i < len(s); i++ { + c := s[i]; + if 'a' <= c && c <= 'z' { + c -= 'a' - 'A'; + } + b[i] = c; + } + return string(b); +} + +// Upper returns a copy of the string s, with all low ASCII lowercase letters +// converted to lowercase. +// TODO: full Unicode support +func LowerASCII(s string) string { + // Note, we can work byte-by-byte because UTF-8 multibyte characters + // don't use any low ASCII byte values. + b := make([]byte, len(s)); + for i := 0; i < len(s); i++ { + c := s[i]; + if 'A' <= c && c <= 'Z' { + c += 'a' - 'A'; + } + b[i] = c; + } + return string(b); +} + +func isWhitespaceASCII(c byte) bool { + switch int(c) { + case ' ', '\t', '\r', '\n': + return true; + } + return false; +} + +// Trim returns a slice of the string s, with all leading and trailing whitespace +// removed. "Whitespace" for now defined as space, tab, CR, or LF. +// TODO: full Unicode whitespace support (need a unicode.IsWhitespace method) +func TrimSpaceASCII(s string) string { + // Note, we can work byte-by-byte because UTF-8 multibyte characters + // don't use any low ASCII byte values. + start, end := 0, len(s); + for start < end && isWhitespaceASCII(s[start]) { + start++; + } + for start < end && isWhitespaceASCII(s[end-1]) { + end--; + } + return s[start:end]; +} diff --git a/src/pkg/strings/strings_test.go b/src/pkg/strings/strings_test.go new file mode 100644 index 000000000..05e662032 --- /dev/null +++ b/src/pkg/strings/strings_test.go @@ -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. + +package strings + +import ( + "strings"; + "testing"; +) + +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 ExplodeTest struct { + s string; + a []string; +} +var explodetests = []ExplodeTest { + ExplodeTest{ abcd, []string{"a", "b", "c", "d"} }, + ExplodeTest{ faces, []string{"☺", "☻", "☹" } }, +} +func TestExplode(t *testing.T) { + for i := 0; i < len(explodetests); i++ { + tt := explodetests[i]; + a := Explode(tt.s); + if !eq(a, tt.a) { + t.Errorf("Explode(%q) = %v; want %v", tt.s, a, tt.a); + continue; + } + s := Join(a, ""); + if s != tt.s { + t.Errorf(`Join(Explode(%q), "") = %q`, tt.s, s); + } + } +} + +type SplitTest struct { + s string; + sep string; + a []string; +} +var splittests = []SplitTest { + SplitTest{ abcd, "a", []string{"", "bcd"} }, + SplitTest{ abcd, "z", []string{"abcd"} }, + SplitTest{ abcd, "", []string{"a", "b", "c", "d"} }, + SplitTest{ commas, ",", []string{"1", "2", "3", "4"} }, + SplitTest{ dots, "...", []string{"1", ".2", ".3", ".4"} }, + SplitTest{ faces, "☹", []string{"☺☻", ""} }, + SplitTest{ faces, "~", []string{faces} }, + SplitTest{ faces, "", []string{"☺", "☻", "☹"} }, +} +func TestSplit(t *testing.T) { + for i := 0; i < len(splittests); i++ { + tt := splittests[i]; + a := Split(tt.s, tt.sep); + if !eq(a, tt.a) { + t.Errorf("Split(%q, %q) = %v; want %v", tt.s, tt.sep, a, tt.a); + continue; + } + s := Join(a, tt.sep); + if s != tt.s { + t.Errorf("Join(Split(%q, %q), %q) = %q", tt.s, tt.sep, tt.sep, s); + } + } +} + +// 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 i, 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 upperASCIITests = []StringTest { + StringTest{"", ""}, + StringTest{"abc", "ABC"}, + StringTest{"AbC123", "ABC123"}, + StringTest{"azAZ09_", "AZAZ09_"} +} + +var lowerASCIITests = []StringTest { + StringTest{"", ""}, + StringTest{"abc", "abc"}, + StringTest{"AbC123", "abc123"}, + StringTest{"azAZ09_", "azaz09_"} +} + +var trimSpaceASCIITests = []StringTest { + StringTest{"", ""}, + StringTest{"abc", "abc"}, + StringTest{" ", ""}, + StringTest{" \t\r\n \t\t\r\r\n\n ", ""}, + StringTest{" \t\r\n x\t\t\r\r\n\n ", "x"}, + StringTest{" \t\r\n x\t\t\r\r\ny\n ", "x\t\t\r\r\ny"}, + StringTest{"1 \t\r\n2", "1 \t\r\n2"}, +} + +func TestUpperASCII(t *testing.T) { + runStringTests(t, UpperASCII, "UpperASCII", upperASCIITests); +} + +func TestLowerASCII(t *testing.T) { + runStringTests(t, LowerASCII, "LowerASCII", lowerASCIITests); +} + +func TestTrimSpaceASCII(t *testing.T) { + runStringTests(t, TrimSpaceASCII, "TrimSpaceASCII", trimSpaceASCIITests); +} + diff --git a/src/pkg/sync/Makefile b/src/pkg/sync/Makefile new file mode 100644 index 000000000..566853d57 --- /dev/null +++ b/src/pkg/sync/Makefile @@ -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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m asm_${GOARCH}.s mutex.go >Makefile + +D= + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + asm_$(GOARCH).$O\ + mutex.$O\ + + +phases: a1 +_obj$D/sync.a: phases + +a1: $(O1) + $(AR) grc _obj$D/sync.a asm_$(GOARCH).$O mutex.$O + rm -f $(O1) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/sync.a + +$(O1): newpkg +$(O2): a1 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/sync.a + +packages: _obj$D/sync.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/sync.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/sync.a diff --git a/src/pkg/sync/asm_386.s b/src/pkg/sync/asm_386.s new file mode 100644 index 000000000..f71182b75 --- /dev/null +++ b/src/pkg/sync/asm_386.s @@ -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. + +// func cas(val *int32, old, new int32) bool +// Atomically: +// if *val == old { +// *val = new; +// return true; +// }else +// return false; +TEXT sync·cas(SB), 7, $0 + MOVL 4(SP), BX + MOVL 8(SP), AX + MOVL 12(SP), CX + LOCK + CMPXCHGL CX, 0(BX) + JZ ok + MOVL $0, 16(SP) + RET +ok: + MOVL $1, 16(SP) + RET diff --git a/src/pkg/sync/asm_amd64.s b/src/pkg/sync/asm_amd64.s new file mode 100644 index 000000000..07389dd3b --- /dev/null +++ b/src/pkg/sync/asm_amd64.s @@ -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. + +// func cas(val *int32, old, new int32) bool +// Atomically: +// if *val == old { +// *val = new; +// return true; +// }else +// return false; +TEXT sync·cas(SB), 7, $0 + MOVQ 8(SP), BX + MOVL 16(SP), AX + MOVL 20(SP), CX + LOCK + CMPXCHGL CX, 0(BX) + JZ ok + MOVL $0, 24(SP) + RET +ok: + MOVL $1, 24(SP) + RET diff --git a/src/pkg/sync/mutex.go b/src/pkg/sync/mutex.go new file mode 100644 index 000000000..5a6311a83 --- /dev/null +++ b/src/pkg/sync/mutex.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. + +// The sync package provides basic synchronization primitives +// such as mutual exclusion locks. These are intended for use +// by low-level library routines. Higher-level synchronization +// is better done via channels and communication. +package sync + +func cas(val *int32, old, new int32) bool +func semacquire(*int32) +func semrelease(*int32) + +// A Mutex is a mutual exclusion lock. +// Mutexes can be created as part of other structures; +// the zero value for a Mutex is an unlocked mutex. +type Mutex struct { + key int32; + sema int32; +} + +func xadd(val *int32, delta int32) (new int32) { + for { + v := *val; + if cas(val, v, v+delta) { + return v+delta; + } + } + panic("unreached") +} + +// Lock locks m. +// If the lock is already in use, the calling goroutine +// blocks until the mutex is available. +func (m *Mutex) Lock() { + if xadd(&m.key, 1) == 1 { + // changed from 0 to 1; we hold lock + return; + } + semacquire(&m.sema); +} + +// Unlock unlocks m. +// It is a run-time error if m is not locked on entry to Unlock. +// +// A locked Mutex is not associated with a particular goroutine. +// It is allowed for one goroutine to lock a Mutex and then +// arrange for another goroutine to unlock it. +func (m *Mutex) Unlock() { + if xadd(&m.key, -1) == 0 { + // changed from 1 to 0; no contention + return; + } + semrelease(&m.sema); +} + +// Stub implementation of r/w locks. +// This satisfies the semantics but +// is not terribly efficient. + +// The next comment goes in the BUGS section of the document, +// in its own paragraph, without the (rsc) tag. + +// BUG(rsc): RWMutex does not (yet) allow multiple readers; +// instead it behaves as if RLock and RUnlock were Lock and Unlock. + +// 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 { + m Mutex; +} + +// RLock locks rw for reading. +// If the lock is already locked for writing or there is a writer already waiting +// to acquire the lock, RLock blocks until the writer has released the lock. +func (rw *RWMutex) RLock() { + rw.m.Lock(); +} + +// 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() { + rw.m.Unlock(); +} + +// Lock locks rw for writing. +// If the lock is already locked for reading or writing, +// Lock blocks until the lock is available. +// To ensure that the lock eventually becomes available, +// a blocked Lock call excludes new readers from acquiring +// the lock. +func (rw *RWMutex) Lock() { + rw.m.Lock(); +} + +// Unlock unlocks rw for writing. +// It is a run-time error if rw is not locked for writing +// on entry to Unlock. +// +// Like for Mutexes, +// a locked RWMutex is not associated with a particular goroutine. +// It is allowed for one goroutine to RLock (Lock) an RWMutex and then +// arrange for another goroutine to RUnlock (Unlock) it. +func (rw *RWMutex) Unlock() { + rw.m.Unlock(); +} + diff --git a/src/pkg/sync/mutex_test.go b/src/pkg/sync/mutex_test.go new file mode 100644 index 000000000..819dbb9de --- /dev/null +++ b/src/pkg/sync/mutex_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. + +// GOMAXPROCS=10 gotest + +package sync + +import ( + "sync"; + "testing" +) + +func HammerSemaphore(s *int32, cdone chan bool) { + for i := 0; i < 1000; i++ { + semacquire(s); + semrelease(s); + } + cdone <- true; +} + +func TestSemaphore(t *testing.T) { + s := new(int32); + *s = 1; + c := make(chan bool); + for i := 0; i < 10; i++ { + go HammerSemaphore(s, c); + } + for i := 0; i < 10; i++ { + <-c; + } +} + + +func HammerMutex(m *Mutex, cdone chan bool) { + for i := 0; i < 1000; 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, c); + } + for i := 0; i < 10; i++ { + <-c; + } +} + diff --git a/src/pkg/syscall/Makefile b/src/pkg/syscall/Makefile new file mode 100644 index 000000000..a5cc042d7 --- /dev/null +++ b/src/pkg/syscall/Makefile @@ -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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m asm_${GOOS}_${GOARCH}.s errstr.go exec.go syscall.go syscall_${GOOS}.go syscall_${GOOS}_${GOARCH}.go zerrors_${GOOS}_${GOARCH}.go zsyscall_${GOOS}_${GOARCH}.go zsysnum_${GOOS}_${GOARCH}.go ztypes_${GOOS}_${GOARCH}.go >Makefile + +D= + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + asm_$(GOOS)_$(GOARCH).$O\ + syscall.$O\ + zerrors_$(GOOS)_$(GOARCH).$O\ + zsysnum_$(GOOS)_$(GOARCH).$O\ + ztypes_$(GOOS)_$(GOARCH).$O\ + +O2=\ + errstr.$O\ + zsyscall_$(GOOS)_$(GOARCH).$O\ + +O3=\ + syscall_$(GOOS)_$(GOARCH).$O\ + +O4=\ + syscall_$(GOOS).$O\ + +O5=\ + exec.$O\ + + +phases: a1 a2 a3 a4 a5 +_obj$D/syscall.a: phases + +a1: $(O1) + $(AR) grc _obj$D/syscall.a asm_$(GOOS)_$(GOARCH).$O syscall.$O zerrors_$(GOOS)_$(GOARCH).$O zsysnum_$(GOOS)_$(GOARCH).$O ztypes_$(GOOS)_$(GOARCH).$O + rm -f $(O1) + +a2: $(O2) + $(AR) grc _obj$D/syscall.a errstr.$O zsyscall_$(GOOS)_$(GOARCH).$O + rm -f $(O2) + +a3: $(O3) + $(AR) grc _obj$D/syscall.a syscall_$(GOOS)_$(GOARCH).$O + rm -f $(O3) + +a4: $(O4) + $(AR) grc _obj$D/syscall.a syscall_$(GOOS).$O + rm -f $(O4) + +a5: $(O5) + $(AR) grc _obj$D/syscall.a exec.$O + rm -f $(O5) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/syscall.a + +$(O1): newpkg +$(O2): a1 +$(O3): a2 +$(O4): a3 +$(O5): a4 +$(O6): a5 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/syscall.a + +packages: _obj$D/syscall.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/syscall.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/syscall.a diff --git a/src/pkg/syscall/PORT b/src/pkg/syscall/PORT new file mode 100755 index 000000000..f3addcdb0 --- /dev/null +++ b/src/pkg/syscall/PORT @@ -0,0 +1,124 @@ +#!/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. + +# 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 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. +# +# * types_${GOOS}_${GOARCH}.c +# +# Same as types_${GOOS}_${GOARCH}.go except that it contains +# definitions specific to ${GOOS} one one particular architecture. +# +# * zerror_${GOOS}_${GOARCH}.go +# +# This machine-generated file defines the system's error numbers, +# error strings, and signal numbers. The generator is "mkerrors". +# Usually no arguments are needed, but mkerrors will pass its +# arguments on to godefs. +# +# * zsyscall_${GOOS}_${GOARCH}.go +# +# Generated by mksyscall; 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" +mkerrors="mkerrors" + +case "$GOOSARCH" in +_* | *_ | _) + echo 'undefined $GOOS_$GOARCH:' "$GOOSARCH" 1>&2 + exit 1 + ;; +darwin_386) + mksyscall="mksyscall -l32" + mksysnum="mksysnum_darwin /home/rsc/pub/xnu-1228/bsd/kern/syscalls.master" + mktypes="godefs -gsyscall -f-m32" + ;; +darwin_amd64) + mksysnum="mksysnum_darwin /home/rsc/pub/xnu-1228/bsd/kern/syscalls.master" + mktypes="godefs -gsyscall -f-m64" + mkerrors="mkerrors" + ;; +linux_386) + mksysnum="mksysnum_linux /usr/include/asm/unistd_32.h" + mktypes="godefs -gsyscall -f-m32" + ;; +linux_amd64) + mksysnum="mksysnum_linux /usr/include/asm/unistd_64.h" + mktypes="godefs -gsyscall -f-m64" + ;; +*) + echo 'unrecognized $GOOS_$GOARCH: ' "$GOOSARCH" 1>&2 + exit 1 + ;; +esac + +echo "$mkerrors >zerrors_$GOOSARCH.go" +echo "$mksyscall syscall_$GOOS.go syscall_$GOOSARCH.go >zsyscall_$GOOSARCH.go" +echo "$mksysnum >zsysnum_$GOOSARCH.go" +echo "$mktypes types_$GOOS.c types_$GOOSARCH.c >ztypes_$GOOSARCH.go" + +port=$(ls *.go | grep -v _) +arch=$(ls *_$GOOSARCH.s *_$GOOSARCH.go *_$GOOS.go) +all=$(ls $port $arch) # sort them +echo gobuild $all diff --git a/src/pkg/syscall/asm_darwin_386.s b/src/pkg/syscall/asm_darwin_386.s new file mode 100644 index 000000000..a8ec5b00c --- /dev/null +++ b/src/pkg/syscall/asm_darwin_386.s @@ -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. + +// +// 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·Syscall(SB),7,$0 + CALL sys·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 sys·exitsyscall(SB) + RET +ok: + MOVL AX, 20(SP) // r1 + MOVL DX, 24(SP) // r2 ??? + MOVL $0, 28(SP) // errno + CALL sys·exitsyscall(SB) + RET + +TEXT syscall·Syscall6(SB),7,$0 + CALL sys·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 sys·exitsyscall(SB) + RET +ok6: + MOVL AX, 32(SP) // r1 + MOVL DX, 36(SP) // r2 ??? + MOVL $0, 40(SP) // errno + CALL sys·exitsyscall(SB) + RET + +TEXT syscall·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 diff --git a/src/pkg/syscall/asm_darwin_amd64.s b/src/pkg/syscall/asm_darwin_amd64.s new file mode 100644 index 000000000..e1527977f --- /dev/null +++ b/src/pkg/syscall/asm_darwin_amd64.s @@ -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. + +// +// 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·Syscall(SB),7,$0 + CALL sys·entersyscall(SB) + MOVQ 16(SP), DI + MOVQ 24(SP), SI + MOVQ 32(SP), DX + 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 sys·exitsyscall(SB) + RET +ok: + MOVQ AX, 40(SP) // r1 + MOVQ DX, 48(SP) // r2 + MOVQ $0, 56(SP) // errno + CALL sys·exitsyscall(SB) + RET + +TEXT syscall·Syscall6(SB),7,$0 + CALL sys·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 sys·exitsyscall(SB) + RET +ok6: + MOVQ AX, 64(SP) // r1 + MOVQ DX, 72(SP) // r2 + MOVQ $0, 80(SP) // errno + CALL sys·exitsyscall(SB) + RET + +TEXT syscall·RawSyscall(SB),7,$0 + MOVQ 16(SP), DI + MOVQ 24(SP), SI + MOVQ 32(SP), DX + 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 diff --git a/src/pkg/syscall/asm_linux_386.s b/src/pkg/syscall/asm_linux_386.s new file mode 100644 index 000000000..c6b01792d --- /dev/null +++ b/src/pkg/syscall/asm_linux_386.s @@ -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. + +// +// System calls for 386, Linux +// + +// func Syscall(trap int64, a1, a2, a3 int64) (r1, r2, err int64); +// Trap # in AX, args in BX CX DX SI DI, return in AX + +TEXT syscall·Syscall(SB),7,$0 + CALL sys·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 sys·exitsyscall(SB) + RET +ok: + MOVL AX, 20(SP) // r1 + MOVL DX, 24(SP) // r2 + MOVL $0, 28(SP) // errno + CALL sys·exitsyscall(SB) + RET + +// Actually Syscall5 but the rest of the code expects it to be named Syscall6. +TEXT syscall·Syscall6(SB),7,$0 + CALL sys·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 + // 28(SP) is ignored + 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 sys·exitsyscall(SB) + RET +ok6: + MOVL AX, 32(SP) // r1 + MOVL DX, 36(SP) // r2 + MOVL $0, 40(SP) // errno + CALL sys·exitsyscall(SB) + RET + +TEXT syscall·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 + CALL sys·exitsyscall(SB) + RET +ok1: + MOVL AX, 20(SP) // r1 + MOVL DX, 24(SP) // r2 + MOVL $0, 28(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 syscall·socketcall(SB),7,$0 + CALL sys·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, 28(SP) // n + NEGL AX + MOVL AX, 32(SP) // errno + CALL sys·exitsyscall(SB) + RET +oksock: + MOVL AX, 28(SP) // n + MOVL $0, 32(SP) // errno + CALL sys·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..cb93b481a --- /dev/null +++ b/src/pkg/syscall/asm_linux_amd64.s @@ -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. + +// +// 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·Syscall(SB),7,$0 + CALL sys·entersyscall(SB) + MOVQ 16(SP), DI + MOVQ 24(SP), SI + MOVQ 32(SP), DX + 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 sys·exitsyscall(SB) + RET +ok: + MOVQ AX, 40(SP) // r1 + MOVQ DX, 48(SP) // r2 + MOVQ $0, 56(SP) // errno + CALL sys·exitsyscall(SB) + RET + +TEXT syscall·Syscall6(SB),7,$0 + CALL sys·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 sys·exitsyscall(SB) + RET +ok6: + MOVQ AX, 64(SP) // r1 + MOVQ DX, 72(SP) // r2 + MOVQ $0, 80(SP) // errno + CALL sys·exitsyscall(SB) + RET + +TEXT syscall·RawSyscall(SB),7,$0 + MOVQ 16(SP), DI + MOVQ 24(SP), SI + MOVQ 32(SP), DX + 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 diff --git a/src/pkg/syscall/errstr.go b/src/pkg/syscall/errstr.go new file mode 100644 index 000000000..67a529d34 --- /dev/null +++ b/src/pkg/syscall/errstr.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 + +import "syscall" + +func str(val int) string { // do it here rather than with fmt to avoid dependency + if val < 0 { + return "-" + str(-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:len(buf)]); +} + +func Errstr(errno int) string { + if errno < 0 || errno >= int(len(errors)) { + return "error " + str(errno) + } + return errors[errno] +} + diff --git a/src/pkg/syscall/exec.go b/src/pkg/syscall/exec.go new file mode 100644 index 000000000..58fb05863 --- /dev/null +++ b/src/pkg/syscall/exec.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. + +// Fork, exec, wait, etc. + +package syscall + +import ( + "sync"; + "syscall"; + "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 StringArrayPtr(ss []string) []*byte { + bb := make([]*byte, len(ss)+1); + for i := 0; i < len(ss); i++ { + bb[i] = StringBytePtr(ss[i]); + } + bb[len(ss)] = nil; + return bb; +} + +func CloseOnExec(fd int) { + fcntl(fd, F_SETFD, FD_CLOEXEC); +} + +func SetNonblock(fd int, nonblocking bool) (errno int) { + flag, err := fcntl(fd, F_GETFL, 0); + if err != 0 { + return err; + } + if nonblocking { + flag |= O_NONBLOCK; + } else { + flag &= ^O_NONBLOCK; + } + flag, err = fcntl(fd, F_SETFL, flag); + return err; +} + + +// 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 []*byte, envv []*byte, dir *byte, fd []int, pipe int) + (pid int, err int) +{ + // Declare all variables at top in case any + // declarations require heap allocation (e.g., err1). + var r1, r2, err1 uintptr; + var nextfd int; + var i int; + + darwin := OS == "darwin"; + + // About to call fork. + // No more allocation or calls of non-assembly functions. + 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. + + // Chdir + if dir != nil { + r1, r2, 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 { + r1, r2, 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) { + r1, r2, 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. + r1, r2, 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. + r1, r2, 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); + } + + // Time to exec. + r1, r2, 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)), uintptr(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"); +} + +// Combination of fork and exec, careful to be thread safe. +func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []int) + (pid int, err int) +{ + var p [2]int; + var r1 int; + var n int; + var err1 uintptr; + var wstatus WaitStatus; + + p[0] = -1; + p[1] = -1; + + // Convert args to C form. + argv0p := StringBytePtr(argv0); + argvp := StringArrayPtr(argv); + envvp := StringArrayPtr(envv); + var dirp *byte; + if len(dir) > 0 { + dirp = StringBytePtr(dir); + } + + // Acquire the fork lock so that no other threads + // create new fds that are not yet close-on-exec + // before we fork. + ForkLock.Lock(); + + // Allocate child status pipe close on exec. + if err = Pipe(&p); err != 0 { + goto error; + } + var val int; + if val, err = fcntl(p[0], F_SETFD, FD_CLOEXEC); err != 0 { + goto error; + } + if val, err = fcntl(p[1], F_SETFD, FD_CLOEXEC); err != 0 { + goto error; + } + + // Kick off child. + pid, err = forkAndExecInChild(argv0p, argvp, envvp, dirp, fd, p[1]); + if err != 0 { + error: + if p[0] >= 0 { + Close(p[0]); + Close(p[1]); + } + ForkLock.Unlock(); + return 0, err + } + ForkLock.Unlock(); + + // Read child error status from pipe. + Close(p[1]); + n, err = read(p[0], (*byte)(unsafe.Pointer(&err1)), unsafe.Sizeof(err1)); + Close(p[0]); + if err != 0 || n != 0 { + if n == unsafe.Sizeof(err1) { + err = int(err1); + } + if err == 0 { + err = EPIPE; + } + + // Child failed; wait for it to exit, to make sure + // the zombies don't accumulate. + pid1, err1 := Wait4(pid, &wstatus, 0, nil); + for err1 == EINTR { + pid1, err1 = Wait4(pid, &wstatus, 0, nil); + } + return 0, err + } + + // Read got EOF, so pipe closed on exec, so exec succeeded. + return pid, 0 +} + +// Ordinary exec. +func Exec(argv0 string, argv []string, envv []string) (err int) { + r1, r2, err1 := RawSyscall(SYS_EXECVE, + uintptr(unsafe.Pointer(StringBytePtr(argv0))), + uintptr(unsafe.Pointer(&StringArrayPtr(argv)[0])), + uintptr(unsafe.Pointer(&StringArrayPtr(envv)[0]))); + return int(err1); +} + diff --git a/src/pkg/syscall/mkerrors b/src/pkg/syscall/mkerrors new file mode 100755 index 000000000..015f02145 --- /dev/null +++ b/src/pkg/syscall/mkerrors @@ -0,0 +1,94 @@ +#!/bin/sh +# Copyright 2009 The Go Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + + +# Generate Go code listing error values (ENAMETOOLONG etc) +# and signal values (SIGALRM etc). They're unrelated except +# that we use the same method for finding them. + +errors=$( + echo '#include ' | + # The gcc command line prints all the #defines + # it encounters while processing the input + gcc -x c - -E -dM | + egrep -h '#define E[A-Z0-9_]+ ' $files | + sed 's/#define //; s/ .*//' +) + +signals=$( + echo '#include ' | + gcc -x c - -E -dM | + egrep -h '#define SIG[^_]' | + egrep -v '#define (SIGEV_|SIGSTKSZ|SIGRT(MIN|MAX))' | + sed 's/#define //; s/ .*//' +) + +# Write godefs input. +( + echo '#include ' + echo '#include ' + echo 'enum {' + for i in $errors $signals + do + echo '$'"$i = $i," + done + echo '};' +) >_errors.c + +echo '// mkerrors' "$@" +echo '// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT' +echo +godefs -gsyscall "$@" _errors.c + +# Run C program to print error strings. +( + echo " +#include +#include +#include +#include + +#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 + echo ' '$i, + done + + echo ' +}; + +int +main(void) +{ + int i, j, e; + char buf[1024]; + + printf("\n\n// Error table\n"); + printf("var errors = [...]string {\n"); + for(i=0; i bad, but STREAM -> STREAM. + if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z) + buf[0] += a - A; + printf("\t%d: \"%s\",\n", e, buf); + next:; + } + printf("}\n\n"); +} + +' +) >_errors.c + +gcc -o _errors _errors.c && ./_errors +rm -f _errors.c _errors diff --git a/src/pkg/syscall/mksyscall b/src/pkg/syscall/mksyscall new file mode 100755 index 000000000..850fc1e3f --- /dev/null +++ b/src/pkg/syscall/mksyscall @@ -0,0 +1,170 @@ +#!/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. + +$cmdline = "mksyscall " . join(' ', @ARGV); +$errors = 0; +$_32bit = ""; + +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 [-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); +} + +$text = ""; +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*(?:=\s*(SYS_[A-Z0-9_]+))?$/) { + print STDERR "$ARGV:$.: malformed //sys declaration\n"; + $errors = 1; + next; + } + my ($func, $in, $out, $sysname) = ($1, $2, $3, $4); + + # Split argument lists on comma. + my @in = parseparamlist($in); + my @out = parseparamlist($out); + + # Go function header. + $text .= sprintf "func %s(%s) (%s) {\n", $func, join(', ', @in), join(', ', @out); + + # 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 nil in that case. + $text .= "\tvar _p$n *$1;\n"; + $text .= "\tif len($name) > 0 { _p$n = \&${name}[0]; }\n"; + push @args, "uintptr(unsafe.Pointer(_p$n))", "uintptr(len($name))"; + $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(@args <= 3) { + while(@args < 3) { + push @args, "0"; + } + } elsif(@args <= 6) { + $asm = "Syscall6"; + while(@args < 6) { + 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); + $text .= "\tr0, r1, e1 := $asm($sysname, $args);\n"; + + # Assign return values. + for(my $i=0; $i<@out; $i++) { + my $p = $out[$i]; + my ($name, $type) = parseparam($p); + my $reg = ""; + if($name eq "errno") { + $reg = "e1"; + } else { + $reg = sprintf("r%d", $i); + } + if($type eq "bool") { + $reg = "$reg != 0"; + } + $text .= "\t$name = $type($reg);\n"; + } + + $text .= "\treturn;\n"; + $text .= "}\n\n"; +} + +if($errors) { + exit 1; +} + +print <){ + if(/^([0-9]+)\s+ALL\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"; + } + + print " $name = $num; // $proto\n"; + } +} + +print <){ + if(/^#define __NR_(\w+)\s+([0-9]+)/){ + my $name = "SYS_$1"; + my $num = $2; + $name =~ y/a-z/A-Z/; + print " $name = $num;\n"; + } +} + +print < 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]); +} + +// 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; +} + +//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; +} + +//sys 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(rsc): How does 386 return an int64 newoffset? +//sys lseek(fd int, offset int64, whence int) (newoffset uintptr, errno int) +func Seek(fd int, offset int64, whence int) (newoffset int64, errno int) { + n, e := lseek(fd, offset, whence); + return int64(n), e; +} + +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) +//sys socket(domain int, typ int, proto int) (fd int, errno int) +//sys setsockopt(s int, level int, name int, val uintptr, vallen 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; + 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); + 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 anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, int) { + switch rsa.Addr.Family { + 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 := (*[len(pp.Path)]byte)(unsafe.Pointer(&pp.Path[0])); + sa.Name = string(bytes[0:n]); + return sa, 0; + + case AF_INET: + pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa)); + sa := new(SockaddrInet4); + p := (*[2]byte)(unsafe.Pointer(&pp.Port)); + sa.Port = int(p[0])<<8 + int(p[1]); + for i := 0; i < len(sa.Addr); i++ { + sa.Addr[i] = pp.Addr[i]; + } + return sa, 0; + + case AF_INET6: + pp := (*RawSockaddrInet6)(unsafe.Pointer(rsa)); + sa := new(SockaddrInet6); + p := (*[2]byte)(unsafe.Pointer(&pp.Port)); + sa.Port = int(p[0])<<8 + int(p[1]); + for i := 0; i < len(sa.Addr); i++ { + sa.Addr[i] = pp.Addr[i]; + } + return sa, 0; + } + return nil, EAFNOSUPPORT; +} + +func 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 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 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)); +} + +//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); +} + +// TODO: wrap +// Acct(name nil-string) (errno int) +// Futimes(fd int, timeval *Timeval) (errno int) // Pointer to 2 timevals! +// Gethostuuid(uuid *byte, timeout *Timespec) (errno int) +// Getpeername(fd int, addr *Sockaddr, addrlen *int) (errno int) +// Getsockname(fd int, addr *Sockaddr, addrlen *int) (errno int) +// Getsockopt(s int, level int, name int, val *byte, vallen *int) (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) +// Munmap(addr *byte, len int) (errno int) +// Ptrace(req int, pid int, addr uintptr, data int) (ret uintptr, errno int) +// Recvfrom(s int, buf *byte, nbuf int, flags int, from *Sockaddr, fromlen *int) (n int, errno int) +// Recvmsg(s int, msg *Msghdr, flags int) (n int, errno int) +// Sendmsg(s int, msg *Msghdr, flags int) (n int, errno int) +// Sendto(s int, buf *byte, nbuf int, flags int, to *Sockaddr, addrlen int) (errno int) +// Utimes(path string, timeval *Timeval) (errno int) // Pointer to 2 timevals! +//sys fcntl(fd int, cmd int, arg int) (val int, errno int) + + +/* + * Exposed directly + */ +//sys Access(path string, flags int) (errno int) +//sys Adjtime(delta *Timeval, olddelta *Timeval) (errno int) +//sys Chdir(path string) (errno int) +//sys Chflags(path string, flags int) (errno int) +//sys Chmod(path string, mode int) (errno int) +//sys Chown(path string, uid int, gid int) (errno int) +//sys Chroot(path string) (errno int) +//sys Close(fd int) (errno int) +//sys Dup(fd int) (nfd int, errno int) +//sys 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 int) (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) +//sys Getegid() (egid int) +//sys Geteuid() (uid int) +//sys Getfsstat(buf []Statfs_t, flags int) (n int, errno int) = SYS_GETFSSTAT64 +//sys Getgid() (gid int) +//sys Getpgid(pid int) (pgid int, errno int) +//sys Getpgrp() (pgrp int) +//sys Getpid() (pid int) +//sys Getppid() (ppid int) +//sys Getpriority(which int, who int) (prio int, errno int) +//sys Getrlimit(which int, lim *Rlimit) (errno int) +//sys Getrusage(who int, rusage *Rusage) (errno int) +//sys Getsid(pid int) (sid int, errno int) +//sys Getuid() (uid int) +//sys Issetugid() (tainted bool) +//sys Kill(pid int, signum int, posix 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_LSTAT64 +//sys Mkdir(path string, mode int) (errno int) +//sys Mkfifo(path string, mode int) (errno int) +//sys Mknod(path string, mode int, dev int) (errno int) +//sys Open(path string, mode int, perm int) (fd int, errno int) +//sys 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 Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (errno int) +//sys Setegid(egid int) (errno int) +//sys Seteuid(euid int) (errno int) +//sys Setgid(gid int) (errno int) +//sys Setlogin(name string) (errno int) +//sys Setpgid(pid int, pgid int) (errno int) +//sys Setpriority(which int, who int, prio int) (errno int) +//sys Setprivexec(flag int) (errno int) +//sys Setregid(rgid int, egid int) (errno int) +//sys Setreuid(ruid int, euid int) (errno int) +//sys Setrlimit(which int, lim *Rlimit) (errno int) +//sys Setsid() (pid int, errno int) +//sys Settimeofday(tp *Timeval) (errno int) +//sys 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) (errno 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 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 +// __Sysctl +// 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..5633d7c03 --- /dev/null +++ b/src/pkg/syscall/syscall_darwin_386.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 syscall + +import "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; +} + +//sys 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 = 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); +} diff --git a/src/pkg/syscall/syscall_darwin_amd64.go b/src/pkg/syscall/syscall_darwin_amd64.go new file mode 100644 index 000000000..f7a93f121 --- /dev/null +++ b/src/pkg/syscall/syscall_darwin_amd64.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 syscall + +import "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; +} + +//sys 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); +} diff --git a/src/pkg/syscall/syscall_linux.go b/src/pkg/syscall/syscall_linux.go new file mode 100644 index 000000000..50f3938d7 --- /dev/null +++ b/src/pkg/syscall/syscall_linux.go @@ -0,0 +1,636 @@ +// Copyright 2009 The Go 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 ( + "syscall"; + "unsafe"; +) + +const OS = "linux" + +/* + * Wrapped + */ + +//sys 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 string, times *[2]Timeval) (errno int) +func Futimesat(dirfd int, path string, tv []Timeval) (errno int) { + if len(tv) != 2 { + return EINVAL; + } + return futimesat(dirfd, path, (*[2]Timeval)(unsafe.Pointer(&tv[0]))); +} + +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); + 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 +} + +//sys getgroups(n int, list *_Gid_t) (nn int, errno int) +//sys setgroups(n int, list *_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 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; +} + +//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); + n, err := Select(0, nil, nil, nil, &tv); + return err; +} + +// Implemented in syscall_linux_*.go +func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, errno int) +func bind(s int, addr uintptr, addrlen _Socklen) (errno int) +func connect(s int, addr uintptr, addrlen _Socklen) (errno int) +func socket(domain int, typ int, proto int) (fd int, errno int) +func setsockopt(s int, level int, name int, val uintptr, vallen int) (errno int) +func Listen(s int, n 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.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; + 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); + 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]); + } + if sa.raw.Path[0] == '@' { + sa.raw.Path[0] = 0; + } + + // length is family, name, NUL. + return uintptr(unsafe.Pointer(&sa.raw)), 1 + _Socklen(n) + 1, 0; +} + +func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, int) { + switch rsa.Addr.Family { + 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 := (*[len(pp.Path)]byte)(unsafe.Pointer(&pp.Path[0])); + sa.Name = string(bytes[0:n]); + return sa, 0; + + case AF_INET: + pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa)); + sa := new(SockaddrInet4); + p := (*[2]byte)(unsafe.Pointer(&pp.Port)); + sa.Port = int(p[0])<<8 + int(p[1]); + for i := 0; i < len(sa.Addr); i++ { + sa.Addr[i] = pp.Addr[i]; + } + return sa, 0; + + case AF_INET6: + pp := (*RawSockaddrInet6)(unsafe.Pointer(rsa)); + sa := new(SockaddrInet6); + p := (*[2]byte)(unsafe.Pointer(&pp.Port)); + sa.Port = int(p[0])<<8 + int(p[1]); + for i := 0; i < len(sa.Addr); i++ { + sa.Addr[i] = pp.Addr[i]; + } + return sa, 0; + } + return nil, EAFNOSUPPORT; +} + +func 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 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 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)); +} + +// Sendto +// Recvfrom +// Sendmsg +// Recvmsg +// Getsockname +// Getpeername +// Socketpair +// Getsockopt + +/* + * Direct access + */ +//sys Access(path string, mode int) (errno int) +//sys Acct(path string) (errno int) +//sys Adjtimex(buf *Timex) (state int, errno int) +//sys Chdir(path string) (errno int) +//sys Chmod(path string, mode int) (errno int) +//sys Chown(path string, uid int, gid int) (errno int) +//sys Chroot(path string) (errno int) +//sys Close(fd int) (errno int) +//sys Creat(path string, mode int) (fd int, errno int) +//sys Dup(oldfd int) (fd int, errno int) +//sys Dup2(oldfd int, newfd int) (fd int, errno int) +//sys EpollCreate(size int) (fd int, errno int) +//sys EpollCtl(epfd int, op int, fd int, event *EpollEvent) (errno int) +//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, errno int) +//sys Exit(code int) = SYS_EXIT_GROUP +//sys Faccessat(dirfd int, path string, mode int, flags int) (errno int) +//sys Fallocate(fd int, mode int, off int64, len int64) (errno int) +//sys Fchdir(fd int) (errno int) +//sys Fchmod(fd int, mode int) (errno int) +//sys Fchmodat(dirfd int, path string, mode int, flags int) (errno int) +//sys Fchown(fd int, uid int, gid 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 Fstat(fd int, stat *Stat_t) (errno int) +//sys Fstatfs(fd int, buf *Statfs_t) (errno int) +//sys Fsync(fd int) (errno int) +//sys Ftruncate(fd int, length int64) (errno int) +//sys Getdents(fd int, buf []byte) (n int, errno int) = SYS_GETDENTS64 +//sys Getegid() (egid int) +//sys Geteuid() (euid int) +//sys Getgid() (gid int) +//sys Getpgid(pid int) (pgid int, errno int) +//sys Getpgrp() (pid int) +//sys Getpid() (pid int) +//sys Getppid() (ppid int) +//sys Getrlimit(resource int, rlim *Rlimit) (errno int) +//sys Getrusage(who int, rusage *Rusage) (errno int) +//sys Gettid() (tid int) +//sys Gettimeofday(tv *Timeval) (errno int) +//sys Getuid() (uid int) +//sys Ioperm(from int, num int, on int) (errno int) +//sys Iopl(level int) (errno int) +//sys Kill(pid int, sig int) (errno int) +//sys Klogctl(typ int, buf []byte) (n int, errno int) = SYS_SYSLOG +//sys Lchown(path string, uid int, gid int) (errno int) +//sys Link(oldpath string, newpath string) (errno int) +//sys Lstat(path string, stat *Stat_t) (errno int) +//sys Mkdir(path string, mode int) (errno int) +//sys Mkdirat(dirfd int, path string, mode int) (errno int) +//sys Mknod(path string, mode int, dev int) (errno int) +//sys Mknodat(dirfd int, path string, mode int, dev int) (errno int) +//sys Nanosleep(time *Timespec, leftover *Timespec) (errno int) +//sys Open(path string, mode int, perm int) (fd int, errno int) +//sys Openat(dirfd int, path string, flags int, mode int) (fd int, errno int) +//sys Pause() (errno int) +//sys PivotRoot(newroot string, putold string) (errno int) = SYS_PIVOT_ROOT +//sys Pread(fd int, p []byte, offset int64) (n int, errno int) = SYS_PREAD64 +//sys Pwrite(fd int, p []byte, offset int64) (n int, errno int) = SYS_PWRITE64 +//sys Read(fd int, p []byte) (n int, errno int) +//sys Readlink(path string, buf []byte) (n int, errno int) +//sys Rename(oldpath string, newpath string) (errno int) +//sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (errno int) +//sys Rmdir(path string) (errno int) +//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 Setdomainname(p []byte) (errno int) +//sys Setfsgid(gid int) (errno int) +//sys Setfsuid(uid int) (errno int) +//sys Setgid(gid int) (errno int) +//sys Sethostname(p []byte) (errno int) +//sys Setpgid(pid int, pgid int) (errno int) +//sys Setregid(rgid int, egid int) (errno int) +//sys Setresgid(rgid int, egid int, sgid int) (errno int) +//sys Setresuid(ruid int, euid int, suid int) (errno int) +//sys Setreuid(ruid int, euid int) (errno int) +//sys Setrlimit(resource int, rlim *Rlimit) (errno int) +//sys Setsid() (pid int) +//sys Settimeofday(tv *Timeval) (errno int) +//sys Setuid(uid int) (errno int) +//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, errno int) +//sys Stat(path string, stat *Stat_t) (errno int) +//sys Statfs(path string, buf *Statfs_t) (errno int) +//sys Symlink(oldpath string, newpath string) (errno int) +//sys Sync() +//sys SyncFileRange(fd int, off int64, n int64, flags int) (errno int) +//sys Sysinfo(info *Sysinfo_t) (errno int) +//sys Tee(rfd int, wfd int, len int, flags int) (n int64, errno int) +//sys Tgkill(tgid int, tid int, sig int) (errno int) +//sys Time(t *Time_t) (tt Time_t, errno int) +//sys Times(tms *Tms) (ticks uintptr, errno int) +//sys Truncate(path string, length int64) (errno int) +//sys Umask(mask int) (oldmask int) +//sys Uname(buf *Utsname) (errno int) +//sys Unlink(path string) (errno int) +//sys Unlinkat(dirfd int, path string) (errno int) +//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) + +/* + * Unimplemented + */ +// AddKey +// AfsSyscall +// Alarm +// ArchPrctl +// Brk +// Capget +// Capset +// ClockGetres +// ClockGettime +// ClockNanosleep +// ClockSettime +// Clone +// CreateModule +// DeleteModule +// EpollCtlOld +// EpollPwait +// EpollWaitOld +// Eventfd +// Execve +// Fadvise64 +// Fgetxattr +// Flistxattr +// Flock +// Fork +// Fremovexattr +// Fsetxattr +// Futex +// GetKernelSyms +// GetMempolicy +// GetRobustList +// GetThreadArea +// Getitimer +// Getpmsg +// Getpriority +// Getxattr +// InotifyAddWatch +// InotifyInit +// InotifyRmWatch +// IoCancel +// IoDestroy +// IoGetevents +// IoSetup +// IoSubmit +// Ioctl +// IoprioGet +// IoprioSet +// KexecLoad +// Keyctl +// Lgetxattr +// Listxattr +// Llistxattr +// LookupDcookie +// Lremovexattr +// Lsetxattr +// Madvise +// Mbind +// MigratePages +// Mincore +// Mlock +// Mmap +// ModifyLdt +// Mount +// MovePages +// Mprotect +// MqGetsetattr +// MqNotify +// MqOpen +// MqTimedreceive +// MqTimedsend +// MqUnlink +// Mremap +// Msgctl +// Msgget +// Msgrcv +// Msgsnd +// Msync +// Munlock +// Munlockall +// Munmap +// Newfstatat +// Nfsservctl +// Personality +// Poll +// Ppoll +// Prctl +// Pselect6 +// Ptrace +// Putpmsg +// QueryModule +// Quotactl +// Readahead +// Readv +// Reboot +// 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 +// Sendfile +// 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..9bf3f9cf0 --- /dev/null +++ b/src/pkg/syscall/syscall_linux_386.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 syscall + +import ( + "syscall"; + "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; +} + +// 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 accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, errno int) { + fd, errno = socketcall(_SOCKET, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0); + return; +} + +func bind(s int, addr uintptr, addrlen _Socklen) (errno int) { + var _ int; + _, errno = socketcall(_BIND, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0); + return; +} + +func connect(s int, addr uintptr, addrlen _Socklen) (errno int) { + var _ 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 = socketcall(_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto), 0, 0, 0); + return; +} + +func setsockopt(s int, level int, name int, val uintptr, vallen int) (errno int) { + var _ int; + _, errno = socketcall(_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0); + return; +} + +func Listen(s int, n int) (errno int) { + var _ int; + _, errno = socketcall(_LISTEN, uintptr(s), uintptr(n), 0, 0, 0, 0); + return; +} + diff --git a/src/pkg/syscall/syscall_linux_amd64.go b/src/pkg/syscall/syscall_linux_amd64.go new file mode 100644 index 000000000..a2a58c35b --- /dev/null +++ b/src/pkg/syscall/syscall_linux_amd64.go @@ -0,0 +1,41 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package syscall + +import "syscall" + +//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) +//sys socket(domain int, typ int, proto int) (fd int, errno int) +//sys setsockopt(s int, level int, name int, val uintptr, vallen int) (errno int) +//sys Listen(s int, n int) (errno int) +//sys Shutdown(fd int, how int) (errno int) + +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.Sec = nsec/1e9; + tv.Usec = nsec%1e9 / 1e3; + return; +} + diff --git a/src/pkg/syscall/types_darwin.c b/src/pkg/syscall/types_darwin.c new file mode 100644 index 000000000..65afd6ca6 --- /dev/null +++ b/src/pkg/syscall/types_darwin.c @@ -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. + +/* +Input to godefs. See PORT. + */ + +#define __DARWIN_UNIX03 0 +#define KERNEL +#define _DARWIN_USE_64_BIT_INODE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Machine characteristics; for internal use. + +enum +{ + $sizeofPtr = sizeof(void*), + $sizeofShort = sizeof(short), + $sizeofInt = sizeof(int), + $sizeofLong = sizeof(long), + $sizeofLongLong = sizeof(long long), +}; + + +// Time + +typedef struct timespec $Timespec; +typedef struct timeval $Timeval; + +// Processes + +typedef struct rusage $Rusage; +typedef struct rlimit $Rlimit; + +typedef int $_C_int; +typedef gid_t $_Gid_t; + +// Files + +enum +{ + $O_RDONLY = O_RDONLY, + $O_WRONLY = O_WRONLY, + $O_RDWR = O_RDWR, + $O_APPEND = O_APPEND, + $O_ASYNC = O_ASYNC, + $O_CREAT = O_CREAT, + $O_NOCTTY = O_NOCTTY, + $O_NONBLOCK = O_NONBLOCK, + $O_SYNC = O_SYNC, + $O_TRUNC = O_TRUNC, + $O_CLOEXEC = 0, // not supported + + $F_GETFD = F_GETFD, + $F_SETFD = F_SETFD, + + $F_GETFL = F_GETFL, + $F_SETFL = F_SETFL, + + $FD_CLOEXEC = FD_CLOEXEC, + + $NAME_MAX = NAME_MAX +}; + +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_IFWHT = S_IFWHT, + $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 stat64 $Stat_t; +typedef struct statfs64 $Statfs_t; + +typedef struct dirent $Dirent; + +// Wait status. + +enum +{ + $WNOHANG = WNOHANG, + $WUNTRACED = WUNTRACED, + $WEXITED = WEXITED, + $WSTOPPED = WSTOPPED, + $WCONTINUED = WCONTINUED, + $WNOWAIT = WNOWAIT, +}; + +// Sockets + +enum +{ + $AF_UNIX = AF_UNIX, + $AF_INET = AF_INET, + $AF_DATAKIT = AF_DATAKIT, + $AF_INET6 = AF_INET6, + + $SOCK_STREAM = SOCK_STREAM, + $SOCK_DGRAM = SOCK_DGRAM, + $SOCK_RAW = SOCK_RAW, + $SOCK_SEQPACKET = SOCK_SEQPACKET, + + $SOL_SOCKET = SOL_SOCKET, + + $SO_REUSEADDR = SO_REUSEADDR, + $SO_KEEPALIVE = SO_KEEPALIVE, + $SO_DONTROUTE = SO_DONTROUTE, + $SO_BROADCAST = SO_BROADCAST, + $SO_USELOOPBACK = SO_USELOOPBACK, + $SO_LINGER = SO_LINGER, + $SO_REUSEPORT = SO_REUSEPORT, + $SO_SNDBUF = SO_SNDBUF, + $SO_RCVBUF = SO_RCVBUF, + $SO_SNDTIMEO = SO_SNDTIMEO, + $SO_RCVTIMEO = SO_RCVTIMEO, + $SO_NOSIGPIPE = SO_NOSIGPIPE, + + $IPPROTO_TCP = IPPROTO_TCP, + $IPPROTO_UDP = IPPROTO_UDP, + + $TCP_NODELAY = TCP_NODELAY, + + $SOMAXCONN = SOMAXCONN +}; + +typedef struct sockaddr_in $RawSockaddrInet4; +typedef struct sockaddr_in6 $RawSockaddrInet6; +typedef struct sockaddr_un $RawSockaddrUnix; +typedef struct sockaddr $RawSockaddr; + +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_any { + struct sockaddr addr; + char pad[sizeof(union sockaddr_all) - sizeof(struct sockaddr)]; +}; + +enum { + $SizeofSockaddrInet4 = sizeof(struct sockaddr_in), + $SizeofSockaddrInet6 = sizeof(struct sockaddr_in6), + $SizeofSockaddrAny = sizeof(struct sockaddr_any), + $SizeofSockaddrUnix = sizeof(struct sockaddr_un), +}; + +typedef struct sockaddr_any $RawSockaddrAny; +typedef socklen_t $_Socklen; +typedef struct linger $Linger; + +// Events (kqueue, kevent) + +enum { + // filters + $EVFILT_READ = EVFILT_READ, + $EVFILT_WRITE = EVFILT_WRITE, + $EVFILT_AIO = EVFILT_AIO, + $EVFILT_VNODE = EVFILT_VNODE, + $EVFILT_PROC = EVFILT_PROC, + $EVFILT_SIGNAL = EVFILT_SIGNAL, + $EVFILT_TIMER = EVFILT_TIMER, + $EVFILT_MACHPORT = EVFILT_MACHPORT, + $EVFILT_FS = EVFILT_FS, + + $EVFILT_SYSCOUNT = EVFILT_SYSCOUNT, + + // actions + $EV_ADD = EV_ADD, + $EV_DELETE = EV_DELETE, + $EV_DISABLE = EV_DISABLE, + $EV_RECEIPT = EV_RECEIPT, + + // flags + $EV_ONESHOT = EV_ONESHOT, + $EV_CLEAR = EV_CLEAR, + $EV_SYSFLAGS = EV_SYSFLAGS, + $EV_FLAG0 = EV_FLAG0, + $EV_FLAG1 = EV_FLAG1, + + // returned values + $EV_EOF = EV_EOF, + $EV_ERROR = EV_ERROR, +}; + +typedef struct kevent $Kevent_t; + +// Select + +typedef fd_set $FdSet; diff --git a/src/pkg/syscall/types_darwin_386.c b/src/pkg/syscall/types_darwin_386.c new file mode 100644 index 000000000..dd5356944 --- /dev/null +++ b/src/pkg/syscall/types_darwin_386.c @@ -0,0 +1 @@ +// Nothing to see here. diff --git a/src/pkg/syscall/types_darwin_amd64.c b/src/pkg/syscall/types_darwin_amd64.c new file mode 100644 index 000000000..dd5356944 --- /dev/null +++ b/src/pkg/syscall/types_darwin_amd64.c @@ -0,0 +1 @@ +// Nothing to see here. diff --git a/src/pkg/syscall/types_linux.c b/src/pkg/syscall/types_linux.c new file mode 100644 index 000000000..261772eac --- /dev/null +++ b/src/pkg/syscall/types_linux.c @@ -0,0 +1,217 @@ +// Copyright 2009 The Go 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 PORT. + */ + +#define __DARWIN_UNIX03 0 +#define KERNEL + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// 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, +}; + + +// 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 int $_C_int; +typedef gid_t $_Gid_t; + +// Files + +enum +{ + $O_RDONLY = O_RDONLY, + $O_WRONLY = O_WRONLY, + $O_RDWR = O_RDWR, + $O_APPEND = O_APPEND, + $O_ASYNC = O_ASYNC, + $O_CREAT = O_CREAT, + $O_NOCTTY = O_NOCTTY, + $O_NONBLOCK = O_NONBLOCK, + $O_SYNC = O_SYNC, + $O_TRUNC = O_TRUNC, + $O_CLOEXEC = 0, // not supported + + $F_GETFD = F_GETFD, + $F_SETFD = F_SETFD, + + $F_GETFL = F_GETFL, + $F_SETFL = F_SETFL, + + $FD_CLOEXEC = FD_CLOEXEC, + + $NAME_MAX = NAME_MAX +}; + +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 dirent $Dirent; + +// Wait status. + +enum +{ + $WNOHANG = WNOHANG, + $WUNTRACED = WUNTRACED, + $WEXITED = WEXITED, + $WSTOPPED = WSTOPPED, + $WCONTINUED = WCONTINUED, + $WNOWAIT = WNOWAIT, +}; + +// Sockets + +enum +{ + $AF_UNIX = AF_UNIX, + $AF_INET = AF_INET, + $AF_INET6 = AF_INET6, + + $SOCK_STREAM = SOCK_STREAM, + $SOCK_DGRAM = SOCK_DGRAM, + $SOCK_RAW = SOCK_RAW, + $SOCK_SEQPACKET = SOCK_SEQPACKET, + + $SOL_SOCKET = SOL_SOCKET, + + $SO_REUSEADDR = SO_REUSEADDR, + $SO_KEEPALIVE = SO_KEEPALIVE, + $SO_DONTROUTE = SO_DONTROUTE, + $SO_BROADCAST = SO_BROADCAST, + $SO_LINGER = SO_LINGER, + $SO_SNDBUF = SO_SNDBUF, + $SO_RCVBUF = SO_RCVBUF, + $SO_SNDTIMEO = SO_SNDTIMEO, + $SO_RCVTIMEO = SO_RCVTIMEO, + + $IPPROTO_TCP = IPPROTO_TCP, + $IPPROTO_UDP = IPPROTO_UDP, + + $TCP_NODELAY = TCP_NODELAY, + + $SOMAXCONN = SOMAXCONN +}; + +typedef struct sockaddr_in $RawSockaddrInet4; +typedef struct sockaddr_in6 $RawSockaddrInet6; +typedef struct sockaddr_un $RawSockaddrUnix; +typedef struct sockaddr $RawSockaddr; + +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_any { + struct sockaddr addr; + char pad[sizeof(union sockaddr_all) - sizeof(struct sockaddr)]; +}; + +enum { + $SizeofSockaddrInet4 = sizeof(struct sockaddr_in), + $SizeofSockaddrInet6 = sizeof(struct sockaddr_in6), + $SizeofSockaddrAny = sizeof(struct sockaddr_any), + $SizeofSockaddrUnix = sizeof(struct sockaddr_un), +}; + +typedef struct sockaddr_any $RawSockaddrAny; +typedef socklen_t $_Socklen; +typedef struct linger $Linger; + +// Misc + +enum { + $EPOLLIN = EPOLLIN, + $EPOLLRDHUP = EPOLLRDHUP, + $EPOLLOUT = EPOLLOUT, + $EPOLLONESHOT = EPOLLONESHOT, + $EPOLL_CTL_MOD = EPOLL_CTL_MOD, + $EPOLL_CTL_ADD = EPOLL_CTL_ADD, + $EPOLL_CTL_DEL = EPOLL_CTL_DEL, +}; + +typedef fd_set $FdSet; +typedef struct sysinfo $Sysinfo_t; +typedef struct utsname $Utsname; +typedef struct ustat $Ustat_t; + +// The real epoll_event is a union, and godefs doesn't handle it well. +struct my_epoll_event { + uint32_t events; + int32_t fd; + int32_t pad; +}; + +typedef struct my_epoll_event $EpollEvent; diff --git a/src/pkg/syscall/types_linux_386.c b/src/pkg/syscall/types_linux_386.c new file mode 100644 index 000000000..3b5481af4 --- /dev/null +++ b/src/pkg/syscall/types_linux_386.c @@ -0,0 +1 @@ +// Nothing to see here diff --git a/src/pkg/syscall/types_linux_amd64.c b/src/pkg/syscall/types_linux_amd64.c new file mode 100644 index 000000000..3b5481af4 --- /dev/null +++ b/src/pkg/syscall/types_linux_amd64.c @@ -0,0 +1 @@ +// Nothing to see here diff --git a/src/pkg/syscall/zerrors_darwin_386.go b/src/pkg/syscall/zerrors_darwin_386.go new file mode 100644 index 000000000..bc2d17656 --- /dev/null +++ b/src/pkg/syscall/zerrors_darwin_386.go @@ -0,0 +1,260 @@ +// mkerrors +// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT + +// godefs -gsyscall _errors.c + +// MACHINE GENERATED - DO NOT EDIT. + +package syscall + +// Constants +const ( + EMULTIHOP = 0x5f; + EAFNOSUPPORT = 0x2f; + EACCES = 0xd; + EDESTADDRREQ = 0x27; + EILSEQ = 0x5c; + ESPIPE = 0x1d; + EMLINK = 0x1f; + EPROGUNAVAIL = 0x4a; + ENOTTY = 0x19; + EBADF = 0x9; + ERANGE = 0x22; + ECANCELED = 0x59; + ETXTBSY = 0x1a; + ENOMEM = 0xc; + EINPROGRESS = 0x24; + ENOTEMPTY = 0x42; + ENOTBLK = 0xf; + EPROTOTYPE = 0x29; + ENOMSG = 0x5b; + ERPCMISMATCH = 0x49; + ENOTDIR = 0x14; + EALREADY = 0x25; + ETIMEDOUT = 0x3c; + ENEEDAUTH = 0x51; + ENODATA = 0x60; + EINTR = 0x4; + ENOLINK = 0x61; + EPERM = 0x1; + ENETDOWN = 0x32; + ESTALE = 0x46; + ENOTSOCK = 0x26; + ENOSR = 0x62; + EAUTH = 0x50; + ECHILD = 0xa; + EPIPE = 0x20; + ENOATTR = 0x5d; + EBADMSG = 0x5e; + EREMOTE = 0x47; + ETOOMANYREFS = 0x3b; + EPFNOSUPPORT = 0x2e; + EPROCUNAVAIL = 0x4c; + EADDRINUSE = 0x30; + ENETRESET = 0x34; + EISDIR = 0x15; + EIDRM = 0x5a; + EDEVERR = 0x53; + EINVAL = 0x16; + ESHUTDOWN = 0x3a; + EPWROFF = 0x52; + EOVERFLOW = 0x54; + EBUSY = 0x10; + EPROCLIM = 0x43; + EPROTO = 0x64; + ENODEV = 0x13; + EROFS = 0x1e; + E2BIG = 0x7; + EDEADLK = 0xb; + ECONNRESET = 0x36; + EBADMACHO = 0x58; + ENXIO = 0x6; + EBADRPC = 0x48; + ENAMETOOLONG = 0x3f; + ELAST = 0x67; + ESOCKTNOSUPPORT = 0x2c; + EADDRNOTAVAIL = 0x31; + ETIME = 0x65; + EPROTONOSUPPORT = 0x2b; + EIO = 0x5; + ENETUNREACH = 0x33; + EXDEV = 0x12; + EDQUOT = 0x45; + ENOSPC = 0x1c; + ENOEXEC = 0x8; + EMSGSIZE = 0x28; + EFTYPE = 0x4f; + EDOM = 0x21; + ENOSTR = 0x63; + EFBIG = 0x1b; + ESRCH = 0x3; + EHOSTDOWN = 0x40; + ENOLCK = 0x4d; + ENFILE = 0x17; + ENOSYS = 0x4e; + EBADARCH = 0x56; + ENOTCONN = 0x39; + ENOTSUP = 0x2d; + ECONNABORTED = 0x35; + EISCONN = 0x38; + ESHLIBVERS = 0x57; + EUSERS = 0x44; + ENOPROTOOPT = 0x2a; + EMFILE = 0x18; + ELOOP = 0x3e; + ENOBUFS = 0x37; + EFAULT = 0xe; + EWOULDBLOCK = 0x23; + EBADEXEC = 0x55; + ENOPOLICY = 0x67; + ECONNREFUSED = 0x3d; + EAGAIN = 0x23; + EEXIST = 0x11; + EPROGMISMATCH = 0x4b; + ENOENT = 0x2; + EHOSTUNREACH = 0x41; + EOPNOTSUPP = 0x66; + SIGBUS = 0xa; + SIGTTIN = 0x15; + SIGPROF = 0x1b; + SIGFPE = 0x8; + SIGHUP = 0x1; + SIGTTOU = 0x16; + SIGUSR1 = 0x1e; + SIGURG = 0x10; + SIGQUIT = 0x3; + SIGIO = 0x17; + SIGABRT = 0x6; + SIGINFO = 0x1d; + SIGUSR2 = 0x1f; + SIGTRAP = 0x5; + SIGVTALRM = 0x1a; + SIGSEGV = 0xb; + SIGCONT = 0x13; + SIGPIPE = 0xd; + SIGXFSZ = 0x19; + SIGCHLD = 0x14; + SIGSYS = 0xc; + SIGSTOP = 0x11; + SIGALRM = 0xe; + SIGTSTP = 0x12; + SIGEMT = 0x7; + SIGKILL = 0x9; + SIGXCPU = 0x18; + SIGILL = 0x4; + SIGINT = 0x2; + SIGIOT = 0x6; + SIGTERM = 0xf; + SIGWINCH = 0x1c; +) + +// Types + + +// Error table +var errors = [...]string { + 95: "EMULTIHOP (Reserved)", + 47: "address family not supported by protocol family", + 13: "permission denied", + 39: "destination address required", + 92: "illegal byte sequence", + 29: "illegal seek", + 31: "too many links", + 74: "RPC prog. not avail", + 25: "inappropriate ioctl for device", + 9: "bad file descriptor", + 34: "result too large", + 89: "operation canceled", + 26: "text file busy", + 12: "cannot allocate memory", + 36: "operation now in progress", + 66: "directory not empty", + 15: "block device required", + 41: "protocol wrong type for socket", + 91: "no message of desired type", + 73: "RPC version wrong", + 20: "not a directory", + 37: "operation already in progress", + 60: "operation timed out", + 81: "need authenticator", + 96: "no message available on STREAM", + 4: "interrupted system call", + 97: "ENOLINK (Reserved)", + 1: "operation not permitted", + 50: "network is down", + 70: "stale NFS file handle", + 38: "socket operation on non-socket", + 98: "no STREAM resources", + 80: "authentication error", + 10: "no child processes", + 32: "broken pipe", + 93: "attribute not found", + 94: "bad message", + 71: "too many levels of remote in path", + 59: "too many references: can't splice", + 46: "protocol family not supported", + 76: "bad procedure for program", + 48: "address already in use", + 52: "network dropped connection on reset", + 21: "is a directory", + 90: "identifier removed", + 83: "device error", + 22: "invalid argument", + 58: "can't send after socket shutdown", + 82: "device power is off", + 84: "value too large to be stored in data type", + 16: "resource busy", + 67: "too many processes", + 100: "protocol error", + 19: "operation not supported by device", + 30: "read-only file system", + 7: "argument list too long", + 11: "resource deadlock avoided", + 54: "connection reset by peer", + 88: "malformed Mach-o file", + 6: "device not configured", + 72: "RPC struct is bad", + 63: "file name too long", + 103: "policy not found", + 44: "socket type not supported", + 49: "can't assign requested address", + 101: "STREAM ioctl timeout", + 43: "protocol not supported", + 5: "input/output error", + 51: "network is unreachable", + 18: "cross-device link", + 69: "disc quota exceeded", + 28: "no space left on device", + 8: "exec format error", + 40: "message too long", + 79: "inappropriate file type or format", + 33: "numerical argument out of domain", + 99: "not a STREAM", + 27: "file too large", + 3: "no such process", + 64: "host is down", + 77: "no locks available", + 23: "too many open files in system", + 78: "function not implemented", + 86: "bad CPU type in executable", + 57: "socket is not connected", + 45: "operation not supported", + 53: "software caused connection abort", + 56: "socket is already connected", + 87: "shared library version mismatch", + 68: "too many users", + 42: "protocol not available", + 24: "too many open files", + 62: "too many levels of symbolic links", + 55: "no buffer space available", + 14: "bad address", + 35: "resource temporarily unavailable", + 85: "bad executable (or shared library)", + 61: "connection refused", + 17: "file exists", + 75: "program version wrong", + 2: "no such file or directory", + 65: "no route to host", + 102: "operation not supported on socket", +} + diff --git a/src/pkg/syscall/zerrors_darwin_amd64.go b/src/pkg/syscall/zerrors_darwin_amd64.go new file mode 100644 index 000000000..bc2d17656 --- /dev/null +++ b/src/pkg/syscall/zerrors_darwin_amd64.go @@ -0,0 +1,260 @@ +// mkerrors +// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT + +// godefs -gsyscall _errors.c + +// MACHINE GENERATED - DO NOT EDIT. + +package syscall + +// Constants +const ( + EMULTIHOP = 0x5f; + EAFNOSUPPORT = 0x2f; + EACCES = 0xd; + EDESTADDRREQ = 0x27; + EILSEQ = 0x5c; + ESPIPE = 0x1d; + EMLINK = 0x1f; + EPROGUNAVAIL = 0x4a; + ENOTTY = 0x19; + EBADF = 0x9; + ERANGE = 0x22; + ECANCELED = 0x59; + ETXTBSY = 0x1a; + ENOMEM = 0xc; + EINPROGRESS = 0x24; + ENOTEMPTY = 0x42; + ENOTBLK = 0xf; + EPROTOTYPE = 0x29; + ENOMSG = 0x5b; + ERPCMISMATCH = 0x49; + ENOTDIR = 0x14; + EALREADY = 0x25; + ETIMEDOUT = 0x3c; + ENEEDAUTH = 0x51; + ENODATA = 0x60; + EINTR = 0x4; + ENOLINK = 0x61; + EPERM = 0x1; + ENETDOWN = 0x32; + ESTALE = 0x46; + ENOTSOCK = 0x26; + ENOSR = 0x62; + EAUTH = 0x50; + ECHILD = 0xa; + EPIPE = 0x20; + ENOATTR = 0x5d; + EBADMSG = 0x5e; + EREMOTE = 0x47; + ETOOMANYREFS = 0x3b; + EPFNOSUPPORT = 0x2e; + EPROCUNAVAIL = 0x4c; + EADDRINUSE = 0x30; + ENETRESET = 0x34; + EISDIR = 0x15; + EIDRM = 0x5a; + EDEVERR = 0x53; + EINVAL = 0x16; + ESHUTDOWN = 0x3a; + EPWROFF = 0x52; + EOVERFLOW = 0x54; + EBUSY = 0x10; + EPROCLIM = 0x43; + EPROTO = 0x64; + ENODEV = 0x13; + EROFS = 0x1e; + E2BIG = 0x7; + EDEADLK = 0xb; + ECONNRESET = 0x36; + EBADMACHO = 0x58; + ENXIO = 0x6; + EBADRPC = 0x48; + ENAMETOOLONG = 0x3f; + ELAST = 0x67; + ESOCKTNOSUPPORT = 0x2c; + EADDRNOTAVAIL = 0x31; + ETIME = 0x65; + EPROTONOSUPPORT = 0x2b; + EIO = 0x5; + ENETUNREACH = 0x33; + EXDEV = 0x12; + EDQUOT = 0x45; + ENOSPC = 0x1c; + ENOEXEC = 0x8; + EMSGSIZE = 0x28; + EFTYPE = 0x4f; + EDOM = 0x21; + ENOSTR = 0x63; + EFBIG = 0x1b; + ESRCH = 0x3; + EHOSTDOWN = 0x40; + ENOLCK = 0x4d; + ENFILE = 0x17; + ENOSYS = 0x4e; + EBADARCH = 0x56; + ENOTCONN = 0x39; + ENOTSUP = 0x2d; + ECONNABORTED = 0x35; + EISCONN = 0x38; + ESHLIBVERS = 0x57; + EUSERS = 0x44; + ENOPROTOOPT = 0x2a; + EMFILE = 0x18; + ELOOP = 0x3e; + ENOBUFS = 0x37; + EFAULT = 0xe; + EWOULDBLOCK = 0x23; + EBADEXEC = 0x55; + ENOPOLICY = 0x67; + ECONNREFUSED = 0x3d; + EAGAIN = 0x23; + EEXIST = 0x11; + EPROGMISMATCH = 0x4b; + ENOENT = 0x2; + EHOSTUNREACH = 0x41; + EOPNOTSUPP = 0x66; + SIGBUS = 0xa; + SIGTTIN = 0x15; + SIGPROF = 0x1b; + SIGFPE = 0x8; + SIGHUP = 0x1; + SIGTTOU = 0x16; + SIGUSR1 = 0x1e; + SIGURG = 0x10; + SIGQUIT = 0x3; + SIGIO = 0x17; + SIGABRT = 0x6; + SIGINFO = 0x1d; + SIGUSR2 = 0x1f; + SIGTRAP = 0x5; + SIGVTALRM = 0x1a; + SIGSEGV = 0xb; + SIGCONT = 0x13; + SIGPIPE = 0xd; + SIGXFSZ = 0x19; + SIGCHLD = 0x14; + SIGSYS = 0xc; + SIGSTOP = 0x11; + SIGALRM = 0xe; + SIGTSTP = 0x12; + SIGEMT = 0x7; + SIGKILL = 0x9; + SIGXCPU = 0x18; + SIGILL = 0x4; + SIGINT = 0x2; + SIGIOT = 0x6; + SIGTERM = 0xf; + SIGWINCH = 0x1c; +) + +// Types + + +// Error table +var errors = [...]string { + 95: "EMULTIHOP (Reserved)", + 47: "address family not supported by protocol family", + 13: "permission denied", + 39: "destination address required", + 92: "illegal byte sequence", + 29: "illegal seek", + 31: "too many links", + 74: "RPC prog. not avail", + 25: "inappropriate ioctl for device", + 9: "bad file descriptor", + 34: "result too large", + 89: "operation canceled", + 26: "text file busy", + 12: "cannot allocate memory", + 36: "operation now in progress", + 66: "directory not empty", + 15: "block device required", + 41: "protocol wrong type for socket", + 91: "no message of desired type", + 73: "RPC version wrong", + 20: "not a directory", + 37: "operation already in progress", + 60: "operation timed out", + 81: "need authenticator", + 96: "no message available on STREAM", + 4: "interrupted system call", + 97: "ENOLINK (Reserved)", + 1: "operation not permitted", + 50: "network is down", + 70: "stale NFS file handle", + 38: "socket operation on non-socket", + 98: "no STREAM resources", + 80: "authentication error", + 10: "no child processes", + 32: "broken pipe", + 93: "attribute not found", + 94: "bad message", + 71: "too many levels of remote in path", + 59: "too many references: can't splice", + 46: "protocol family not supported", + 76: "bad procedure for program", + 48: "address already in use", + 52: "network dropped connection on reset", + 21: "is a directory", + 90: "identifier removed", + 83: "device error", + 22: "invalid argument", + 58: "can't send after socket shutdown", + 82: "device power is off", + 84: "value too large to be stored in data type", + 16: "resource busy", + 67: "too many processes", + 100: "protocol error", + 19: "operation not supported by device", + 30: "read-only file system", + 7: "argument list too long", + 11: "resource deadlock avoided", + 54: "connection reset by peer", + 88: "malformed Mach-o file", + 6: "device not configured", + 72: "RPC struct is bad", + 63: "file name too long", + 103: "policy not found", + 44: "socket type not supported", + 49: "can't assign requested address", + 101: "STREAM ioctl timeout", + 43: "protocol not supported", + 5: "input/output error", + 51: "network is unreachable", + 18: "cross-device link", + 69: "disc quota exceeded", + 28: "no space left on device", + 8: "exec format error", + 40: "message too long", + 79: "inappropriate file type or format", + 33: "numerical argument out of domain", + 99: "not a STREAM", + 27: "file too large", + 3: "no such process", + 64: "host is down", + 77: "no locks available", + 23: "too many open files in system", + 78: "function not implemented", + 86: "bad CPU type in executable", + 57: "socket is not connected", + 45: "operation not supported", + 53: "software caused connection abort", + 56: "socket is already connected", + 87: "shared library version mismatch", + 68: "too many users", + 42: "protocol not available", + 24: "too many open files", + 62: "too many levels of symbolic links", + 55: "no buffer space available", + 14: "bad address", + 35: "resource temporarily unavailable", + 85: "bad executable (or shared library)", + 61: "connection refused", + 17: "file exists", + 75: "program version wrong", + 2: "no such file or directory", + 65: "no route to host", + 102: "operation not supported on socket", +} + diff --git a/src/pkg/syscall/zerrors_linux_386.go b/src/pkg/syscall/zerrors_linux_386.go new file mode 100644 index 000000000..f1e7e011d --- /dev/null +++ b/src/pkg/syscall/zerrors_linux_386.go @@ -0,0 +1,316 @@ +// mkerrors +// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT + +// godefs -gsyscall _errors.c + +// MACHINE GENERATED - DO NOT EDIT. + +package syscall + +// Constants +const ( + EMULTIHOP = 0x48; + EUNATCH = 0x31; + EAFNOSUPPORT = 0x61; + EREMCHG = 0x4e; + EACCES = 0xd; + EL3RST = 0x2f; + EDESTADDRREQ = 0x59; + EILSEQ = 0x54; + ESPIPE = 0x1d; + EMLINK = 0x1f; + EOWNERDEAD = 0x82; + ENOTTY = 0x19; + EBADE = 0x34; + EBADF = 0x9; + EBADR = 0x35; + EADV = 0x44; + ERANGE = 0x22; + ECANCELED = 0x7d; + ETXTBSY = 0x1a; + ENOMEM = 0xc; + EINPROGRESS = 0x73; + ENOTBLK = 0xf; + EPROTOTYPE = 0x5b; + ERESTART = 0x55; + EISNAM = 0x78; + ENOMSG = 0x2a; + EALREADY = 0x72; + ETIMEDOUT = 0x6e; + ENODATA = 0x3d; + EINTR = 0x4; + ENOLINK = 0x43; + EPERM = 0x1; + ELOOP = 0x28; + ENETDOWN = 0x64; + ESTALE = 0x74; + ENOTSOCK = 0x58; + ENOSR = 0x3f; + ECHILD = 0xa; + ELNRNG = 0x30; + EPIPE = 0x20; + EBADMSG = 0x4a; + EBFONT = 0x3b; + EREMOTE = 0x42; + ETOOMANYREFS = 0x6d; + EPFNOSUPPORT = 0x60; + ENONET = 0x40; + EXFULL = 0x36; + EBADSLT = 0x39; + ENOTNAM = 0x76; + ELIBEXEC = 0x53; + ENOCSI = 0x32; + ENOTEMPTY = 0x27; + EADDRINUSE = 0x62; + ENETRESET = 0x66; + EISDIR = 0x15; + EIDRM = 0x2b; + ECOMM = 0x46; + EBADFD = 0x4d; + EL2HLT = 0x33; + ENOKEY = 0x7e; + EINVAL = 0x16; + ESHUTDOWN = 0x6c; + EKEYREJECTED = 0x81; + ELIBSCN = 0x51; + ENAVAIL = 0x77; + ENOSTR = 0x3c; + EOVERFLOW = 0x4b; + EUCLEAN = 0x75; + ENOMEDIUM = 0x7b; + EBUSY = 0x10; + EPROTO = 0x47; + ENODEV = 0x13; + EKEYEXPIRED = 0x7f; + EROFS = 0x1e; + ELIBACC = 0x4f; + E2BIG = 0x7; + EDEADLK = 0x23; + ECONNRESET = 0x68; + ENXIO = 0x6; + EBADRQC = 0x38; + ENAMETOOLONG = 0x24; + ESOCKTNOSUPPORT = 0x5e; + EDOTDOT = 0x49; + EADDRNOTAVAIL = 0x63; + ETIME = 0x3e; + EPROTONOSUPPORT = 0x5d; + ENOTRECOVERABLE = 0x83; + EIO = 0x5; + ENETUNREACH = 0x65; + EXDEV = 0x12; + EDQUOT = 0x7a; + EREMOTEIO = 0x79; + ENOSPC = 0x1c; + ENOEXEC = 0x8; + EMSGSIZE = 0x5a; + EDOM = 0x21; + EFBIG = 0x1b; + ESRCH = 0x3; + ECHRNG = 0x2c; + EHOSTDOWN = 0x70; + ENOLCK = 0x25; + ENFILE = 0x17; + ENOSYS = 0x26; + ENOTCONN = 0x6b; + ENOTSUP = 0x5f; + ESRMNT = 0x45; + EDEADLOCK = 0x23; + ECONNABORTED = 0x67; + ENOANO = 0x37; + EISCONN = 0x6a; + EUSERS = 0x57; + ENOPROTOOPT = 0x5c; + EMFILE = 0x18; + ENOBUFS = 0x69; + EL3HLT = 0x2e; + EFAULT = 0xe; + EWOULDBLOCK = 0xb; + ELIBBAD = 0x50; + ESTRPIPE = 0x56; + ECONNREFUSED = 0x6f; + EAGAIN = 0xb; + ELIBMAX = 0x52; + EEXIST = 0x11; + EL2NSYNC = 0x2d; + ENOENT = 0x2; + ENOPKG = 0x41; + EKEYREVOKED = 0x80; + EHOSTUNREACH = 0x71; + ENOTUNIQ = 0x4c; + EOPNOTSUPP = 0x5f; + ENOTDIR = 0x14; + EMEDIUMTYPE = 0x7c; + SIGBUS = 0x7; + SIGTTIN = 0x15; + SIGPROF = 0x1b; + SIGFPE = 0x8; + SIGHUP = 0x1; + SIGTTOU = 0x16; + SIGSTKFLT = 0x10; + SIGUSR1 = 0xa; + SIGURG = 0x17; + SIGQUIT = 0x3; + SIGCLD = 0x11; + SIGIO = 0x1d; + SIGABRT = 0x6; + SIGUSR2 = 0xc; + SIGTRAP = 0x5; + SIGVTALRM = 0x1a; + SIGPOLL = 0x1d; + SIGSEGV = 0xb; + SIGCONT = 0x12; + SIGPIPE = 0xd; + SIGWINCH = 0x1c; + SIGXFSZ = 0x19; + SIGCHLD = 0x11; + SIGSYS = 0x1f; + SIGSTOP = 0x13; + SIGALRM = 0xe; + SIGTSTP = 0x14; + SIGKILL = 0x9; + SIGXCPU = 0x18; + SIGUNUSED = 0x1f; + SIGPWR = 0x1e; + SIGILL = 0x4; + SIGINT = 0x2; + SIGIOT = 0x6; + SIGTERM = 0xf; +) + +// Types + + +// Error table +var errors = [...]string { + 72: "multihop attempted", + 49: "protocol driver not attached", + 97: "address family not supported by protocol", + 78: "remote address changed", + 13: "permission denied", + 47: "level 3 reset", + 89: "destination address required", + 84: "invalid or incomplete multibyte or wide character", + 29: "illegal seek", + 31: "too many links", + 130: "owner died", + 25: "inappropriate ioctl for device", + 52: "invalid exchange", + 9: "bad file descriptor", + 53: "invalid request descriptor", + 68: "advertise error", + 34: "numerical result out of range", + 125: "operation canceled", + 26: "text file busy", + 12: "cannot allocate memory", + 115: "operation now in progress", + 15: "block device required", + 91: "protocol wrong type for socket", + 85: "interrupted system call should be restarted", + 120: "is a named type file", + 42: "no message of desired type", + 114: "operation already in progress", + 110: "connection timed out", + 61: "no data available", + 4: "interrupted system call", + 67: "link has been severed", + 1: "operation not permitted", + 40: "too many levels of symbolic links", + 100: "network is down", + 116: "stale NFS file handle", + 88: "socket operation on non-socket", + 63: "out of streams resources", + 10: "no child processes", + 48: "link number out of range", + 32: "broken pipe", + 74: "bad message", + 59: "bad font file format", + 66: "object is remote", + 109: "too many references: cannot splice", + 96: "protocol family not supported", + 64: "machine is not on the network", + 54: "exchange full", + 57: "invalid slot", + 118: "not a XENIX named type file", + 83: "cannot exec a shared library directly", + 50: "no CSI structure available", + 39: "directory not empty", + 98: "address already in use", + 102: "network dropped connection on reset", + 21: "is a directory", + 43: "identifier removed", + 70: "communication error on send", + 77: "file descriptor in bad state", + 51: "level 2 halted", + 126: "required key not available", + 22: "invalid argument", + 108: "cannot send after transport endpoint shutdown", + 129: "key was rejected by service", + 81: ".lib section in a.out corrupted", + 119: "no XENIX semaphores available", + 60: "device not a stream", + 75: "value too large for defined data type", + 117: "structure needs cleaning", + 123: "no medium found", + 16: "device or resource busy", + 71: "protocol error", + 19: "no such device", + 127: "key has expired", + 30: "read-only file system", + 79: "can not access a needed shared library", + 7: "argument list too long", + 35: "resource deadlock avoided", + 104: "connection reset by peer", + 6: "no such device or address", + 56: "invalid request code", + 36: "file name too long", + 94: "socket type not supported", + 73: "RFS specific error", + 99: "cannot assign requested address", + 62: "timer expired", + 93: "protocol not supported", + 131: "state not recoverable", + 5: "input/output error", + 101: "network is unreachable", + 18: "invalid cross-device link", + 122: "disk quota exceeded", + 121: "remote I/O error", + 28: "no space left on device", + 8: "exec format error", + 90: "message too long", + 33: "numerical argument out of domain", + 27: "file too large", + 3: "no such process", + 44: "channel number out of range", + 112: "host is down", + 37: "no locks available", + 23: "too many open files in system", + 38: "function not implemented", + 107: "transport endpoint is not connected", + 95: "operation not supported", + 69: "srmount error", + 103: "software caused connection abort", + 55: "no anode", + 106: "transport endpoint is already connected", + 87: "too many users", + 92: "protocol not available", + 24: "too many open files", + 105: "no buffer space available", + 46: "level 3 halted", + 14: "bad address", + 11: "resource temporarily unavailable", + 80: "accessing a corrupted shared library", + 86: "streams pipe error", + 111: "connection refused", + 82: "attempting to link in too many shared libraries", + 17: "file exists", + 45: "level 2 not synchronized", + 2: "no such file or directory", + 65: "package not installed", + 128: "key has been revoked", + 113: "no route to host", + 76: "name not unique on network", + 20: "not a directory", + 124: "wrong medium type", +} + diff --git a/src/pkg/syscall/zerrors_linux_amd64.go b/src/pkg/syscall/zerrors_linux_amd64.go new file mode 100644 index 000000000..f1e7e011d --- /dev/null +++ b/src/pkg/syscall/zerrors_linux_amd64.go @@ -0,0 +1,316 @@ +// mkerrors +// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT + +// godefs -gsyscall _errors.c + +// MACHINE GENERATED - DO NOT EDIT. + +package syscall + +// Constants +const ( + EMULTIHOP = 0x48; + EUNATCH = 0x31; + EAFNOSUPPORT = 0x61; + EREMCHG = 0x4e; + EACCES = 0xd; + EL3RST = 0x2f; + EDESTADDRREQ = 0x59; + EILSEQ = 0x54; + ESPIPE = 0x1d; + EMLINK = 0x1f; + EOWNERDEAD = 0x82; + ENOTTY = 0x19; + EBADE = 0x34; + EBADF = 0x9; + EBADR = 0x35; + EADV = 0x44; + ERANGE = 0x22; + ECANCELED = 0x7d; + ETXTBSY = 0x1a; + ENOMEM = 0xc; + EINPROGRESS = 0x73; + ENOTBLK = 0xf; + EPROTOTYPE = 0x5b; + ERESTART = 0x55; + EISNAM = 0x78; + ENOMSG = 0x2a; + EALREADY = 0x72; + ETIMEDOUT = 0x6e; + ENODATA = 0x3d; + EINTR = 0x4; + ENOLINK = 0x43; + EPERM = 0x1; + ELOOP = 0x28; + ENETDOWN = 0x64; + ESTALE = 0x74; + ENOTSOCK = 0x58; + ENOSR = 0x3f; + ECHILD = 0xa; + ELNRNG = 0x30; + EPIPE = 0x20; + EBADMSG = 0x4a; + EBFONT = 0x3b; + EREMOTE = 0x42; + ETOOMANYREFS = 0x6d; + EPFNOSUPPORT = 0x60; + ENONET = 0x40; + EXFULL = 0x36; + EBADSLT = 0x39; + ENOTNAM = 0x76; + ELIBEXEC = 0x53; + ENOCSI = 0x32; + ENOTEMPTY = 0x27; + EADDRINUSE = 0x62; + ENETRESET = 0x66; + EISDIR = 0x15; + EIDRM = 0x2b; + ECOMM = 0x46; + EBADFD = 0x4d; + EL2HLT = 0x33; + ENOKEY = 0x7e; + EINVAL = 0x16; + ESHUTDOWN = 0x6c; + EKEYREJECTED = 0x81; + ELIBSCN = 0x51; + ENAVAIL = 0x77; + ENOSTR = 0x3c; + EOVERFLOW = 0x4b; + EUCLEAN = 0x75; + ENOMEDIUM = 0x7b; + EBUSY = 0x10; + EPROTO = 0x47; + ENODEV = 0x13; + EKEYEXPIRED = 0x7f; + EROFS = 0x1e; + ELIBACC = 0x4f; + E2BIG = 0x7; + EDEADLK = 0x23; + ECONNRESET = 0x68; + ENXIO = 0x6; + EBADRQC = 0x38; + ENAMETOOLONG = 0x24; + ESOCKTNOSUPPORT = 0x5e; + EDOTDOT = 0x49; + EADDRNOTAVAIL = 0x63; + ETIME = 0x3e; + EPROTONOSUPPORT = 0x5d; + ENOTRECOVERABLE = 0x83; + EIO = 0x5; + ENETUNREACH = 0x65; + EXDEV = 0x12; + EDQUOT = 0x7a; + EREMOTEIO = 0x79; + ENOSPC = 0x1c; + ENOEXEC = 0x8; + EMSGSIZE = 0x5a; + EDOM = 0x21; + EFBIG = 0x1b; + ESRCH = 0x3; + ECHRNG = 0x2c; + EHOSTDOWN = 0x70; + ENOLCK = 0x25; + ENFILE = 0x17; + ENOSYS = 0x26; + ENOTCONN = 0x6b; + ENOTSUP = 0x5f; + ESRMNT = 0x45; + EDEADLOCK = 0x23; + ECONNABORTED = 0x67; + ENOANO = 0x37; + EISCONN = 0x6a; + EUSERS = 0x57; + ENOPROTOOPT = 0x5c; + EMFILE = 0x18; + ENOBUFS = 0x69; + EL3HLT = 0x2e; + EFAULT = 0xe; + EWOULDBLOCK = 0xb; + ELIBBAD = 0x50; + ESTRPIPE = 0x56; + ECONNREFUSED = 0x6f; + EAGAIN = 0xb; + ELIBMAX = 0x52; + EEXIST = 0x11; + EL2NSYNC = 0x2d; + ENOENT = 0x2; + ENOPKG = 0x41; + EKEYREVOKED = 0x80; + EHOSTUNREACH = 0x71; + ENOTUNIQ = 0x4c; + EOPNOTSUPP = 0x5f; + ENOTDIR = 0x14; + EMEDIUMTYPE = 0x7c; + SIGBUS = 0x7; + SIGTTIN = 0x15; + SIGPROF = 0x1b; + SIGFPE = 0x8; + SIGHUP = 0x1; + SIGTTOU = 0x16; + SIGSTKFLT = 0x10; + SIGUSR1 = 0xa; + SIGURG = 0x17; + SIGQUIT = 0x3; + SIGCLD = 0x11; + SIGIO = 0x1d; + SIGABRT = 0x6; + SIGUSR2 = 0xc; + SIGTRAP = 0x5; + SIGVTALRM = 0x1a; + SIGPOLL = 0x1d; + SIGSEGV = 0xb; + SIGCONT = 0x12; + SIGPIPE = 0xd; + SIGWINCH = 0x1c; + SIGXFSZ = 0x19; + SIGCHLD = 0x11; + SIGSYS = 0x1f; + SIGSTOP = 0x13; + SIGALRM = 0xe; + SIGTSTP = 0x14; + SIGKILL = 0x9; + SIGXCPU = 0x18; + SIGUNUSED = 0x1f; + SIGPWR = 0x1e; + SIGILL = 0x4; + SIGINT = 0x2; + SIGIOT = 0x6; + SIGTERM = 0xf; +) + +// Types + + +// Error table +var errors = [...]string { + 72: "multihop attempted", + 49: "protocol driver not attached", + 97: "address family not supported by protocol", + 78: "remote address changed", + 13: "permission denied", + 47: "level 3 reset", + 89: "destination address required", + 84: "invalid or incomplete multibyte or wide character", + 29: "illegal seek", + 31: "too many links", + 130: "owner died", + 25: "inappropriate ioctl for device", + 52: "invalid exchange", + 9: "bad file descriptor", + 53: "invalid request descriptor", + 68: "advertise error", + 34: "numerical result out of range", + 125: "operation canceled", + 26: "text file busy", + 12: "cannot allocate memory", + 115: "operation now in progress", + 15: "block device required", + 91: "protocol wrong type for socket", + 85: "interrupted system call should be restarted", + 120: "is a named type file", + 42: "no message of desired type", + 114: "operation already in progress", + 110: "connection timed out", + 61: "no data available", + 4: "interrupted system call", + 67: "link has been severed", + 1: "operation not permitted", + 40: "too many levels of symbolic links", + 100: "network is down", + 116: "stale NFS file handle", + 88: "socket operation on non-socket", + 63: "out of streams resources", + 10: "no child processes", + 48: "link number out of range", + 32: "broken pipe", + 74: "bad message", + 59: "bad font file format", + 66: "object is remote", + 109: "too many references: cannot splice", + 96: "protocol family not supported", + 64: "machine is not on the network", + 54: "exchange full", + 57: "invalid slot", + 118: "not a XENIX named type file", + 83: "cannot exec a shared library directly", + 50: "no CSI structure available", + 39: "directory not empty", + 98: "address already in use", + 102: "network dropped connection on reset", + 21: "is a directory", + 43: "identifier removed", + 70: "communication error on send", + 77: "file descriptor in bad state", + 51: "level 2 halted", + 126: "required key not available", + 22: "invalid argument", + 108: "cannot send after transport endpoint shutdown", + 129: "key was rejected by service", + 81: ".lib section in a.out corrupted", + 119: "no XENIX semaphores available", + 60: "device not a stream", + 75: "value too large for defined data type", + 117: "structure needs cleaning", + 123: "no medium found", + 16: "device or resource busy", + 71: "protocol error", + 19: "no such device", + 127: "key has expired", + 30: "read-only file system", + 79: "can not access a needed shared library", + 7: "argument list too long", + 35: "resource deadlock avoided", + 104: "connection reset by peer", + 6: "no such device or address", + 56: "invalid request code", + 36: "file name too long", + 94: "socket type not supported", + 73: "RFS specific error", + 99: "cannot assign requested address", + 62: "timer expired", + 93: "protocol not supported", + 131: "state not recoverable", + 5: "input/output error", + 101: "network is unreachable", + 18: "invalid cross-device link", + 122: "disk quota exceeded", + 121: "remote I/O error", + 28: "no space left on device", + 8: "exec format error", + 90: "message too long", + 33: "numerical argument out of domain", + 27: "file too large", + 3: "no such process", + 44: "channel number out of range", + 112: "host is down", + 37: "no locks available", + 23: "too many open files in system", + 38: "function not implemented", + 107: "transport endpoint is not connected", + 95: "operation not supported", + 69: "srmount error", + 103: "software caused connection abort", + 55: "no anode", + 106: "transport endpoint is already connected", + 87: "too many users", + 92: "protocol not available", + 24: "too many open files", + 105: "no buffer space available", + 46: "level 3 halted", + 14: "bad address", + 11: "resource temporarily unavailable", + 80: "accessing a corrupted shared library", + 86: "streams pipe error", + 111: "connection refused", + 82: "attempting to link in too many shared libraries", + 17: "file exists", + 45: "level 2 not synchronized", + 2: "no such file or directory", + 65: "package not installed", + 128: "key has been revoked", + 113: "no route to host", + 76: "name not unique on network", + 20: "not a directory", + 124: "wrong medium type", +} + diff --git a/src/pkg/syscall/zsyscall_darwin_386.go b/src/pkg/syscall/zsyscall_darwin_386.go new file mode 100644 index 000000000..61f7c01db --- /dev/null +++ b/src/pkg/syscall/zsyscall_darwin_386.go @@ -0,0 +1,624 @@ +// mksyscall -l32 syscall_darwin.go syscall_darwin_386.go +// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT + +package syscall + +import ( + "syscall"; + "unsafe"; +) + +func getgroups(ngid int, gid *_Gid_t) (n int, errno int) { + r0, r1, e1 := Syscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0); + n = int(r0); + errno = int(e1); + return; +} + +func setgroups(ngid int, gid *_Gid_t) (errno int) { + r0, r1, e1 := Syscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0); + errno = int(e1); + return; +} + +func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, errno int) { + r0, r1, 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; +} + +func pipe() (r int, w int, errno int) { + r0, r1, e1 := Syscall(SYS_PIPE, 0, 0, 0); + r = int(r0); + w = int(r1); + errno = int(e1); + return; +} + +func lseek(fd int, offset int64, whence int) (newoffset uintptr, errno int) { + r0, r1, e1 := Syscall6(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(offset >> 32), uintptr(whence), 0, 0); + newoffset = uintptr(r0); + errno = int(e1); + return; +} + +func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, errno int) { + r0, r1, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))); + fd = int(r0); + errno = int(e1); + return; +} + +func bind(s int, addr uintptr, addrlen _Socklen) (errno int) { + r0, r1, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen)); + errno = int(e1); + return; +} + +func connect(s int, addr uintptr, addrlen _Socklen) (errno int) { + r0, r1, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen)); + errno = int(e1); + return; +} + +func socket(domain int, typ int, proto int) (fd int, errno int) { + r0, r1, e1 := Syscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto)); + fd = int(r0); + errno = int(e1); + return; +} + +func setsockopt(s int, level int, name int, val uintptr, vallen int) (errno int) { + r0, r1, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0); + errno = int(e1); + return; +} + +func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, errno int) { + r0, r1, 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; +} + +func fcntl(fd int, cmd int, arg int) (val int, errno int) { + r0, r1, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg)); + val = int(r0); + errno = int(e1); + return; +} + +func Access(path string, flags int) (errno int) { + r0, r1, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0); + errno = int(e1); + return; +} + +func Adjtime(delta *Timeval, olddelta *Timeval) (errno int) { + r0, r1, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0); + errno = int(e1); + return; +} + +func Chdir(path string) (errno int) { + r0, r1, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); + errno = int(e1); + return; +} + +func Chflags(path string, flags int) (errno int) { + r0, r1, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0); + errno = int(e1); + return; +} + +func Chmod(path string, mode int) (errno int) { + r0, r1, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0); + errno = int(e1); + return; +} + +func Chown(path string, uid int, gid int) (errno int) { + r0, r1, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid)); + errno = int(e1); + return; +} + +func Chroot(path string) (errno int) { + r0, r1, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); + errno = int(e1); + return; +} + +func Close(fd int) (errno int) { + r0, r1, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0); + errno = int(e1); + return; +} + +func Dup(fd int) (nfd int, errno int) { + r0, r1, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0); + nfd = int(r0); + errno = int(e1); + return; +} + +func Dup2(from int, to int) (errno int) { + r0, r1, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0); + errno = int(e1); + return; +} + +func Exchangedata(path1 string, path2 string, options int) (errno int) { + r0, r1, e1 := Syscall(SYS_EXCHANGEDATA, uintptr(unsafe.Pointer(StringBytePtr(path1))), uintptr(unsafe.Pointer(StringBytePtr(path2))), uintptr(options)); + errno = int(e1); + return; +} + +func Exit(code int) () { + r0, r1, e1 := Syscall(SYS_EXIT, uintptr(code), 0, 0); + return; +} + +func Fchdir(fd int) (errno int) { + r0, r1, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0); + errno = int(e1); + return; +} + +func Fchflags(path string, flags int) (errno int) { + r0, r1, e1 := Syscall(SYS_FCHFLAGS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0); + errno = int(e1); + return; +} + +func Fchmod(fd int, mode int) (errno int) { + r0, r1, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0); + errno = int(e1); + return; +} + +func Fchown(fd int, uid int, gid int) (errno int) { + r0, r1, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid)); + errno = int(e1); + return; +} + +func Flock(fd int, how int) (errno int) { + r0, r1, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0); + errno = int(e1); + return; +} + +func Fpathconf(fd int, name int) (val int, errno int) { + r0, r1, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0); + val = int(r0); + errno = int(e1); + return; +} + +func Fstat(fd int, stat *Stat_t) (errno int) { + r0, r1, e1 := Syscall(SYS_FSTAT64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0); + errno = int(e1); + return; +} + +func Fstatfs(fd int, stat *Statfs_t) (errno int) { + r0, r1, e1 := Syscall(SYS_FSTATFS64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0); + errno = int(e1); + return; +} + +func Fsync(fd int) (errno int) { + r0, r1, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0); + errno = int(e1); + return; +} + +func Ftruncate(fd int, length int64) (errno int) { + r0, r1, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), uintptr(length >> 32)); + errno = int(e1); + return; +} + +func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, errno int) { + var _p0 *byte; + if len(buf) > 0 { _p0 = &buf[0]; } + r0, r1, e1 := Syscall6(SYS_GETDIRENTRIES64, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0); + n = int(r0); + errno = int(e1); + return; +} + +func Getdtablesize() (size int) { + r0, r1, e1 := Syscall(SYS_GETDTABLESIZE, 0, 0, 0); + size = int(r0); + return; +} + +func Getegid() (egid int) { + r0, r1, e1 := Syscall(SYS_GETEGID, 0, 0, 0); + egid = int(r0); + return; +} + +func Geteuid() (uid int) { + r0, r1, e1 := Syscall(SYS_GETEUID, 0, 0, 0); + uid = int(r0); + return; +} + +func Getfsstat(buf []Statfs_t, flags int) (n int, errno int) { + var _p0 *Statfs_t; + if len(buf) > 0 { _p0 = &buf[0]; } + r0, r1, e1 := Syscall(SYS_GETFSSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(flags)); + n = int(r0); + errno = int(e1); + return; +} + +func Getgid() (gid int) { + r0, r1, e1 := Syscall(SYS_GETGID, 0, 0, 0); + gid = int(r0); + return; +} + +func Getpgid(pid int) (pgid int, errno int) { + r0, r1, e1 := Syscall(SYS_GETPGID, uintptr(pid), 0, 0); + pgid = int(r0); + errno = int(e1); + return; +} + +func Getpgrp() (pgrp int) { + r0, r1, e1 := Syscall(SYS_GETPGRP, 0, 0, 0); + pgrp = int(r0); + return; +} + +func Getpid() (pid int) { + r0, r1, e1 := Syscall(SYS_GETPID, 0, 0, 0); + pid = int(r0); + return; +} + +func Getppid() (ppid int) { + r0, r1, e1 := Syscall(SYS_GETPPID, 0, 0, 0); + ppid = int(r0); + return; +} + +func Getpriority(which int, who int) (prio int, errno int) { + r0, r1, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0); + prio = int(r0); + errno = int(e1); + return; +} + +func Getrlimit(which int, lim *Rlimit) (errno int) { + r0, r1, e1 := Syscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0); + errno = int(e1); + return; +} + +func Getrusage(who int, rusage *Rusage) (errno int) { + r0, r1, e1 := Syscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0); + errno = int(e1); + return; +} + +func Getsid(pid int) (sid int, errno int) { + r0, r1, e1 := Syscall(SYS_GETSID, uintptr(pid), 0, 0); + sid = int(r0); + errno = int(e1); + return; +} + +func Getuid() (uid int) { + r0, r1, e1 := Syscall(SYS_GETUID, 0, 0, 0); + uid = int(r0); + return; +} + +func Issetugid() (tainted bool) { + r0, r1, e1 := Syscall(SYS_ISSETUGID, 0, 0, 0); + tainted = bool(r0 != 0); + return; +} + +func Kill(pid int, signum int, posix int) (errno int) { + r0, r1, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), uintptr(posix)); + errno = int(e1); + return; +} + +func Kqueue() (fd int, errno int) { + r0, r1, e1 := Syscall(SYS_KQUEUE, 0, 0, 0); + fd = int(r0); + errno = int(e1); + return; +} + +func Lchown(path string, uid int, gid int) (errno int) { + r0, r1, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid)); + errno = int(e1); + return; +} + +func Link(path string, link string) (errno int) { + r0, r1, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(StringBytePtr(link))), 0); + errno = int(e1); + return; +} + +func Listen(s int, backlog int) (errno int) { + r0, r1, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0); + errno = int(e1); + return; +} + +func Lstat(path string, stat *Stat_t) (errno int) { + r0, r1, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0); + errno = int(e1); + return; +} + +func Mkdir(path string, mode int) (errno int) { + r0, r1, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0); + errno = int(e1); + return; +} + +func Mkfifo(path string, mode int) (errno int) { + r0, r1, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0); + errno = int(e1); + return; +} + +func Mknod(path string, mode int, dev int) (errno int) { + r0, r1, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(dev)); + errno = int(e1); + return; +} + +func Open(path string, mode int, perm int) (fd int, errno int) { + r0, r1, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(perm)); + fd = int(r0); + errno = int(e1); + return; +} + +func Pathconf(path string, name int) (val int, errno int) { + r0, r1, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(name), 0); + val = int(r0); + errno = int(e1); + return; +} + +func Pread(fd int, p []byte, offset int64) (n int, errno int) { + var _p0 *byte; + if len(p) > 0 { _p0 = &p[0]; } + r0, r1, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), uintptr(offset >> 32), 0); + n = int(r0); + errno = int(e1); + return; +} + +func Pwrite(fd int, p []byte, offset int64) (n int, errno int) { + var _p0 *byte; + if len(p) > 0 { _p0 = &p[0]; } + r0, r1, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), uintptr(offset >> 32), 0); + n = int(r0); + errno = int(e1); + return; +} + +func Read(fd int, p []byte) (n int, errno int) { + var _p0 *byte; + if len(p) > 0 { _p0 = &p[0]; } + r0, r1, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p))); + n = int(r0); + errno = int(e1); + return; +} + +func Readlink(path string, buf []byte) (n int, errno int) { + var _p0 *byte; + if len(buf) > 0 { _p0 = &buf[0]; } + r0, r1, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf))); + n = int(r0); + errno = int(e1); + return; +} + +func Rename(from string, to string) (errno int) { + r0, r1, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(StringBytePtr(from))), uintptr(unsafe.Pointer(StringBytePtr(to))), 0); + errno = int(e1); + return; +} + +func Revoke(path string) (errno int) { + r0, r1, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); + errno = int(e1); + return; +} + +func Rmdir(path string) (errno int) { + r0, r1, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); + errno = int(e1); + return; +} + +func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (errno int) { + r0, r1, 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; +} + +func Setegid(egid int) (errno int) { + r0, r1, e1 := Syscall(SYS_SETEGID, uintptr(egid), 0, 0); + errno = int(e1); + return; +} + +func Seteuid(euid int) (errno int) { + r0, r1, e1 := Syscall(SYS_SETEUID, uintptr(euid), 0, 0); + errno = int(e1); + return; +} + +func Setgid(gid int) (errno int) { + r0, r1, e1 := Syscall(SYS_SETGID, uintptr(gid), 0, 0); + errno = int(e1); + return; +} + +func Setlogin(name string) (errno int) { + r0, r1, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(StringBytePtr(name))), 0, 0); + errno = int(e1); + return; +} + +func Setpgid(pid int, pgid int) (errno int) { + r0, r1, e1 := Syscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0); + errno = int(e1); + return; +} + +func Setpriority(which int, who int, prio int) (errno int) { + r0, r1, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio)); + errno = int(e1); + return; +} + +func Setprivexec(flag int) (errno int) { + r0, r1, e1 := Syscall(SYS_SETPRIVEXEC, uintptr(flag), 0, 0); + errno = int(e1); + return; +} + +func Setregid(rgid int, egid int) (errno int) { + r0, r1, e1 := Syscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0); + errno = int(e1); + return; +} + +func Setreuid(ruid int, euid int) (errno int) { + r0, r1, e1 := Syscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0); + errno = int(e1); + return; +} + +func Setrlimit(which int, lim *Rlimit) (errno int) { + r0, r1, e1 := Syscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0); + errno = int(e1); + return; +} + +func Setsid() (pid int, errno int) { + r0, r1, e1 := Syscall(SYS_SETSID, 0, 0, 0); + pid = int(r0); + errno = int(e1); + return; +} + +func Settimeofday(tp *Timeval) (errno int) { + r0, r1, e1 := Syscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0); + errno = int(e1); + return; +} + +func Setuid(uid int) (errno int) { + r0, r1, e1 := Syscall(SYS_SETUID, uintptr(uid), 0, 0); + errno = int(e1); + return; +} + +func Stat(path string, stat *Stat_t) (errno int) { + r0, r1, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0); + errno = int(e1); + return; +} + +func Statfs(path string, stat *Statfs_t) (errno int) { + r0, r1, e1 := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0); + errno = int(e1); + return; +} + +func Symlink(path string, link string) (errno int) { + r0, r1, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(StringBytePtr(link))), 0); + errno = int(e1); + return; +} + +func Sync() (errno int) { + r0, r1, e1 := Syscall(SYS_SYNC, 0, 0, 0); + errno = int(e1); + return; +} + +func Truncate(path string, length int64) (errno int) { + r0, r1, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(length), uintptr(length >> 32)); + errno = int(e1); + return; +} + +func Umask(newmask int) (errno int) { + r0, r1, e1 := Syscall(SYS_UMASK, uintptr(newmask), 0, 0); + errno = int(e1); + return; +} + +func Undelete(path string) (errno int) { + r0, r1, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); + errno = int(e1); + return; +} + +func Unlink(path string) (errno int) { + r0, r1, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); + errno = int(e1); + return; +} + +func Unmount(path string, flags int) (errno int) { + r0, r1, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0); + errno = int(e1); + return; +} + +func Write(fd int, p []byte) (n int, errno int) { + var _p0 *byte; + if len(p) > 0 { _p0 = &p[0]; } + r0, r1, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p))); + n = int(r0); + errno = int(e1); + return; +} + +func read(fd int, buf *byte, nbuf int) (n int, errno int) { + r0, r1, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)); + n = int(r0); + errno = int(e1); + return; +} + +func write(fd int, buf *byte, nbuf int) (n int, errno int) { + r0, r1, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)); + n = int(r0); + errno = int(e1); + return; +} + +func gettimeofday(tp *Timeval) (sec int64, usec int32, errno int) { + r0, r1, e1 := Syscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0); + sec = int64(r0); + 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..c8a0b10a7 --- /dev/null +++ b/src/pkg/syscall/zsyscall_darwin_amd64.go @@ -0,0 +1,624 @@ +// mksyscall syscall_darwin.go syscall_darwin_amd64.go +// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT + +package syscall + +import ( + "syscall"; + "unsafe"; +) + +func getgroups(ngid int, gid *_Gid_t) (n int, errno int) { + r0, r1, e1 := Syscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0); + n = int(r0); + errno = int(e1); + return; +} + +func setgroups(ngid int, gid *_Gid_t) (errno int) { + r0, r1, e1 := Syscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0); + errno = int(e1); + return; +} + +func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, errno int) { + r0, r1, 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; +} + +func pipe() (r int, w int, errno int) { + r0, r1, e1 := Syscall(SYS_PIPE, 0, 0, 0); + r = int(r0); + w = int(r1); + errno = int(e1); + return; +} + +func lseek(fd int, offset int64, whence int) (newoffset uintptr, errno int) { + r0, r1, e1 := Syscall(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence)); + newoffset = uintptr(r0); + errno = int(e1); + return; +} + +func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, errno int) { + r0, r1, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))); + fd = int(r0); + errno = int(e1); + return; +} + +func bind(s int, addr uintptr, addrlen _Socklen) (errno int) { + r0, r1, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen)); + errno = int(e1); + return; +} + +func connect(s int, addr uintptr, addrlen _Socklen) (errno int) { + r0, r1, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen)); + errno = int(e1); + return; +} + +func socket(domain int, typ int, proto int) (fd int, errno int) { + r0, r1, e1 := Syscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto)); + fd = int(r0); + errno = int(e1); + return; +} + +func setsockopt(s int, level int, name int, val uintptr, vallen int) (errno int) { + r0, r1, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0); + errno = int(e1); + return; +} + +func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, errno int) { + r0, r1, 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; +} + +func fcntl(fd int, cmd int, arg int) (val int, errno int) { + r0, r1, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg)); + val = int(r0); + errno = int(e1); + return; +} + +func Access(path string, flags int) (errno int) { + r0, r1, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0); + errno = int(e1); + return; +} + +func Adjtime(delta *Timeval, olddelta *Timeval) (errno int) { + r0, r1, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0); + errno = int(e1); + return; +} + +func Chdir(path string) (errno int) { + r0, r1, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); + errno = int(e1); + return; +} + +func Chflags(path string, flags int) (errno int) { + r0, r1, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0); + errno = int(e1); + return; +} + +func Chmod(path string, mode int) (errno int) { + r0, r1, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0); + errno = int(e1); + return; +} + +func Chown(path string, uid int, gid int) (errno int) { + r0, r1, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid)); + errno = int(e1); + return; +} + +func Chroot(path string) (errno int) { + r0, r1, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); + errno = int(e1); + return; +} + +func Close(fd int) (errno int) { + r0, r1, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0); + errno = int(e1); + return; +} + +func Dup(fd int) (nfd int, errno int) { + r0, r1, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0); + nfd = int(r0); + errno = int(e1); + return; +} + +func Dup2(from int, to int) (errno int) { + r0, r1, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0); + errno = int(e1); + return; +} + +func Exchangedata(path1 string, path2 string, options int) (errno int) { + r0, r1, e1 := Syscall(SYS_EXCHANGEDATA, uintptr(unsafe.Pointer(StringBytePtr(path1))), uintptr(unsafe.Pointer(StringBytePtr(path2))), uintptr(options)); + errno = int(e1); + return; +} + +func Exit(code int) () { + r0, r1, e1 := Syscall(SYS_EXIT, uintptr(code), 0, 0); + return; +} + +func Fchdir(fd int) (errno int) { + r0, r1, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0); + errno = int(e1); + return; +} + +func Fchflags(path string, flags int) (errno int) { + r0, r1, e1 := Syscall(SYS_FCHFLAGS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0); + errno = int(e1); + return; +} + +func Fchmod(fd int, mode int) (errno int) { + r0, r1, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0); + errno = int(e1); + return; +} + +func Fchown(fd int, uid int, gid int) (errno int) { + r0, r1, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid)); + errno = int(e1); + return; +} + +func Flock(fd int, how int) (errno int) { + r0, r1, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0); + errno = int(e1); + return; +} + +func Fpathconf(fd int, name int) (val int, errno int) { + r0, r1, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0); + val = int(r0); + errno = int(e1); + return; +} + +func Fstat(fd int, stat *Stat_t) (errno int) { + r0, r1, e1 := Syscall(SYS_FSTAT64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0); + errno = int(e1); + return; +} + +func Fstatfs(fd int, stat *Statfs_t) (errno int) { + r0, r1, e1 := Syscall(SYS_FSTATFS64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0); + errno = int(e1); + return; +} + +func Fsync(fd int) (errno int) { + r0, r1, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0); + errno = int(e1); + return; +} + +func Ftruncate(fd int, length int64) (errno int) { + r0, r1, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), 0); + errno = int(e1); + return; +} + +func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, errno int) { + var _p0 *byte; + if len(buf) > 0 { _p0 = &buf[0]; } + r0, r1, e1 := Syscall6(SYS_GETDIRENTRIES64, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0); + n = int(r0); + errno = int(e1); + return; +} + +func Getdtablesize() (size int) { + r0, r1, e1 := Syscall(SYS_GETDTABLESIZE, 0, 0, 0); + size = int(r0); + return; +} + +func Getegid() (egid int) { + r0, r1, e1 := Syscall(SYS_GETEGID, 0, 0, 0); + egid = int(r0); + return; +} + +func Geteuid() (uid int) { + r0, r1, e1 := Syscall(SYS_GETEUID, 0, 0, 0); + uid = int(r0); + return; +} + +func Getfsstat(buf []Statfs_t, flags int) (n int, errno int) { + var _p0 *Statfs_t; + if len(buf) > 0 { _p0 = &buf[0]; } + r0, r1, e1 := Syscall(SYS_GETFSSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(flags)); + n = int(r0); + errno = int(e1); + return; +} + +func Getgid() (gid int) { + r0, r1, e1 := Syscall(SYS_GETGID, 0, 0, 0); + gid = int(r0); + return; +} + +func Getpgid(pid int) (pgid int, errno int) { + r0, r1, e1 := Syscall(SYS_GETPGID, uintptr(pid), 0, 0); + pgid = int(r0); + errno = int(e1); + return; +} + +func Getpgrp() (pgrp int) { + r0, r1, e1 := Syscall(SYS_GETPGRP, 0, 0, 0); + pgrp = int(r0); + return; +} + +func Getpid() (pid int) { + r0, r1, e1 := Syscall(SYS_GETPID, 0, 0, 0); + pid = int(r0); + return; +} + +func Getppid() (ppid int) { + r0, r1, e1 := Syscall(SYS_GETPPID, 0, 0, 0); + ppid = int(r0); + return; +} + +func Getpriority(which int, who int) (prio int, errno int) { + r0, r1, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0); + prio = int(r0); + errno = int(e1); + return; +} + +func Getrlimit(which int, lim *Rlimit) (errno int) { + r0, r1, e1 := Syscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0); + errno = int(e1); + return; +} + +func Getrusage(who int, rusage *Rusage) (errno int) { + r0, r1, e1 := Syscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0); + errno = int(e1); + return; +} + +func Getsid(pid int) (sid int, errno int) { + r0, r1, e1 := Syscall(SYS_GETSID, uintptr(pid), 0, 0); + sid = int(r0); + errno = int(e1); + return; +} + +func Getuid() (uid int) { + r0, r1, e1 := Syscall(SYS_GETUID, 0, 0, 0); + uid = int(r0); + return; +} + +func Issetugid() (tainted bool) { + r0, r1, e1 := Syscall(SYS_ISSETUGID, 0, 0, 0); + tainted = bool(r0 != 0); + return; +} + +func Kill(pid int, signum int, posix int) (errno int) { + r0, r1, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), uintptr(posix)); + errno = int(e1); + return; +} + +func Kqueue() (fd int, errno int) { + r0, r1, e1 := Syscall(SYS_KQUEUE, 0, 0, 0); + fd = int(r0); + errno = int(e1); + return; +} + +func Lchown(path string, uid int, gid int) (errno int) { + r0, r1, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid)); + errno = int(e1); + return; +} + +func Link(path string, link string) (errno int) { + r0, r1, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(StringBytePtr(link))), 0); + errno = int(e1); + return; +} + +func Listen(s int, backlog int) (errno int) { + r0, r1, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0); + errno = int(e1); + return; +} + +func Lstat(path string, stat *Stat_t) (errno int) { + r0, r1, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0); + errno = int(e1); + return; +} + +func Mkdir(path string, mode int) (errno int) { + r0, r1, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0); + errno = int(e1); + return; +} + +func Mkfifo(path string, mode int) (errno int) { + r0, r1, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0); + errno = int(e1); + return; +} + +func Mknod(path string, mode int, dev int) (errno int) { + r0, r1, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(dev)); + errno = int(e1); + return; +} + +func Open(path string, mode int, perm int) (fd int, errno int) { + r0, r1, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(perm)); + fd = int(r0); + errno = int(e1); + return; +} + +func Pathconf(path string, name int) (val int, errno int) { + r0, r1, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(name), 0); + val = int(r0); + errno = int(e1); + return; +} + +func Pread(fd int, p []byte, offset int64) (n int, errno int) { + var _p0 *byte; + if len(p) > 0 { _p0 = &p[0]; } + r0, r1, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), 0, 0); + n = int(r0); + errno = int(e1); + return; +} + +func Pwrite(fd int, p []byte, offset int64) (n int, errno int) { + var _p0 *byte; + if len(p) > 0 { _p0 = &p[0]; } + r0, r1, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), 0, 0); + n = int(r0); + errno = int(e1); + return; +} + +func Read(fd int, p []byte) (n int, errno int) { + var _p0 *byte; + if len(p) > 0 { _p0 = &p[0]; } + r0, r1, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p))); + n = int(r0); + errno = int(e1); + return; +} + +func Readlink(path string, buf []byte) (n int, errno int) { + var _p0 *byte; + if len(buf) > 0 { _p0 = &buf[0]; } + r0, r1, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf))); + n = int(r0); + errno = int(e1); + return; +} + +func Rename(from string, to string) (errno int) { + r0, r1, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(StringBytePtr(from))), uintptr(unsafe.Pointer(StringBytePtr(to))), 0); + errno = int(e1); + return; +} + +func Revoke(path string) (errno int) { + r0, r1, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); + errno = int(e1); + return; +} + +func Rmdir(path string) (errno int) { + r0, r1, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); + errno = int(e1); + return; +} + +func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (errno int) { + r0, r1, 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; +} + +func Setegid(egid int) (errno int) { + r0, r1, e1 := Syscall(SYS_SETEGID, uintptr(egid), 0, 0); + errno = int(e1); + return; +} + +func Seteuid(euid int) (errno int) { + r0, r1, e1 := Syscall(SYS_SETEUID, uintptr(euid), 0, 0); + errno = int(e1); + return; +} + +func Setgid(gid int) (errno int) { + r0, r1, e1 := Syscall(SYS_SETGID, uintptr(gid), 0, 0); + errno = int(e1); + return; +} + +func Setlogin(name string) (errno int) { + r0, r1, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(StringBytePtr(name))), 0, 0); + errno = int(e1); + return; +} + +func Setpgid(pid int, pgid int) (errno int) { + r0, r1, e1 := Syscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0); + errno = int(e1); + return; +} + +func Setpriority(which int, who int, prio int) (errno int) { + r0, r1, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio)); + errno = int(e1); + return; +} + +func Setprivexec(flag int) (errno int) { + r0, r1, e1 := Syscall(SYS_SETPRIVEXEC, uintptr(flag), 0, 0); + errno = int(e1); + return; +} + +func Setregid(rgid int, egid int) (errno int) { + r0, r1, e1 := Syscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0); + errno = int(e1); + return; +} + +func Setreuid(ruid int, euid int) (errno int) { + r0, r1, e1 := Syscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0); + errno = int(e1); + return; +} + +func Setrlimit(which int, lim *Rlimit) (errno int) { + r0, r1, e1 := Syscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0); + errno = int(e1); + return; +} + +func Setsid() (pid int, errno int) { + r0, r1, e1 := Syscall(SYS_SETSID, 0, 0, 0); + pid = int(r0); + errno = int(e1); + return; +} + +func Settimeofday(tp *Timeval) (errno int) { + r0, r1, e1 := Syscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0); + errno = int(e1); + return; +} + +func Setuid(uid int) (errno int) { + r0, r1, e1 := Syscall(SYS_SETUID, uintptr(uid), 0, 0); + errno = int(e1); + return; +} + +func Stat(path string, stat *Stat_t) (errno int) { + r0, r1, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0); + errno = int(e1); + return; +} + +func Statfs(path string, stat *Statfs_t) (errno int) { + r0, r1, e1 := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0); + errno = int(e1); + return; +} + +func Symlink(path string, link string) (errno int) { + r0, r1, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(StringBytePtr(link))), 0); + errno = int(e1); + return; +} + +func Sync() (errno int) { + r0, r1, e1 := Syscall(SYS_SYNC, 0, 0, 0); + errno = int(e1); + return; +} + +func Truncate(path string, length int64) (errno int) { + r0, r1, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(length), 0); + errno = int(e1); + return; +} + +func Umask(newmask int) (errno int) { + r0, r1, e1 := Syscall(SYS_UMASK, uintptr(newmask), 0, 0); + errno = int(e1); + return; +} + +func Undelete(path string) (errno int) { + r0, r1, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); + errno = int(e1); + return; +} + +func Unlink(path string) (errno int) { + r0, r1, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); + errno = int(e1); + return; +} + +func Unmount(path string, flags int) (errno int) { + r0, r1, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0); + errno = int(e1); + return; +} + +func Write(fd int, p []byte) (n int, errno int) { + var _p0 *byte; + if len(p) > 0 { _p0 = &p[0]; } + r0, r1, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p))); + n = int(r0); + errno = int(e1); + return; +} + +func read(fd int, buf *byte, nbuf int) (n int, errno int) { + r0, r1, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)); + n = int(r0); + errno = int(e1); + return; +} + +func write(fd int, buf *byte, nbuf int) (n int, errno int) { + r0, r1, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)); + n = int(r0); + errno = int(e1); + return; +} + +func gettimeofday(tp *Timeval) (sec int64, usec int32, errno int) { + r0, r1, e1 := Syscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0); + sec = int64(r0); + usec = int32(r1); + 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..ef323b088 --- /dev/null +++ b/src/pkg/syscall/zsyscall_linux_386.go @@ -0,0 +1,720 @@ +// mksyscall syscall_linux.go syscall_linux_386.go +// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT + +package syscall + +import ( + "syscall"; + "unsafe"; +) + +func pipe(p *[2]_C_int) (errno int) { + r0, r1, e1 := Syscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0); + errno = int(e1); + return; +} + +func utimes(path string, times *[2]Timeval) (errno int) { + r0, r1, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(times)), 0); + errno = int(e1); + return; +} + +func futimesat(dirfd int, path string, times *[2]Timeval) (errno int) { + r0, r1, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(times))); + errno = int(e1); + return; +} + +func Getcwd(buf []byte) (n int, errno int) { + var _p0 *byte; + if len(buf) > 0 { _p0 = &buf[0]; } + r0, r1, e1 := Syscall(SYS_GETCWD, uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), 0); + n = int(r0); + errno = int(e1); + return; +} + +func getgroups(n int, list *_Gid_t) (nn int, errno int) { + r0, r1, e1 := Syscall(SYS_GETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0); + nn = int(r0); + errno = int(e1); + return; +} + +func setgroups(n int, list *_Gid_t) (errno int) { + r0, r1, e1 := Syscall(SYS_SETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0); + errno = int(e1); + return; +} + +func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, errno int) { + r0, r1, 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; +} + +func Access(path string, mode int) (errno int) { + r0, r1, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0); + errno = int(e1); + return; +} + +func Acct(path string) (errno int) { + r0, r1, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); + errno = int(e1); + return; +} + +func Adjtimex(buf *Timex) (state int, errno int) { + r0, r1, e1 := Syscall(SYS_ADJTIMEX, uintptr(unsafe.Pointer(buf)), 0, 0); + state = int(r0); + errno = int(e1); + return; +} + +func Chdir(path string) (errno int) { + r0, r1, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); + errno = int(e1); + return; +} + +func Chmod(path string, mode int) (errno int) { + r0, r1, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0); + errno = int(e1); + return; +} + +func Chown(path string, uid int, gid int) (errno int) { + r0, r1, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid)); + errno = int(e1); + return; +} + +func Chroot(path string) (errno int) { + r0, r1, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); + errno = int(e1); + return; +} + +func Close(fd int) (errno int) { + r0, r1, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0); + errno = int(e1); + return; +} + +func Creat(path string, mode int) (fd int, errno int) { + r0, r1, e1 := Syscall(SYS_CREAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0); + fd = int(r0); + errno = int(e1); + return; +} + +func Dup(oldfd int) (fd int, errno int) { + r0, r1, e1 := Syscall(SYS_DUP, uintptr(oldfd), 0, 0); + fd = int(r0); + errno = int(e1); + return; +} + +func Dup2(oldfd int, newfd int) (fd int, errno int) { + r0, r1, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0); + fd = int(r0); + errno = int(e1); + return; +} + +func EpollCreate(size int) (fd int, errno int) { + r0, r1, e1 := Syscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0); + fd = int(r0); + errno = int(e1); + return; +} + +func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (errno int) { + r0, r1, e1 := Syscall6(SYS_EPOLL_CTL, uintptr(epfd), uintptr(op), uintptr(fd), uintptr(unsafe.Pointer(event)), 0, 0); + errno = int(e1); + return; +} + +func EpollWait(epfd int, events []EpollEvent, msec int) (n int, errno int) { + var _p0 *EpollEvent; + if len(events) > 0 { _p0 = &events[0]; } + r0, r1, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(unsafe.Pointer(_p0)), uintptr(len(events)), uintptr(msec), 0, 0); + n = int(r0); + errno = int(e1); + return; +} + +func Exit(code int) () { + r0, r1, e1 := Syscall(SYS_EXIT_GROUP, uintptr(code), 0, 0); + return; +} + +func Faccessat(dirfd int, path string, mode int, flags int) (errno int) { + r0, r1, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(flags), 0, 0); + errno = int(e1); + return; +} + +func Fallocate(fd int, mode int, off int64, len int64) (errno int) { + r0, r1, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(off >> 32), uintptr(len), uintptr(len >> 32)); + errno = int(e1); + return; +} + +func Fchdir(fd int) (errno int) { + r0, r1, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0); + errno = int(e1); + return; +} + +func Fchmod(fd int, mode int) (errno int) { + r0, r1, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0); + errno = int(e1); + return; +} + +func Fchmodat(dirfd int, path string, mode int, flags int) (errno int) { + r0, r1, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(flags), 0, 0); + errno = int(e1); + return; +} + +func Fchown(fd int, uid int, gid int) (errno int) { + r0, r1, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid)); + errno = int(e1); + return; +} + +func Fchownat(dirfd int, path string, uid int, gid int, flags int) (errno int) { + r0, r1, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid), uintptr(flags), 0); + errno = int(e1); + return; +} + +func fcntl(fd int, cmd int, arg int) (val int, errno int) { + r0, r1, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg)); + val = int(r0); + errno = int(e1); + return; +} + +func Fdatasync(fd int) (errno int) { + r0, r1, e1 := Syscall(SYS_FDATASYNC, uintptr(fd), 0, 0); + errno = int(e1); + return; +} + +func Fstat(fd int, stat *Stat_t) (errno int) { + r0, r1, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0); + errno = int(e1); + return; +} + +func Fstatfs(fd int, buf *Statfs_t) (errno int) { + r0, r1, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(buf)), 0); + errno = int(e1); + return; +} + +func Fsync(fd int) (errno int) { + r0, r1, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0); + errno = int(e1); + return; +} + +func Ftruncate(fd int, length int64) (errno int) { + r0, r1, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), uintptr(length >> 32)); + errno = int(e1); + return; +} + +func Getdents(fd int, buf []byte) (n int, errno int) { + var _p0 *byte; + if len(buf) > 0 { _p0 = &buf[0]; } + r0, r1, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf))); + n = int(r0); + errno = int(e1); + return; +} + +func Getegid() (egid int) { + r0, r1, e1 := Syscall(SYS_GETEGID, 0, 0, 0); + egid = int(r0); + return; +} + +func Geteuid() (euid int) { + r0, r1, e1 := Syscall(SYS_GETEUID, 0, 0, 0); + euid = int(r0); + return; +} + +func Getgid() (gid int) { + r0, r1, e1 := Syscall(SYS_GETGID, 0, 0, 0); + gid = int(r0); + return; +} + +func Getpgid(pid int) (pgid int, errno int) { + r0, r1, e1 := Syscall(SYS_GETPGID, uintptr(pid), 0, 0); + pgid = int(r0); + errno = int(e1); + return; +} + +func Getpgrp() (pid int) { + r0, r1, e1 := Syscall(SYS_GETPGRP, 0, 0, 0); + pid = int(r0); + return; +} + +func Getpid() (pid int) { + r0, r1, e1 := Syscall(SYS_GETPID, 0, 0, 0); + pid = int(r0); + return; +} + +func Getppid() (ppid int) { + r0, r1, e1 := Syscall(SYS_GETPPID, 0, 0, 0); + ppid = int(r0); + return; +} + +func Getrlimit(resource int, rlim *Rlimit) (errno int) { + r0, r1, e1 := Syscall(SYS_GETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0); + errno = int(e1); + return; +} + +func Getrusage(who int, rusage *Rusage) (errno int) { + r0, r1, e1 := Syscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0); + errno = int(e1); + return; +} + +func Gettid() (tid int) { + r0, r1, e1 := Syscall(SYS_GETTID, 0, 0, 0); + tid = int(r0); + return; +} + +func Gettimeofday(tv *Timeval) (errno int) { + r0, r1, e1 := Syscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0); + errno = int(e1); + return; +} + +func Getuid() (uid int) { + r0, r1, e1 := Syscall(SYS_GETUID, 0, 0, 0); + uid = int(r0); + return; +} + +func Ioperm(from int, num int, on int) (errno int) { + r0, r1, e1 := Syscall(SYS_IOPERM, uintptr(from), uintptr(num), uintptr(on)); + errno = int(e1); + return; +} + +func Iopl(level int) (errno int) { + r0, r1, e1 := Syscall(SYS_IOPL, uintptr(level), 0, 0); + errno = int(e1); + return; +} + +func Kill(pid int, sig int) (errno int) { + r0, r1, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(sig), 0); + errno = int(e1); + return; +} + +func Klogctl(typ int, buf []byte) (n int, errno int) { + var _p0 *byte; + if len(buf) > 0 { _p0 = &buf[0]; } + r0, r1, e1 := Syscall(SYS_SYSLOG, uintptr(typ), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf))); + n = int(r0); + errno = int(e1); + return; +} + +func Lchown(path string, uid int, gid int) (errno int) { + r0, r1, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid)); + errno = int(e1); + return; +} + +func Link(oldpath string, newpath string) (errno int) { + r0, r1, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(StringBytePtr(oldpath))), uintptr(unsafe.Pointer(StringBytePtr(newpath))), 0); + errno = int(e1); + return; +} + +func Lstat(path string, stat *Stat_t) (errno int) { + r0, r1, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0); + errno = int(e1); + return; +} + +func Mkdir(path string, mode int) (errno int) { + r0, r1, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0); + errno = int(e1); + return; +} + +func Mkdirat(dirfd int, path string, mode int) (errno int) { + r0, r1, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode)); + errno = int(e1); + return; +} + +func Mknod(path string, mode int, dev int) (errno int) { + r0, r1, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(dev)); + errno = int(e1); + return; +} + +func Mknodat(dirfd int, path string, mode int, dev int) (errno int) { + r0, r1, e1 := Syscall6(SYS_MKNODAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(dev), 0, 0); + errno = int(e1); + return; +} + +func Nanosleep(time *Timespec, leftover *Timespec) (errno int) { + r0, r1, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0); + errno = int(e1); + return; +} + +func Open(path string, mode int, perm int) (fd int, errno int) { + r0, r1, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(perm)); + fd = int(r0); + errno = int(e1); + return; +} + +func Openat(dirfd int, path string, flags int, mode int) (fd int, errno int) { + r0, r1, e1 := Syscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), uintptr(mode), 0, 0); + fd = int(r0); + errno = int(e1); + return; +} + +func Pause() (errno int) { + r0, r1, e1 := Syscall(SYS_PAUSE, 0, 0, 0); + errno = int(e1); + return; +} + +func PivotRoot(newroot string, putold string) (errno int) { + r0, r1, e1 := Syscall(SYS_PIVOT_ROOT, uintptr(unsafe.Pointer(StringBytePtr(newroot))), uintptr(unsafe.Pointer(StringBytePtr(putold))), 0); + errno = int(e1); + return; +} + +func Pread(fd int, p []byte, offset int64) (n int, errno int) { + var _p0 *byte; + if len(p) > 0 { _p0 = &p[0]; } + r0, r1, e1 := Syscall6(SYS_PREAD64, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), uintptr(offset >> 32), 0); + n = int(r0); + errno = int(e1); + return; +} + +func Pwrite(fd int, p []byte, offset int64) (n int, errno int) { + var _p0 *byte; + if len(p) > 0 { _p0 = &p[0]; } + r0, r1, e1 := Syscall6(SYS_PWRITE64, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), uintptr(offset >> 32), 0); + n = int(r0); + errno = int(e1); + return; +} + +func Read(fd int, p []byte) (n int, errno int) { + var _p0 *byte; + if len(p) > 0 { _p0 = &p[0]; } + r0, r1, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p))); + n = int(r0); + errno = int(e1); + return; +} + +func Readlink(path string, buf []byte) (n int, errno int) { + var _p0 *byte; + if len(buf) > 0 { _p0 = &buf[0]; } + r0, r1, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf))); + n = int(r0); + errno = int(e1); + return; +} + +func Rename(oldpath string, newpath string) (errno int) { + r0, r1, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(StringBytePtr(oldpath))), uintptr(unsafe.Pointer(StringBytePtr(newpath))), 0); + errno = int(e1); + return; +} + +func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (errno int) { + r0, r1, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(StringBytePtr(oldpath))), uintptr(newdirfd), uintptr(unsafe.Pointer(StringBytePtr(newpath))), 0, 0); + errno = int(e1); + return; +} + +func Rmdir(path string) (errno int) { + r0, r1, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); + errno = int(e1); + return; +} + +func Seek(fd int, offset int64, whence int) (off int64, errno int) { + r0, r1, e1 := Syscall6(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(offset >> 32), uintptr(whence), 0, 0); + off = int64(r0); + errno = int(e1); + return; +} + +func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, errno int) { + r0, r1, 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; +} + +func Setdomainname(p []byte) (errno int) { + var _p0 *byte; + if len(p) > 0 { _p0 = &p[0]; } + r0, r1, e1 := Syscall(SYS_SETDOMAINNAME, uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), 0); + errno = int(e1); + return; +} + +func Setfsgid(gid int) (errno int) { + r0, r1, e1 := Syscall(SYS_SETFSGID, uintptr(gid), 0, 0); + errno = int(e1); + return; +} + +func Setfsuid(uid int) (errno int) { + r0, r1, e1 := Syscall(SYS_SETFSUID, uintptr(uid), 0, 0); + errno = int(e1); + return; +} + +func Setgid(gid int) (errno int) { + r0, r1, e1 := Syscall(SYS_SETGID, uintptr(gid), 0, 0); + errno = int(e1); + return; +} + +func Sethostname(p []byte) (errno int) { + var _p0 *byte; + if len(p) > 0 { _p0 = &p[0]; } + r0, r1, e1 := Syscall(SYS_SETHOSTNAME, uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), 0); + errno = int(e1); + return; +} + +func Setpgid(pid int, pgid int) (errno int) { + r0, r1, e1 := Syscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0); + errno = int(e1); + return; +} + +func Setregid(rgid int, egid int) (errno int) { + r0, r1, e1 := Syscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0); + errno = int(e1); + return; +} + +func Setresgid(rgid int, egid int, sgid int) (errno int) { + r0, r1, e1 := Syscall(SYS_SETRESGID, uintptr(rgid), uintptr(egid), uintptr(sgid)); + errno = int(e1); + return; +} + +func Setresuid(ruid int, euid int, suid int) (errno int) { + r0, r1, e1 := Syscall(SYS_SETRESUID, uintptr(ruid), uintptr(euid), uintptr(suid)); + errno = int(e1); + return; +} + +func Setreuid(ruid int, euid int) (errno int) { + r0, r1, e1 := Syscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0); + errno = int(e1); + return; +} + +func Setrlimit(resource int, rlim *Rlimit) (errno int) { + r0, r1, e1 := Syscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0); + errno = int(e1); + return; +} + +func Setsid() (pid int) { + r0, r1, e1 := Syscall(SYS_SETSID, 0, 0, 0); + pid = int(r0); + return; +} + +func Settimeofday(tv *Timeval) (errno int) { + r0, r1, e1 := Syscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0); + errno = int(e1); + return; +} + +func Setuid(uid int) (errno int) { + r0, r1, e1 := Syscall(SYS_SETUID, uintptr(uid), 0, 0); + errno = int(e1); + return; +} + +func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, errno int) { + r0, r1, e1 := Syscall6(SYS_SPLICE, uintptr(rfd), uintptr(unsafe.Pointer(roff)), uintptr(wfd), uintptr(unsafe.Pointer(woff)), uintptr(len), uintptr(flags)); + n = int64(r0); + errno = int(e1); + return; +} + +func Stat(path string, stat *Stat_t) (errno int) { + r0, r1, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0); + errno = int(e1); + return; +} + +func Statfs(path string, buf *Statfs_t) (errno int) { + r0, r1, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(buf)), 0); + errno = int(e1); + return; +} + +func Symlink(oldpath string, newpath string) (errno int) { + r0, r1, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(StringBytePtr(oldpath))), uintptr(unsafe.Pointer(StringBytePtr(newpath))), 0); + errno = int(e1); + return; +} + +func Sync() () { + r0, r1, e1 := Syscall(SYS_SYNC, 0, 0, 0); + return; +} + +func SyncFileRange(fd int, off int64, n int64, flags int) (errno int) { + r0, r1, e1 := Syscall6(SYS_SYNC_FILE_RANGE, uintptr(fd), uintptr(off), uintptr(off >> 32), uintptr(n), uintptr(n >> 32), uintptr(flags)); + errno = int(e1); + return; +} + +func Sysinfo(info *Sysinfo_t) (errno int) { + r0, r1, e1 := Syscall(SYS_SYSINFO, uintptr(unsafe.Pointer(info)), 0, 0); + errno = int(e1); + return; +} + +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(r0); + errno = int(e1); + return; +} + +func Tgkill(tgid int, tid int, sig int) (errno int) { + r0, r1, e1 := Syscall(SYS_TGKILL, uintptr(tgid), uintptr(tid), uintptr(sig)); + errno = int(e1); + return; +} + +func Time(t *Time_t) (tt Time_t, errno int) { + r0, r1, e1 := Syscall(SYS_TIME, uintptr(unsafe.Pointer(t)), 0, 0); + tt = Time_t(r0); + errno = int(e1); + return; +} + +func Times(tms *Tms) (ticks uintptr, errno int) { + r0, r1, e1 := Syscall(SYS_TIMES, uintptr(unsafe.Pointer(tms)), 0, 0); + ticks = uintptr(r0); + errno = int(e1); + return; +} + +func Truncate(path string, length int64) (errno int) { + r0, r1, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(length), uintptr(length >> 32)); + errno = int(e1); + return; +} + +func Umask(mask int) (oldmask int) { + r0, r1, e1 := Syscall(SYS_UMASK, uintptr(mask), 0, 0); + oldmask = int(r0); + return; +} + +func Uname(buf *Utsname) (errno int) { + r0, r1, e1 := Syscall(SYS_UNAME, uintptr(unsafe.Pointer(buf)), 0, 0); + errno = int(e1); + return; +} + +func Unlink(path string) (errno int) { + r0, r1, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); + errno = int(e1); + return; +} + +func Unlinkat(dirfd int, path string) (errno int) { + r0, r1, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), 0); + errno = int(e1); + return; +} + +func Unshare(flags int) (errno int) { + r0, r1, e1 := Syscall(SYS_UNSHARE, uintptr(flags), 0, 0); + errno = int(e1); + return; +} + +func Ustat(dev int, ubuf *Ustat_t) (errno int) { + r0, r1, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0); + errno = int(e1); + return; +} + +func Utime(path string, buf *Utimbuf) (errno int) { + r0, r1, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(buf)), 0); + errno = int(e1); + return; +} + +func Write(fd int, p []byte) (n int, errno int) { + var _p0 *byte; + if len(p) > 0 { _p0 = &p[0]; } + r0, r1, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p))); + n = int(r0); + errno = int(e1); + return; +} + +func exitThread(code int) (errno int) { + r0, r1, e1 := Syscall(SYS_EXIT, uintptr(code), 0, 0); + errno = int(e1); + return; +} + +func read(fd int, p *byte, np int) (n int, errno int) { + r0, r1, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np)); + n = int(r0); + errno = int(e1); + return; +} + +func write(fd int, p *byte, np int) (n int, errno int) { + r0, r1, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np)); + n = int(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..490ffc392 --- /dev/null +++ b/src/pkg/syscall/zsyscall_linux_amd64.go @@ -0,0 +1,764 @@ +// mksyscall syscall_linux.go syscall_linux_amd64.go +// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT + +package syscall + +import ( + "syscall"; + "unsafe"; +) + +func pipe(p *[2]_C_int) (errno int) { + r0, r1, e1 := Syscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0); + errno = int(e1); + return; +} + +func utimes(path string, times *[2]Timeval) (errno int) { + r0, r1, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(times)), 0); + errno = int(e1); + return; +} + +func futimesat(dirfd int, path string, times *[2]Timeval) (errno int) { + r0, r1, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(times))); + errno = int(e1); + return; +} + +func Getcwd(buf []byte) (n int, errno int) { + var _p0 *byte; + if len(buf) > 0 { _p0 = &buf[0]; } + r0, r1, e1 := Syscall(SYS_GETCWD, uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), 0); + n = int(r0); + errno = int(e1); + return; +} + +func getgroups(n int, list *_Gid_t) (nn int, errno int) { + r0, r1, e1 := Syscall(SYS_GETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0); + nn = int(r0); + errno = int(e1); + return; +} + +func setgroups(n int, list *_Gid_t) (errno int) { + r0, r1, e1 := Syscall(SYS_SETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0); + errno = int(e1); + return; +} + +func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, errno int) { + r0, r1, 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; +} + +func Access(path string, mode int) (errno int) { + r0, r1, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0); + errno = int(e1); + return; +} + +func Acct(path string) (errno int) { + r0, r1, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); + errno = int(e1); + return; +} + +func Adjtimex(buf *Timex) (state int, errno int) { + r0, r1, e1 := Syscall(SYS_ADJTIMEX, uintptr(unsafe.Pointer(buf)), 0, 0); + state = int(r0); + errno = int(e1); + return; +} + +func Chdir(path string) (errno int) { + r0, r1, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); + errno = int(e1); + return; +} + +func Chmod(path string, mode int) (errno int) { + r0, r1, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0); + errno = int(e1); + return; +} + +func Chown(path string, uid int, gid int) (errno int) { + r0, r1, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid)); + errno = int(e1); + return; +} + +func Chroot(path string) (errno int) { + r0, r1, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); + errno = int(e1); + return; +} + +func Close(fd int) (errno int) { + r0, r1, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0); + errno = int(e1); + return; +} + +func Creat(path string, mode int) (fd int, errno int) { + r0, r1, e1 := Syscall(SYS_CREAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0); + fd = int(r0); + errno = int(e1); + return; +} + +func Dup(oldfd int) (fd int, errno int) { + r0, r1, e1 := Syscall(SYS_DUP, uintptr(oldfd), 0, 0); + fd = int(r0); + errno = int(e1); + return; +} + +func Dup2(oldfd int, newfd int) (fd int, errno int) { + r0, r1, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0); + fd = int(r0); + errno = int(e1); + return; +} + +func EpollCreate(size int) (fd int, errno int) { + r0, r1, e1 := Syscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0); + fd = int(r0); + errno = int(e1); + return; +} + +func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (errno int) { + r0, r1, e1 := Syscall6(SYS_EPOLL_CTL, uintptr(epfd), uintptr(op), uintptr(fd), uintptr(unsafe.Pointer(event)), 0, 0); + errno = int(e1); + return; +} + +func EpollWait(epfd int, events []EpollEvent, msec int) (n int, errno int) { + var _p0 *EpollEvent; + if len(events) > 0 { _p0 = &events[0]; } + r0, r1, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(unsafe.Pointer(_p0)), uintptr(len(events)), uintptr(msec), 0, 0); + n = int(r0); + errno = int(e1); + return; +} + +func Exit(code int) () { + r0, r1, e1 := Syscall(SYS_EXIT_GROUP, uintptr(code), 0, 0); + return; +} + +func Faccessat(dirfd int, path string, mode int, flags int) (errno int) { + r0, r1, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(flags), 0, 0); + errno = int(e1); + return; +} + +func Fallocate(fd int, mode int, off int64, len int64) (errno int) { + r0, r1, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(len), 0, 0); + errno = int(e1); + return; +} + +func Fchdir(fd int) (errno int) { + r0, r1, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0); + errno = int(e1); + return; +} + +func Fchmod(fd int, mode int) (errno int) { + r0, r1, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0); + errno = int(e1); + return; +} + +func Fchmodat(dirfd int, path string, mode int, flags int) (errno int) { + r0, r1, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(flags), 0, 0); + errno = int(e1); + return; +} + +func Fchown(fd int, uid int, gid int) (errno int) { + r0, r1, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid)); + errno = int(e1); + return; +} + +func Fchownat(dirfd int, path string, uid int, gid int, flags int) (errno int) { + r0, r1, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid), uintptr(flags), 0); + errno = int(e1); + return; +} + +func fcntl(fd int, cmd int, arg int) (val int, errno int) { + r0, r1, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg)); + val = int(r0); + errno = int(e1); + return; +} + +func Fdatasync(fd int) (errno int) { + r0, r1, e1 := Syscall(SYS_FDATASYNC, uintptr(fd), 0, 0); + errno = int(e1); + return; +} + +func Fstat(fd int, stat *Stat_t) (errno int) { + r0, r1, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0); + errno = int(e1); + return; +} + +func Fstatfs(fd int, buf *Statfs_t) (errno int) { + r0, r1, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(buf)), 0); + errno = int(e1); + return; +} + +func Fsync(fd int) (errno int) { + r0, r1, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0); + errno = int(e1); + return; +} + +func Ftruncate(fd int, length int64) (errno int) { + r0, r1, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), 0); + errno = int(e1); + return; +} + +func Getdents(fd int, buf []byte) (n int, errno int) { + var _p0 *byte; + if len(buf) > 0 { _p0 = &buf[0]; } + r0, r1, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf))); + n = int(r0); + errno = int(e1); + return; +} + +func Getegid() (egid int) { + r0, r1, e1 := Syscall(SYS_GETEGID, 0, 0, 0); + egid = int(r0); + return; +} + +func Geteuid() (euid int) { + r0, r1, e1 := Syscall(SYS_GETEUID, 0, 0, 0); + euid = int(r0); + return; +} + +func Getgid() (gid int) { + r0, r1, e1 := Syscall(SYS_GETGID, 0, 0, 0); + gid = int(r0); + return; +} + +func Getpgid(pid int) (pgid int, errno int) { + r0, r1, e1 := Syscall(SYS_GETPGID, uintptr(pid), 0, 0); + pgid = int(r0); + errno = int(e1); + return; +} + +func Getpgrp() (pid int) { + r0, r1, e1 := Syscall(SYS_GETPGRP, 0, 0, 0); + pid = int(r0); + return; +} + +func Getpid() (pid int) { + r0, r1, e1 := Syscall(SYS_GETPID, 0, 0, 0); + pid = int(r0); + return; +} + +func Getppid() (ppid int) { + r0, r1, e1 := Syscall(SYS_GETPPID, 0, 0, 0); + ppid = int(r0); + return; +} + +func Getrlimit(resource int, rlim *Rlimit) (errno int) { + r0, r1, e1 := Syscall(SYS_GETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0); + errno = int(e1); + return; +} + +func Getrusage(who int, rusage *Rusage) (errno int) { + r0, r1, e1 := Syscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0); + errno = int(e1); + return; +} + +func Gettid() (tid int) { + r0, r1, e1 := Syscall(SYS_GETTID, 0, 0, 0); + tid = int(r0); + return; +} + +func Gettimeofday(tv *Timeval) (errno int) { + r0, r1, e1 := Syscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0); + errno = int(e1); + return; +} + +func Getuid() (uid int) { + r0, r1, e1 := Syscall(SYS_GETUID, 0, 0, 0); + uid = int(r0); + return; +} + +func Ioperm(from int, num int, on int) (errno int) { + r0, r1, e1 := Syscall(SYS_IOPERM, uintptr(from), uintptr(num), uintptr(on)); + errno = int(e1); + return; +} + +func Iopl(level int) (errno int) { + r0, r1, e1 := Syscall(SYS_IOPL, uintptr(level), 0, 0); + errno = int(e1); + return; +} + +func Kill(pid int, sig int) (errno int) { + r0, r1, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(sig), 0); + errno = int(e1); + return; +} + +func Klogctl(typ int, buf []byte) (n int, errno int) { + var _p0 *byte; + if len(buf) > 0 { _p0 = &buf[0]; } + r0, r1, e1 := Syscall(SYS_SYSLOG, uintptr(typ), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf))); + n = int(r0); + errno = int(e1); + return; +} + +func Lchown(path string, uid int, gid int) (errno int) { + r0, r1, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid)); + errno = int(e1); + return; +} + +func Link(oldpath string, newpath string) (errno int) { + r0, r1, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(StringBytePtr(oldpath))), uintptr(unsafe.Pointer(StringBytePtr(newpath))), 0); + errno = int(e1); + return; +} + +func Lstat(path string, stat *Stat_t) (errno int) { + r0, r1, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0); + errno = int(e1); + return; +} + +func Mkdir(path string, mode int) (errno int) { + r0, r1, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0); + errno = int(e1); + return; +} + +func Mkdirat(dirfd int, path string, mode int) (errno int) { + r0, r1, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode)); + errno = int(e1); + return; +} + +func Mknod(path string, mode int, dev int) (errno int) { + r0, r1, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(dev)); + errno = int(e1); + return; +} + +func Mknodat(dirfd int, path string, mode int, dev int) (errno int) { + r0, r1, e1 := Syscall6(SYS_MKNODAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(dev), 0, 0); + errno = int(e1); + return; +} + +func Nanosleep(time *Timespec, leftover *Timespec) (errno int) { + r0, r1, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0); + errno = int(e1); + return; +} + +func Open(path string, mode int, perm int) (fd int, errno int) { + r0, r1, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(perm)); + fd = int(r0); + errno = int(e1); + return; +} + +func Openat(dirfd int, path string, flags int, mode int) (fd int, errno int) { + r0, r1, e1 := Syscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), uintptr(mode), 0, 0); + fd = int(r0); + errno = int(e1); + return; +} + +func Pause() (errno int) { + r0, r1, e1 := Syscall(SYS_PAUSE, 0, 0, 0); + errno = int(e1); + return; +} + +func PivotRoot(newroot string, putold string) (errno int) { + r0, r1, e1 := Syscall(SYS_PIVOT_ROOT, uintptr(unsafe.Pointer(StringBytePtr(newroot))), uintptr(unsafe.Pointer(StringBytePtr(putold))), 0); + errno = int(e1); + return; +} + +func Pread(fd int, p []byte, offset int64) (n int, errno int) { + var _p0 *byte; + if len(p) > 0 { _p0 = &p[0]; } + r0, r1, e1 := Syscall6(SYS_PREAD64, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), 0, 0); + n = int(r0); + errno = int(e1); + return; +} + +func Pwrite(fd int, p []byte, offset int64) (n int, errno int) { + var _p0 *byte; + if len(p) > 0 { _p0 = &p[0]; } + r0, r1, e1 := Syscall6(SYS_PWRITE64, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), 0, 0); + n = int(r0); + errno = int(e1); + return; +} + +func Read(fd int, p []byte) (n int, errno int) { + var _p0 *byte; + if len(p) > 0 { _p0 = &p[0]; } + r0, r1, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p))); + n = int(r0); + errno = int(e1); + return; +} + +func Readlink(path string, buf []byte) (n int, errno int) { + var _p0 *byte; + if len(buf) > 0 { _p0 = &buf[0]; } + r0, r1, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf))); + n = int(r0); + errno = int(e1); + return; +} + +func Rename(oldpath string, newpath string) (errno int) { + r0, r1, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(StringBytePtr(oldpath))), uintptr(unsafe.Pointer(StringBytePtr(newpath))), 0); + errno = int(e1); + return; +} + +func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (errno int) { + r0, r1, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(StringBytePtr(oldpath))), uintptr(newdirfd), uintptr(unsafe.Pointer(StringBytePtr(newpath))), 0, 0); + errno = int(e1); + return; +} + +func Rmdir(path string) (errno int) { + r0, r1, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); + errno = int(e1); + return; +} + +func Seek(fd int, offset int64, whence int) (off int64, errno int) { + r0, r1, e1 := Syscall(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence)); + off = int64(r0); + errno = int(e1); + return; +} + +func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, errno int) { + r0, r1, 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; +} + +func Setdomainname(p []byte) (errno int) { + var _p0 *byte; + if len(p) > 0 { _p0 = &p[0]; } + r0, r1, e1 := Syscall(SYS_SETDOMAINNAME, uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), 0); + errno = int(e1); + return; +} + +func Setfsgid(gid int) (errno int) { + r0, r1, e1 := Syscall(SYS_SETFSGID, uintptr(gid), 0, 0); + errno = int(e1); + return; +} + +func Setfsuid(uid int) (errno int) { + r0, r1, e1 := Syscall(SYS_SETFSUID, uintptr(uid), 0, 0); + errno = int(e1); + return; +} + +func Setgid(gid int) (errno int) { + r0, r1, e1 := Syscall(SYS_SETGID, uintptr(gid), 0, 0); + errno = int(e1); + return; +} + +func Sethostname(p []byte) (errno int) { + var _p0 *byte; + if len(p) > 0 { _p0 = &p[0]; } + r0, r1, e1 := Syscall(SYS_SETHOSTNAME, uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), 0); + errno = int(e1); + return; +} + +func Setpgid(pid int, pgid int) (errno int) { + r0, r1, e1 := Syscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0); + errno = int(e1); + return; +} + +func Setregid(rgid int, egid int) (errno int) { + r0, r1, e1 := Syscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0); + errno = int(e1); + return; +} + +func Setresgid(rgid int, egid int, sgid int) (errno int) { + r0, r1, e1 := Syscall(SYS_SETRESGID, uintptr(rgid), uintptr(egid), uintptr(sgid)); + errno = int(e1); + return; +} + +func Setresuid(ruid int, euid int, suid int) (errno int) { + r0, r1, e1 := Syscall(SYS_SETRESUID, uintptr(ruid), uintptr(euid), uintptr(suid)); + errno = int(e1); + return; +} + +func Setreuid(ruid int, euid int) (errno int) { + r0, r1, e1 := Syscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0); + errno = int(e1); + return; +} + +func Setrlimit(resource int, rlim *Rlimit) (errno int) { + r0, r1, e1 := Syscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0); + errno = int(e1); + return; +} + +func Setsid() (pid int) { + r0, r1, e1 := Syscall(SYS_SETSID, 0, 0, 0); + pid = int(r0); + return; +} + +func Settimeofday(tv *Timeval) (errno int) { + r0, r1, e1 := Syscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0); + errno = int(e1); + return; +} + +func Setuid(uid int) (errno int) { + r0, r1, e1 := Syscall(SYS_SETUID, uintptr(uid), 0, 0); + errno = int(e1); + return; +} + +func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, errno int) { + r0, r1, e1 := Syscall6(SYS_SPLICE, uintptr(rfd), uintptr(unsafe.Pointer(roff)), uintptr(wfd), uintptr(unsafe.Pointer(woff)), uintptr(len), uintptr(flags)); + n = int64(r0); + errno = int(e1); + return; +} + +func Stat(path string, stat *Stat_t) (errno int) { + r0, r1, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0); + errno = int(e1); + return; +} + +func Statfs(path string, buf *Statfs_t) (errno int) { + r0, r1, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(buf)), 0); + errno = int(e1); + return; +} + +func Symlink(oldpath string, newpath string) (errno int) { + r0, r1, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(StringBytePtr(oldpath))), uintptr(unsafe.Pointer(StringBytePtr(newpath))), 0); + errno = int(e1); + return; +} + +func Sync() () { + r0, r1, e1 := Syscall(SYS_SYNC, 0, 0, 0); + return; +} + +func SyncFileRange(fd int, off int64, n int64, flags int) (errno int) { + r0, r1, e1 := Syscall6(SYS_SYNC_FILE_RANGE, uintptr(fd), uintptr(off), uintptr(n), uintptr(flags), 0, 0); + errno = int(e1); + return; +} + +func Sysinfo(info *Sysinfo_t) (errno int) { + r0, r1, e1 := Syscall(SYS_SYSINFO, uintptr(unsafe.Pointer(info)), 0, 0); + errno = int(e1); + return; +} + +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(r0); + errno = int(e1); + return; +} + +func Tgkill(tgid int, tid int, sig int) (errno int) { + r0, r1, e1 := Syscall(SYS_TGKILL, uintptr(tgid), uintptr(tid), uintptr(sig)); + errno = int(e1); + return; +} + +func Time(t *Time_t) (tt Time_t, errno int) { + r0, r1, e1 := Syscall(SYS_TIME, uintptr(unsafe.Pointer(t)), 0, 0); + tt = Time_t(r0); + errno = int(e1); + return; +} + +func Times(tms *Tms) (ticks uintptr, errno int) { + r0, r1, e1 := Syscall(SYS_TIMES, uintptr(unsafe.Pointer(tms)), 0, 0); + ticks = uintptr(r0); + errno = int(e1); + return; +} + +func Truncate(path string, length int64) (errno int) { + r0, r1, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(length), 0); + errno = int(e1); + return; +} + +func Umask(mask int) (oldmask int) { + r0, r1, e1 := Syscall(SYS_UMASK, uintptr(mask), 0, 0); + oldmask = int(r0); + return; +} + +func Uname(buf *Utsname) (errno int) { + r0, r1, e1 := Syscall(SYS_UNAME, uintptr(unsafe.Pointer(buf)), 0, 0); + errno = int(e1); + return; +} + +func Unlink(path string) (errno int) { + r0, r1, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0); + errno = int(e1); + return; +} + +func Unlinkat(dirfd int, path string) (errno int) { + r0, r1, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), 0); + errno = int(e1); + return; +} + +func Unshare(flags int) (errno int) { + r0, r1, e1 := Syscall(SYS_UNSHARE, uintptr(flags), 0, 0); + errno = int(e1); + return; +} + +func Ustat(dev int, ubuf *Ustat_t) (errno int) { + r0, r1, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0); + errno = int(e1); + return; +} + +func Utime(path string, buf *Utimbuf) (errno int) { + r0, r1, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(buf)), 0); + errno = int(e1); + return; +} + +func Write(fd int, p []byte) (n int, errno int) { + var _p0 *byte; + if len(p) > 0 { _p0 = &p[0]; } + r0, r1, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p))); + n = int(r0); + errno = int(e1); + return; +} + +func exitThread(code int) (errno int) { + r0, r1, e1 := Syscall(SYS_EXIT, uintptr(code), 0, 0); + errno = int(e1); + return; +} + +func read(fd int, p *byte, np int) (n int, errno int) { + r0, r1, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np)); + n = int(r0); + errno = int(e1); + return; +} + +func write(fd int, p *byte, np int) (n int, errno int) { + r0, r1, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np)); + n = int(r0); + errno = int(e1); + return; +} + +func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, errno int) { + r0, r1, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))); + fd = int(r0); + errno = int(e1); + return; +} + +func bind(s int, addr uintptr, addrlen _Socklen) (errno int) { + r0, r1, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen)); + errno = int(e1); + return; +} + +func connect(s int, addr uintptr, addrlen _Socklen) (errno int) { + r0, r1, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen)); + errno = int(e1); + return; +} + +func socket(domain int, typ int, proto int) (fd int, errno int) { + r0, r1, e1 := Syscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto)); + fd = int(r0); + errno = int(e1); + return; +} + +func setsockopt(s int, level int, name int, val uintptr, vallen int) (errno int) { + r0, r1, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0); + errno = int(e1); + return; +} + +func Listen(s int, n int) (errno int) { + r0, r1, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(n), 0); + errno = int(e1); + return; +} + +func Shutdown(fd int, how int) (errno int) { + r0, r1, e1 := Syscall(SYS_SHUTDOWN, uintptr(fd), uintptr(how), 0); + errno = int(e1); + 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..c4c48c2a2 --- /dev/null +++ b/src/pkg/syscall/zsysnum_darwin_386.go @@ -0,0 +1,485 @@ +// mksysnum_darwin /home/rsc/pub/xnu-1228/bsd/kern/syscalls.master +// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT + +package syscall + +const ( + // SYS_NOSYS = 0; // { int nosys(void); } { indirect syscall } + SYS_EXIT = 1; // { void exit(int rval); } + SYS_FORK = 2; // { int fork(void); } + SYS_READ = 3; // { user_ssize_t read(int fd, user_addr_t cbuf, user_size_t nbyte); } + SYS_WRITE = 4; // { user_ssize_t write(int fd, user_addr_t cbuf, user_size_t nbyte); } + SYS_OPEN = 5; // { int open(user_addr_t path, int flags, int mode); } + SYS_CLOSE = 6; // { int close(int fd); } + SYS_WAIT4 = 7; // { int wait4(int pid, user_addr_t status, int options, user_addr_t rusage); } + // SYS_NOSYS = 8; // { int nosys(void); } { old creat } + SYS_LINK = 9; // { int link(user_addr_t path, user_addr_t link); } + SYS_UNLINK = 10; // { int unlink(user_addr_t path); } + // SYS_NOSYS = 11; // { int nosys(void); } { old execv } + SYS_CHDIR = 12; // { int chdir(user_addr_t path); } + SYS_FCHDIR = 13; // { int fchdir(int fd); } + SYS_MKNOD = 14; // { int mknod(user_addr_t path, int mode, int dev); } + SYS_CHMOD = 15; // { int chmod(user_addr_t path, int mode); } + SYS_CHOWN = 16; // { int chown(user_addr_t path, int uid, int gid); } + SYS_OGETFSSTAT = 18; // { int ogetfsstat(user_addr_t buf, int bufsize, int flags); } + SYS_GETFSSTAT = 18; // { int getfsstat(user_addr_t buf, int bufsize, int flags); } + // SYS_NOSYS = 19; // { int nosys(void); } { old lseek } + SYS_GETPID = 20; // { int getpid(void); } + // SYS_NOSYS = 21; // { int nosys(void); } { old mount } + // SYS_NOSYS = 22; // { int nosys(void); } { old umount } + SYS_SETUID = 23; // { int setuid(uid_t uid); } + SYS_GETUID = 24; // { int getuid(void); } + SYS_GETEUID = 25; // { int geteuid(void); } + SYS_PTRACE = 26; // { int ptrace(int req, pid_t pid, caddr_t addr, int data); } + SYS_RECVMSG = 27; // { int recvmsg(int s, struct msghdr *msg, int flags); } + SYS_SENDMSG = 28; // { int sendmsg(int s, caddr_t msg, int flags); } + SYS_RECVFROM = 29; // { int recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, int *fromlenaddr); } + SYS_ACCEPT = 30; // { int accept(int s, caddr_t name, socklen_t *anamelen); } + SYS_GETPEERNAME = 31; // { int getpeername(int fdes, caddr_t asa, socklen_t *alen); } + SYS_GETSOCKNAME = 32; // { int getsockname(int fdes, caddr_t asa, socklen_t *alen); } + // SYS_NOSYS = 27; // { int nosys(void); } + // SYS_NOSYS = 28; // { int nosys(void); } + // SYS_NOSYS = 29; // { int nosys(void); } + // SYS_NOSYS = 30; // { int nosys(void); } + // SYS_NOSYS = 31; // { int nosys(void); } + // SYS_NOSYS = 32; // { int nosys(void); } + SYS_ACCESS = 33; // { int access(user_addr_t 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, int posix); } + // SYS_NOSYS = 38; // { int nosys(void); } { old stat } + SYS_GETPPID = 39; // { int getppid(void); } + // SYS_NOSYS = 40; // { int nosys(void); } { old lstat } + SYS_DUP = 41; // { int dup(u_int fd); } + SYS_PIPE = 42; // { int pipe(void); } + SYS_GETEGID = 43; // { int getegid(void); } + SYS_PROFIL = 44; // { int profil(short *bufbase, size_t bufsize, u_long pcoffset, u_int pcscale); } + // SYS_NOSYS = 45; // { int nosys(void); } { old ktrace } + SYS_SIGACTION = 46; // { int sigaction(int signum, struct __sigaction *nsa, struct sigaction *osa); } + SYS_GETGID = 47; // { int getgid(void); } + SYS_SIGPROCMASK = 48; // { int sigprocmask(int how, user_addr_t mask, user_addr_t omask); } + SYS_GETLOGIN = 49; // { int getlogin(char *namebuf, u_int namelen); } + SYS_SETLOGIN = 50; // { int setlogin(char *namebuf); } + SYS_ACCT = 51; // { int acct(char *path); } + SYS_SIGPENDING = 52; // { int sigpending(struct sigvec *osv); } + SYS_SIGALTSTACK = 53; // { int sigaltstack(struct sigaltstack *nss, struct sigaltstack *oss); } + SYS_IOCTL = 54; // { int ioctl(int fd, u_long com, caddr_t data); } + SYS_REBOOT = 55; // { int reboot(int opt, char *command); } + SYS_REVOKE = 56; // { int revoke(char *path); } + SYS_SYMLINK = 57; // { int symlink(char *path, char *link); } + SYS_READLINK = 58; // { int readlink(char *path, char *buf, int count); } + SYS_EXECVE = 59; // { int execve(char *fname, char **argp, char **envp); } + SYS_UMASK = 60; // { int umask(int newmask); } + SYS_CHROOT = 61; // { int chroot(user_addr_t path); } + // SYS_NOSYS = 62; // { int nosys(void); } { old fstat } + // SYS_NOSYS = 63; // { int nosys(void); } { used internally, reserved } + // SYS_NOSYS = 64; // { int nosys(void); } { old getpagesize } + SYS_MSYNC = 65; // { int msync(caddr_t addr, size_t len, int flags); } + SYS_VFORK = 66; // { int vfork(void); } + // SYS_NOSYS = 67; // { int nosys(void); } { old vread } + // SYS_NOSYS = 68; // { int nosys(void); } { old vwrite } + SYS_SBRK = 69; // { int sbrk(int incr) NO_SYSCALL_STUB; } + SYS_SSTK = 70; // { int sstk(int incr) NO_SYSCALL_STUB; } + // SYS_NOSYS = 71; // { int nosys(void); } { old mmap } + SYS_OVADVISE = 72; // { int ovadvise(void) NO_SYSCALL_STUB; } { old vadvise } + SYS_MUNMAP = 73; // { int munmap(caddr_t addr, size_t len); } + SYS_MPROTECT = 74; // { int mprotect(caddr_t addr, size_t len, int prot); } + SYS_MADVISE = 75; // { int madvise(caddr_t addr, size_t len, int behav); } + // SYS_NOSYS = 76; // { int nosys(void); } { old vhangup } + // SYS_NOSYS = 77; // { int nosys(void); } { old vlimit } + SYS_MINCORE = 78; // { int mincore(user_addr_t addr, user_size_t len, user_addr_t vec); } + SYS_GETGROUPS = 79; // { int getgroups(u_int gidsetsize, gid_t *gidset); } + SYS_SETGROUPS = 80; // { int setgroups(u_int gidsetsize, gid_t *gidset); } + SYS_GETPGRP = 81; // { int getpgrp(void); } + SYS_SETPGID = 82; // { int setpgid(int pid, int pgid); } + SYS_SETITIMER = 83; // { int setitimer(u_int which, struct itimerval *itv, struct itimerval *oitv); } + // SYS_NOSYS = 84; // { int nosys(void); } { old wait } + SYS_SWAPON = 85; // { int swapon(void); } + SYS_GETITIMER = 86; // { int getitimer(u_int which, struct itimerval *itv); } + // SYS_NOSYS = 87; // { int nosys(void); } { old gethostname } + // SYS_NOSYS = 88; // { int nosys(void); } { old sethostname } + SYS_GETDTABLESIZE = 89; // { int getdtablesize(void); } + SYS_DUP2 = 90; // { int dup2(u_int from, u_int to); } + // SYS_NOSYS = 91; // { int nosys(void); } { old getdopt } + SYS_FCNTL = 92; // { int fcntl(int fd, int cmd, long arg); } + SYS_SELECT = 93; // { int select(int nd, u_int32_t *in, u_int32_t *ou, u_int32_t *ex, struct timeval *tv); } + // SYS_NOSYS = 94; // { int nosys(void); } { old setdopt } + SYS_FSYNC = 95; // { int fsync(int fd); } + SYS_SETPRIORITY = 96; // { int setpriority(int which, id_t who, int prio); } + SYS_SOCKET = 97; // { int socket(int domain, int type, int protocol); } + SYS_CONNECT = 98; // { int connect(int s, caddr_t name, socklen_t namelen); } + // SYS_NOSYS = 97; // { int nosys(void); } + // SYS_NOSYS = 98; // { int nosys(void); } + // SYS_NOSYS = 99; // { int nosys(void); } { old accept } + SYS_GETPRIORITY = 100; // { int getpriority(int which, id_t who); } + // SYS_NOSYS = 101; // { int nosys(void); } { old send } + // SYS_NOSYS = 102; // { int nosys(void); } { old recv } + // SYS_NOSYS = 103; // { int nosys(void); } { old sigreturn } + SYS_BIND = 104; // { int bind(int s, caddr_t name, socklen_t namelen); } + SYS_SETSOCKOPT = 105; // { int setsockopt(int s, int level, int name, caddr_t val, socklen_t valsize); } + SYS_LISTEN = 106; // { int listen(int s, int backlog); } + // SYS_NOSYS = 104; // { int nosys(void); } + // SYS_NOSYS = 105; // { int nosys(void); } + // SYS_NOSYS = 106; // { int nosys(void); } + // SYS_NOSYS = 107; // { int nosys(void); } { old vtimes } + // SYS_NOSYS = 108; // { int nosys(void); } { old sigvec } + // SYS_NOSYS = 109; // { int nosys(void); } { old sigblock } + // SYS_NOSYS = 110; // { int nosys(void); } { old sigsetmask } + SYS_SIGSUSPEND = 111; // { int sigsuspend(sigset_t mask); } + // SYS_NOSYS = 112; // { int nosys(void); } { old sigstack } + // SYS_NOSYS = 113; // { int nosys(void); } { old recvmsg } + // SYS_NOSYS = 114; // { int nosys(void); } { old sendmsg } + // SYS_NOSYS = 113; // { int nosys(void); } + // SYS_NOSYS = 114; // { int nosys(void); } + // SYS_NOSYS = 115; // { int nosys(void); } { old vtrace } + SYS_GETTIMEOFDAY = 116; // { int gettimeofday(struct timeval *tp, struct timezone *tzp); } + SYS_GETRUSAGE = 117; // { int getrusage(int who, struct rusage *rusage); } + SYS_GETSOCKOPT = 118; // { int getsockopt(int s, int level, int name, caddr_t val, socklen_t *avalsize); } + // SYS_NOSYS = 118; // { int nosys(void); } + // SYS_NOSYS = 119; // { int nosys(void); } { old resuba } + SYS_READV = 120; // { user_ssize_t readv(int fd, struct iovec *iovp, u_int iovcnt); } + SYS_WRITEV = 121; // { user_ssize_t writev(int fd, struct iovec *iovp, u_int iovcnt); } + SYS_SETTIMEOFDAY = 122; // { int settimeofday(struct timeval *tv, struct timezone *tzp); } + SYS_FCHOWN = 123; // { int fchown(int fd, int uid, int gid); } + SYS_FCHMOD = 124; // { int fchmod(int fd, int mode); } + // SYS_NOSYS = 125; // { int nosys(void); } { old recvfrom } + SYS_SETREUID = 126; // { int setreuid(uid_t ruid, uid_t euid); } + SYS_SETREGID = 127; // { int setregid(gid_t rgid, gid_t egid); } + SYS_RENAME = 128; // { int rename(char *from, char *to); } + // SYS_NOSYS = 129; // { int nosys(void); } { old truncate } + // SYS_NOSYS = 130; // { int nosys(void); } { old ftruncate } + SYS_FLOCK = 131; // { int flock(int fd, int how); } + SYS_MKFIFO = 132; // { int mkfifo(user_addr_t path, int mode); } + SYS_SENDTO = 133; // { int sendto(int s, caddr_t buf, size_t len, int flags, caddr_t to, socklen_t tolen); } + SYS_SHUTDOWN = 134; // { int shutdown(int s, int how); } + SYS_SOCKETPAIR = 135; // { int socketpair(int domain, int type, int protocol, int *rsv); } + // SYS_NOSYS = 133; // { int nosys(void); } + // SYS_NOSYS = 134; // { int nosys(void); } + // SYS_NOSYS = 135; // { int nosys(void); } + SYS_MKDIR = 136; // { int mkdir(user_addr_t path, int mode); } + SYS_RMDIR = 137; // { int rmdir(char *path); } + SYS_UTIMES = 138; // { int utimes(char *path, struct timeval *tptr); } + SYS_FUTIMES = 139; // { int futimes(int fd, struct timeval *tptr); } + SYS_ADJTIME = 140; // { int adjtime(struct timeval *delta, struct timeval *olddelta); } + // SYS_NOSYS = 141; // { int nosys(void); } { old getpeername } + SYS_GETHOSTUUID = 142; // { int gethostuuid(unsigned char *uuid_buf, const struct timespec *timeoutp); } + // SYS_NOSYS = 143; // { int nosys(void); } { old sethostid } + // SYS_NOSYS = 144; // { int nosys(void); } { old getrlimit } + // SYS_NOSYS = 145; // { int nosys(void); } { old setrlimit } + // SYS_NOSYS = 146; // { int nosys(void); } { old killpg } + SYS_SETSID = 147; // { int setsid(void); } + // SYS_NOSYS = 148; // { int nosys(void); } { old setquota } + // SYS_NOSYS = 149; // { int nosys(void); } { old qquota } + // SYS_NOSYS = 150; // { int nosys(void); } { old getsockname } + SYS_GETPGID = 151; // { int getpgid(pid_t pid); } + SYS_SETPRIVEXEC = 152; // { int setprivexec(int flag); } + SYS_PREAD = 153; // { user_ssize_t pread(int fd, user_addr_t buf, user_size_t nbyte, off_t offset); } + SYS_PWRITE = 154; // { user_ssize_t pwrite(int fd, user_addr_t buf, user_size_t nbyte, off_t offset); } + SYS_NFSSVC = 155; // { int nfssvc(int flag, caddr_t argp); } + // SYS_NOSYS = 155; // { int nosys(void); } + // SYS_NOSYS = 156; // { int nosys(void); } { old getdirentries } + SYS_STATFS = 157; // { int statfs(char *path, struct statfs *buf); } + SYS_FSTATFS = 158; // { int fstatfs(int fd, struct statfs *buf); } + SYS_UNMOUNT = 159; // { int unmount(user_addr_t path, int flags); } + // SYS_NOSYS = 160; // { int nosys(void); } { old async_daemon } + SYS_GETFH = 161; // { int getfh(char *fname, fhandle_t *fhp); } + // SYS_NOSYS = 161; // { int nosys(void); } + // SYS_NOSYS = 162; // { int nosys(void); } { old getdomainname } + // SYS_NOSYS = 163; // { int nosys(void); } { old setdomainname } + // SYS_NOSYS = 164; // { int nosys(void); } + SYS_QUOTACTL = 165; // { int quotactl(const char *path, int cmd, int uid, caddr_t arg); } + // SYS_NOSYS = 166; // { int nosys(void); } { old exportfs } + SYS_MOUNT = 167; // { int mount(char *type, char *path, int flags, caddr_t data); } + // SYS_NOSYS = 168; // { int nosys(void); } { old ustat } + SYS_CSOPS = 169; // { int csops(pid_t pid, uint32_t ops, user_addr_t useraddr, user_size_t usersize); } + // SYS_NOSYS = 171; // { int nosys(void); } { old wait3 } + // SYS_NOSYS = 172; // { int nosys(void); } { old rpause } + SYS_WAITID = 173; // { int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options); } + // SYS_NOSYS = 174; // { int nosys(void); } { old getdents } + // SYS_NOSYS = 175; // { int nosys(void); } { old gc_control } + SYS_ADD_PROFIL = 176; // { int add_profil(short *bufbase, size_t bufsize, u_long pcoffset, u_int pcscale); } + // SYS_NOSYS = 177; // { int nosys(void); } + // SYS_NOSYS = 178; // { int nosys(void); } + // SYS_NOSYS = 179; // { int nosys(void); } + SYS_KDEBUG_TRACE = 180; // { int kdebug_trace(int code, int arg1, int arg2, int arg3, int arg4, int arg5) NO_SYSCALL_STUB; } + 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_SIGRETURN = 184; // { int sigreturn(struct ucontext *uctx, int infostyle); } + // SYS_NOSYS = 186; // { int nosys(void); } + // SYS_NOSYS = 187; // { int nosys(void); } + SYS_STAT = 188; // { int stat(user_addr_t path, user_addr_t ub); } + SYS_FSTAT = 189; // { int fstat(int fd, user_addr_t ub); } + SYS_LSTAT = 190; // { int lstat(user_addr_t path, user_addr_t ub); } + SYS_PATHCONF = 191; // { int pathconf(char *path, int name); } + SYS_FPATHCONF = 192; // { int fpathconf(int fd, int name); } + // SYS_NOSYS = 193; // { int nosys(void); } + SYS_GETRLIMIT = 194; // { int getrlimit(u_int which, struct rlimit *rlp); } + SYS_SETRLIMIT = 195; // { int setrlimit(u_int which, struct rlimit *rlp); } + SYS_GETDIRENTRIES = 196; // { int getdirentries(int fd, char *buf, u_int count, long *basep); } + SYS_MMAP = 197; // { user_addr_t mmap(caddr_t addr, size_t len, int prot, int flags, int fd, off_t pos); } + // SYS_NOSYS = 198; // { int nosys(void); } { __syscall } + SYS_LSEEK = 199; // { off_t lseek(int fd, off_t offset, int whence); } + SYS_TRUNCATE = 200; // { int truncate(char *path, off_t length); } + SYS_FTRUNCATE = 201; // { int ftruncate(int fd, off_t length); } + SYS___SYSCTL = 202; // { int __sysctl(int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen); } + SYS_MLOCK = 203; // { int mlock(caddr_t addr, size_t len); } + SYS_MUNLOCK = 204; // { int munlock(caddr_t addr, size_t len); } + SYS_UNDELETE = 205; // { int undelete(user_addr_t path); } + SYS_ATSOCKET = 206; // { int ATsocket(int proto); } + // SYS_NOSYS = 213; // { int nosys(void); } { Reserved for AppleTalk } + // SYS_NOSYS = 206; // { int nosys(void); } + // SYS_NOSYS = 207; // { int nosys(void); } + // SYS_NOSYS = 208; // { int nosys(void); } + // SYS_NOSYS = 209; // { int nosys(void); } + // SYS_NOSYS = 210; // { int nosys(void); } + // SYS_NOSYS = 211; // { int nosys(void); } + // SYS_NOSYS = 212; // { int nosys(void); } + // SYS_NOSYS = 213; // { int nosys(void); } { Reserved for AppleTalk } + SYS_KQUEUE_FROM_PORTSET_NP = 214; // { int kqueue_from_portset_np(int portset); } + SYS_KQUEUE_PORTSET_NP = 215; // { int kqueue_portset_np(int fd); } + SYS_GETATTRLIST = 220; // { int getattrlist(const char *path, struct attrlist *alist, void *attributeBuffer, size_t bufferSize, u_long options); } + SYS_SETATTRLIST = 221; // { int setattrlist(const char *path, struct attrlist *alist, void *attributeBuffer, size_t bufferSize, u_long options); } + SYS_GETDIRENTRIESATTR = 222; // { int getdirentriesattr(int fd, struct attrlist *alist, void *buffer, size_t buffersize, u_long *count, u_long *basep, u_long *newstate, u_long options); } + SYS_EXCHANGEDATA = 223; // { int exchangedata(const char *path1, const char *path2, u_long options); } + // SYS_NOSYS = 224; // { int nosys(void); } { was checkuseraccess } + SYS_SEARCHFS = 225; // { int searchfs(const char *path, struct fssearchblock *searchblock, u_long *nummatches, u_long scriptcode, u_long options, struct searchstate *state); } + SYS_DELETE = 226; // { int delete(user_addr_t path) NO_SYSCALL_STUB; } { private delete (Carbon semantics) } + SYS_COPYFILE = 227; // { int copyfile(char *from, char *to, int mode, int flags) NO_SYSCALL_STUB; } + // SYS_NOSYS = 228; // { int nosys(void); } + // SYS_NOSYS = 229; // { int nosys(void); } + SYS_POLL = 230; // { int poll(struct pollfd *fds, u_int nfds, int timeout); } + SYS_WATCHEVENT = 231; // { int watchevent(struct eventreq *u_req, int u_eventmask); } + SYS_WAITEVENT = 232; // { int waitevent(struct eventreq *u_req, struct timeval *tv); } + SYS_MODWATCH = 233; // { int modwatch(struct eventreq *u_req, int u_eventmask); } + SYS_GETXATTR = 234; // { user_ssize_t getxattr(user_addr_t path, user_addr_t attrname, user_addr_t value, size_t size, uint32_t position, int options); } + SYS_FGETXATTR = 235; // { user_ssize_t fgetxattr(int fd, user_addr_t attrname, user_addr_t value, size_t size, uint32_t position, int options); } + SYS_SETXATTR = 236; // { int setxattr(user_addr_t path, user_addr_t attrname, user_addr_t value, size_t size, uint32_t position, int options); } + SYS_FSETXATTR = 237; // { int fsetxattr(int fd, user_addr_t attrname, user_addr_t value, size_t size, uint32_t position, int options); } + SYS_REMOVEXATTR = 238; // { int removexattr(user_addr_t path, user_addr_t attrname, int options); } + SYS_FREMOVEXATTR = 239; // { int fremovexattr(int fd, user_addr_t attrname, int options); } + SYS_LISTXATTR = 240; // { user_ssize_t listxattr(user_addr_t path, user_addr_t namebuf, size_t bufsize, int options); } + SYS_FLISTXATTR = 241; // { user_ssize_t flistxattr(int fd, user_addr_t namebuf, size_t bufsize, int options); } + SYS_FSCTL = 242; // { int fsctl(const char *path, u_long cmd, caddr_t data, u_long options); } + SYS_INITGROUPS = 243; // { int initgroups(u_int gidsetsize, gid_t *gidset, int gmuid); } + SYS_POSIX_SPAWN = 244; // { int posix_spawn(pid_t *pid, const char *path, const struct _posix_spawn_args_desc *adesc, char **argv, char **envp); } + // SYS_NOSYS = 245; // { int nosys(void); } + // SYS_NOSYS = 246; // { int nosys(void); } + SYS_NFSCLNT = 247; // { int nfsclnt(int flag, caddr_t argp); } + // SYS_NOSYS = 247; // { int nosys(void); } + SYS_FHOPEN = 248; // { int fhopen(const struct fhandle *u_fhp, int flags); } + // SYS_NOSYS = 248; // { int nosys(void); } + // SYS_NOSYS = 249; // { int nosys(void); } + SYS_MINHERIT = 250; // { int minherit(void *addr, size_t len, int inherit); } + SYS_SEMSYS = 251; // { int semsys(u_int which, int a2, int a3, int a4, int a5); } + // SYS_NOSYS = 251; // { int nosys(void); } + SYS_MSGSYS = 252; // { int msgsys(u_int which, int a2, int a3, int a4, int a5); } + // SYS_NOSYS = 252; // { int nosys(void); } + SYS_SHMSYS = 253; // { int shmsys(u_int which, int a2, int a3, int a4); } + // SYS_NOSYS = 253; // { int nosys(void); } + SYS_SEMCTL = 254; // { int semctl(int semid, int semnum, int cmd, semun_t arg); } + SYS_SEMGET = 255; // { int semget(key_t key, int nsems, int semflg); } + SYS_SEMOP = 256; // { int semop(int semid, struct sembuf *sops, int nsops); } + // SYS_NOSYS = 257; // { int nosys(void); } + // SYS_NOSYS = 254; // { int nosys(void); } + // SYS_NOSYS = 255; // { int nosys(void); } + // SYS_NOSYS = 256; // { int nosys(void); } + // SYS_NOSYS = 257; // { int nosys(void); } + SYS_MSGCTL = 258; // { int msgctl(int msqid, int cmd, struct msqid_ds *buf); } + SYS_MSGGET = 259; // { int msgget(key_t key, int msgflg); } + SYS_MSGSND = 260; // { int msgsnd(int msqid, void *msgp, size_t msgsz, int msgflg); } + SYS_MSGRCV = 261; // { user_ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg); } + // SYS_NOSYS = 258; // { int nosys(void); } + // SYS_NOSYS = 259; // { int nosys(void); } + // SYS_NOSYS = 260; // { int nosys(void); } + // SYS_NOSYS = 261; // { int nosys(void); } + SYS_SHMAT = 262; // { user_addr_t shmat(int shmid, void *shmaddr, int shmflg); } + SYS_SHMCTL = 263; // { int shmctl(int shmid, int cmd, struct shmid_ds *buf); } + SYS_SHMDT = 264; // { int shmdt(void *shmaddr); } + SYS_SHMGET = 265; // { int shmget(key_t key, size_t size, int shmflg); } + // SYS_NOSYS = 262; // { int nosys(void); } + // SYS_NOSYS = 263; // { int nosys(void); } + // SYS_NOSYS = 264; // { int nosys(void); } + // SYS_NOSYS = 265; // { int nosys(void); } + SYS_SHM_OPEN = 266; // { int shm_open(const char *name, int oflag, int mode); } + SYS_SHM_UNLINK = 267; // { int shm_unlink(const char *name); } + SYS_SEM_OPEN = 268; // { user_addr_t sem_open(const char *name, int oflag, int mode, int value); } + SYS_SEM_CLOSE = 269; // { int sem_close(sem_t *sem); } + SYS_SEM_UNLINK = 270; // { int sem_unlink(const char *name); } + SYS_SEM_WAIT = 271; // { int sem_wait(sem_t *sem); } + SYS_SEM_TRYWAIT = 272; // { int sem_trywait(sem_t *sem); } + SYS_SEM_POST = 273; // { int sem_post(sem_t *sem); } + SYS_SEM_GETVALUE = 274; // { int sem_getvalue(sem_t *sem, int *sval); } + SYS_SEM_INIT = 275; // { int sem_init(sem_t *sem, int phsared, u_int value); } + SYS_SEM_DESTROY = 276; // { int sem_destroy(sem_t *sem); } + SYS_OPEN_EXTENDED = 277; // { int open_extended(user_addr_t path, int flags, uid_t uid, gid_t gid, int mode, user_addr_t xsecurity) NO_SYSCALL_STUB; } + SYS_UMASK_EXTENDED = 278; // { int umask_extended(int newmask, user_addr_t xsecurity) NO_SYSCALL_STUB; } + SYS_STAT_EXTENDED = 279; // { int stat_extended(user_addr_t path, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size) NO_SYSCALL_STUB; } + SYS_LSTAT_EXTENDED = 280; // { int lstat_extended(user_addr_t path, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size) NO_SYSCALL_STUB; } + SYS_FSTAT_EXTENDED = 281; // { int fstat_extended(int fd, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size) NO_SYSCALL_STUB; } + SYS_CHMOD_EXTENDED = 282; // { int chmod_extended(user_addr_t path, uid_t uid, gid_t gid, int mode, user_addr_t xsecurity) NO_SYSCALL_STUB; } + SYS_FCHMOD_EXTENDED = 283; // { int fchmod_extended(int fd, uid_t uid, gid_t gid, int mode, user_addr_t xsecurity) NO_SYSCALL_STUB; } + SYS_ACCESS_EXTENDED = 284; // { int access_extended(user_addr_t entries, size_t size, user_addr_t results, uid_t uid) NO_SYSCALL_STUB; } + SYS_SETTID = 285; // { int settid(uid_t uid, gid_t gid) NO_SYSCALL_STUB; } + SYS_GETTID = 286; // { int gettid(uid_t *uidp, gid_t *gidp) NO_SYSCALL_STUB; } + SYS_SETSGROUPS = 287; // { int setsgroups(int setlen, user_addr_t guidset) NO_SYSCALL_STUB; } + SYS_GETSGROUPS = 288; // { int getsgroups(user_addr_t setlen, user_addr_t guidset) NO_SYSCALL_STUB; } + SYS_SETWGROUPS = 289; // { int setwgroups(int setlen, user_addr_t guidset) NO_SYSCALL_STUB; } + SYS_GETWGROUPS = 290; // { int getwgroups(user_addr_t setlen, user_addr_t guidset) NO_SYSCALL_STUB; } + SYS_MKFIFO_EXTENDED = 291; // { int mkfifo_extended(user_addr_t path, uid_t uid, gid_t gid, int mode, user_addr_t xsecurity) NO_SYSCALL_STUB; } + SYS_MKDIR_EXTENDED = 292; // { int mkdir_extended(user_addr_t path, uid_t uid, gid_t gid, int mode, user_addr_t xsecurity) NO_SYSCALL_STUB; } + SYS_IDENTITYSVC = 293; // { int identitysvc(int opcode, user_addr_t message) NO_SYSCALL_STUB; } + SYS_SHARED_REGION_CHECK_NP = 294; // { int shared_region_check_np(uint64_t *start_address) NO_SYSCALL_STUB; } + SYS_SHARED_REGION_MAP_NP = 295; // { int shared_region_map_np(int fd, uint32_t count, const struct shared_file_mapping_np *mappings) NO_SYSCALL_STUB; } + // SYS_NOSYS = 296; // { int nosys(void); } { old load_shared_file } + // SYS_NOSYS = 297; // { int nosys(void); } { old reset_shared_file } + // SYS_NOSYS = 298; // { int nosys(void); } { old new_system_shared_regions } + // SYS_ENOSYS = 299; // { int enosys(void); } { old shared_region_map_file_np } + // SYS_ENOSYS = 300; // { int enosys(void); } { old shared_region_make_private_np } + SYS___PTHREAD_MUTEX_DESTROY = 301; // { int __pthread_mutex_destroy(int mutexid); } + SYS___PTHREAD_MUTEX_INIT = 302; // { int __pthread_mutex_init(user_addr_t mutex, user_addr_t attr); } + SYS___PTHREAD_MUTEX_LOCK = 303; // { int __pthread_mutex_lock(int mutexid); } + SYS___PTHREAD_MUTEX_TRYLOCK = 304; // { int __pthread_mutex_trylock(int mutexid); } + SYS___PTHREAD_MUTEX_UNLOCK = 305; // { int __pthread_mutex_unlock(int mutexid); } + SYS___PTHREAD_COND_INIT = 306; // { int __pthread_cond_init(user_addr_t cond, user_addr_t attr); } + SYS___PTHREAD_COND_DESTROY = 307; // { int __pthread_cond_destroy(int condid); } + SYS___PTHREAD_COND_BROADCAST = 308; // { int __pthread_cond_broadcast(int condid); } + SYS___PTHREAD_COND_SIGNAL = 309; // { int __pthread_cond_signal(int condid); } + SYS_GETSID = 310; // { int getsid(pid_t pid); } + SYS_SETTID_WITH_PID = 311; // { int settid_with_pid(pid_t pid, int assume) NO_SYSCALL_STUB; } + SYS___PTHREAD_COND_TIMEDWAIT = 312; // { int __pthread_cond_timedwait(int condid, int mutexid, user_addr_t abstime); } + SYS_AIO_FSYNC = 313; // { int aio_fsync(int op, user_addr_t aiocbp); } + SYS_AIO_RETURN = 314; // { user_ssize_t aio_return(user_addr_t aiocbp); } + SYS_AIO_SUSPEND = 315; // { int aio_suspend(user_addr_t aiocblist, int nent, user_addr_t timeoutp); } + SYS_AIO_CANCEL = 316; // { int aio_cancel(int fd, user_addr_t aiocbp); } + SYS_AIO_ERROR = 317; // { int aio_error(user_addr_t aiocbp); } + SYS_AIO_READ = 318; // { int aio_read(user_addr_t aiocbp); } + SYS_AIO_WRITE = 319; // { int aio_write(user_addr_t aiocbp); } + SYS_LIO_LISTIO = 320; // { int lio_listio(int mode, user_addr_t aiocblist, int nent, user_addr_t sigp); } + SYS___PTHREAD_COND_WAIT = 321; // { int __pthread_cond_wait(int condid, int mutexid); } + SYS_IOPOLICYSYS = 322; // { int iopolicysys(int cmd, void *arg) NO_SYSCALL_STUB; } + // SYS_NOSYS = 323; // { int nosys(void); } + SYS_MLOCKALL = 324; // { int mlockall(int how); } + SYS_MUNLOCKALL = 325; // { int munlockall(int how); } + // SYS_NOSYS = 326; // { int nosys(void); } + SYS_ISSETUGID = 327; // { int issetugid(void); } + SYS___PTHREAD_KILL = 328; // { int __pthread_kill(int thread_port, int sig); } + SYS___PTHREAD_SIGMASK = 329; // { int __pthread_sigmask(int how, user_addr_t set, user_addr_t oset); } + SYS___SIGWAIT = 330; // { int __sigwait(user_addr_t set, user_addr_t sig); } + SYS___DISABLE_THREADSIGNAL = 331; // { int __disable_threadsignal(int value); } + SYS___PTHREAD_MARKCANCEL = 332; // { int __pthread_markcancel(int thread_port); } + SYS___PTHREAD_CANCELED = 333; // { int __pthread_canceled(int action); } + SYS___SEMWAIT_SIGNAL = 334; // { int __semwait_signal(int cond_sem, int mutex_sem, int timeout, int relative, time_t tv_sec, int32_t tv_nsec); } + // SYS_NOSYS = 335; // { int nosys(void); } { old utrace } + SYS_PROC_INFO = 336; // { int proc_info(int32_t callnum,int32_t pid,uint32_t flavor, uint64_t arg,user_addr_t buffer,int32_t buffersize) NO_SYSCALL_STUB; } + SYS_SENDFILE = 337; // { int sendfile(int fd, int s, off_t offset, off_t *nbytes, struct sf_hdtr *hdtr, int flags); } + // SYS_NOSYS = 337; // { int nosys(void); } + SYS_STAT64 = 338; // { int stat64(user_addr_t path, user_addr_t ub); } + SYS_FSTAT64 = 339; // { int fstat64(int fd, user_addr_t ub); } + SYS_LSTAT64 = 340; // { int lstat64(user_addr_t path, user_addr_t ub); } + SYS_STAT64_EXTENDED = 341; // { int stat64_extended(user_addr_t path, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size) NO_SYSCALL_STUB; } + SYS_LSTAT64_EXTENDED = 342; // { int lstat64_extended(user_addr_t path, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size) NO_SYSCALL_STUB; } + SYS_FSTAT64_EXTENDED = 343; // { int fstat64_extended(int fd, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size) NO_SYSCALL_STUB; } + SYS_GETDIRENTRIES64 = 344; // { user_ssize_t getdirentries64(int fd, void *buf, user_size_t bufsize, off_t *position) NO_SYSCALL_STUB; } + SYS_STATFS64 = 345; // { int statfs64(char *path, struct statfs64 *buf); } + SYS_FSTATFS64 = 346; // { int fstatfs64(int fd, struct statfs64 *buf); } + SYS_GETFSSTAT64 = 347; // { int getfsstat64(user_addr_t buf, int bufsize, int flags); } + SYS___PTHREAD_CHDIR = 348; // { int __pthread_chdir(user_addr_t path); } + SYS___PTHREAD_FCHDIR = 349; // { int __pthread_fchdir(int fd); } + SYS_AUDIT = 350; // { int audit(void *record, int length); } + SYS_AUDITON = 351; // { int auditon(int cmd, void *data, int length); } + // SYS_NOSYS = 352; // { int nosys(void); } + SYS_GETAUID = 353; // { int getauid(au_id_t *auid); } + SYS_SETAUID = 354; // { int setauid(au_id_t *auid); } + SYS_GETAUDIT = 355; // { int getaudit(struct auditinfo *auditinfo); } + SYS_SETAUDIT = 356; // { int setaudit(struct auditinfo *auditinfo); } + SYS_GETAUDIT_ADDR = 357; // { int getaudit_addr(struct auditinfo_addr *auditinfo_addr, int length); } + SYS_SETAUDIT_ADDR = 358; // { int setaudit_addr(struct auditinfo_addr *auditinfo_addr, int length); } + SYS_AUDITCTL = 359; // { int auditctl(char *path); } + // SYS_NOSYS = 350; // { int nosys(void); } + // SYS_NOSYS = 351; // { int nosys(void); } + // SYS_NOSYS = 352; // { int nosys(void); } + // SYS_NOSYS = 353; // { int nosys(void); } + // SYS_NOSYS = 354; // { int nosys(void); } + // SYS_NOSYS = 355; // { int nosys(void); } + // SYS_NOSYS = 356; // { int nosys(void); } + // SYS_NOSYS = 357; // { int nosys(void); } + // SYS_NOSYS = 358; // { int nosys(void); } + // SYS_NOSYS = 359; // { int nosys(void); } + SYS_BSDTHREAD_CREATE = 360; // { user_addr_t bsdthread_create(user_addr_t func, user_addr_t func_arg, user_addr_t stack, user_addr_t pthread, uint32_t flags) NO_SYSCALL_STUB; } + SYS_BSDTHREAD_TERMINATE = 361; // { int bsdthread_terminate(user_addr_t stackaddr, size_t freesize, uint32_t port, uint32_t sem) NO_SYSCALL_STUB; } + SYS_KQUEUE = 362; // { int kqueue(void); } + SYS_KEVENT = 363; // { int kevent(int fd, const struct kevent *changelist, int nchanges, struct kevent *eventlist, int nevents, const struct timespec *timeout); } + SYS_LCHOWN = 364; // { int lchown(user_addr_t path, uid_t owner, gid_t group); } + SYS_STACK_SNAPSHOT = 365; // { int stack_snapshot(pid_t pid, user_addr_t tracebuf, uint32_t tracebuf_size, uint32_t options) NO_SYSCALL_STUB; } + SYS_BSDTHREAD_REGISTER = 366; // { int bsdthread_register(user_addr_t threadstart, user_addr_t wqthread, int pthsize) NO_SYSCALL_STUB; } + SYS_WORKQ_OPEN = 367; // { int workq_open(void) NO_SYSCALL_STUB; } + SYS_WORKQ_OPS = 368; // { int workq_ops(int options, user_addr_t item, int prio) NO_SYSCALL_STUB; } + // SYS_NOSYS = 369; // { int nosys(void); } + // SYS_NOSYS = 370; // { int nosys(void); } + // SYS_NOSYS = 371; // { int nosys(void); } + // SYS_NOSYS = 372; // { int nosys(void); } + // SYS_NOSYS = 373; // { int nosys(void); } + // SYS_NOSYS = 374; // { int nosys(void); } + // SYS_NOSYS = 375; // { int nosys(void); } + // SYS_NOSYS = 376; // { int nosys(void); } + // SYS_NOSYS = 377; // { int nosys(void); } + // SYS_NOSYS = 378; // { int nosys(void); } + // SYS_NOSYS = 379; // { int nosys(void); } + SYS___MAC_EXECVE = 380; // { int __mac_execve(char *fname, char **argp, char **envp, struct mac *mac_p); } + SYS___MAC_SYSCALL = 381; // { int __mac_syscall(char *policy, int call, user_addr_t arg); } + SYS___MAC_GET_FILE = 382; // { int __mac_get_file(char *path_p, struct mac *mac_p); } + SYS___MAC_SET_FILE = 383; // { int __mac_set_file(char *path_p, struct mac *mac_p); } + SYS___MAC_GET_LINK = 384; // { int __mac_get_link(char *path_p, struct mac *mac_p); } + SYS___MAC_SET_LINK = 385; // { int __mac_set_link(char *path_p, struct mac *mac_p); } + SYS___MAC_GET_PROC = 386; // { int __mac_get_proc(struct mac *mac_p); } + SYS___MAC_SET_PROC = 387; // { int __mac_set_proc(struct mac *mac_p); } + SYS___MAC_GET_FD = 388; // { int __mac_get_fd(int fd, struct mac *mac_p); } + SYS___MAC_SET_FD = 389; // { int __mac_set_fd(int fd, struct mac *mac_p); } + SYS___MAC_GET_PID = 390; // { int __mac_get_pid(pid_t pid, struct mac *mac_p); } + SYS___MAC_GET_LCID = 391; // { int __mac_get_lcid(pid_t lcid, struct mac *mac_p); } + SYS___MAC_GET_LCTX = 392; // { int __mac_get_lctx(struct mac *mac_p); } + SYS___MAC_SET_LCTX = 393; // { int __mac_set_lctx(struct mac *mac_p); } + SYS_SETLCID = 394; // { int setlcid(pid_t pid, pid_t lcid) NO_SYSCALL_STUB; } + SYS_GETLCID = 395; // { int getlcid(pid_t pid) NO_SYSCALL_STUB; } + SYS_READ_NOCANCEL = 396; // { user_ssize_t read_nocancel(int fd, user_addr_t cbuf, user_size_t nbyte) NO_SYSCALL_STUB; } + SYS_WRITE_NOCANCEL = 397; // { user_ssize_t write_nocancel(int fd, user_addr_t cbuf, user_size_t nbyte) NO_SYSCALL_STUB; } + SYS_OPEN_NOCANCEL = 398; // { int open_nocancel(user_addr_t path, int flags, int mode) NO_SYSCALL_STUB; } + SYS_CLOSE_NOCANCEL = 399; // { int close_nocancel(int fd) NO_SYSCALL_STUB; } + SYS_WAIT4_NOCANCEL = 400; // { int wait4_nocancel(int pid, user_addr_t status, int options, user_addr_t rusage) NO_SYSCALL_STUB; } + SYS_RECVMSG_NOCANCEL = 401; // { int recvmsg_nocancel(int s, struct msghdr *msg, int flags) NO_SYSCALL_STUB; } + SYS_SENDMSG_NOCANCEL = 402; // { int sendmsg_nocancel(int s, caddr_t msg, int flags) NO_SYSCALL_STUB; } + SYS_RECVFROM_NOCANCEL = 403; // { int recvfrom_nocancel(int s, void *buf, size_t len, int flags, struct sockaddr *from, int *fromlenaddr) NO_SYSCALL_STUB; } + SYS_ACCEPT_NOCANCEL = 404; // { int accept_nocancel(int s, caddr_t name, socklen_t *anamelen) NO_SYSCALL_STUB; } + // SYS_NOSYS = 401; // { int nosys(void); } + // SYS_NOSYS = 402; // { int nosys(void); } + // SYS_NOSYS = 403; // { int nosys(void); } + // SYS_NOSYS = 404; // { int nosys(void); } + SYS_MSYNC_NOCANCEL = 405; // { int msync_nocancel(caddr_t addr, size_t len, int flags) NO_SYSCALL_STUB; } + SYS_FCNTL_NOCANCEL = 406; // { int fcntl_nocancel(int fd, int cmd, long arg) NO_SYSCALL_STUB; } + SYS_SELECT_NOCANCEL = 407; // { int select_nocancel(int nd, u_int32_t *in, u_int32_t *ou, u_int32_t *ex, struct timeval *tv) NO_SYSCALL_STUB; } + SYS_FSYNC_NOCANCEL = 408; // { int fsync_nocancel(int fd) NO_SYSCALL_STUB; } + SYS_CONNECT_NOCANCEL = 409; // { int connect_nocancel(int s, caddr_t name, socklen_t namelen) NO_SYSCALL_STUB; } + // SYS_NOSYS = 409; // { int nosys(void); } + SYS_SIGSUSPEND_NOCANCEL = 410; // { int sigsuspend_nocancel(sigset_t mask) NO_SYSCALL_STUB; } + SYS_READV_NOCANCEL = 411; // { user_ssize_t readv_nocancel(int fd, struct iovec *iovp, u_int iovcnt) NO_SYSCALL_STUB; } + SYS_WRITEV_NOCANCEL = 412; // { user_ssize_t writev_nocancel(int fd, struct iovec *iovp, u_int iovcnt) NO_SYSCALL_STUB; } + SYS_SENDTO_NOCANCEL = 413; // { int sendto_nocancel(int s, caddr_t buf, size_t len, int flags, caddr_t to, socklen_t tolen) NO_SYSCALL_STUB; } + // SYS_NOSYS = 413; // { int nosys(void); } + SYS_PREAD_NOCANCEL = 414; // { user_ssize_t pread_nocancel(int fd, user_addr_t buf, user_size_t nbyte, off_t offset) NO_SYSCALL_STUB; } + SYS_PWRITE_NOCANCEL = 415; // { user_ssize_t pwrite_nocancel(int fd, user_addr_t buf, user_size_t nbyte, off_t offset) NO_SYSCALL_STUB; } + SYS_WAITID_NOCANCEL = 416; // { int waitid_nocancel(idtype_t idtype, id_t id, siginfo_t *infop, int options) NO_SYSCALL_STUB; } + SYS_POLL_NOCANCEL = 417; // { int poll_nocancel(struct pollfd *fds, u_int nfds, int timeout) NO_SYSCALL_STUB; } + SYS_MSGSND_NOCANCEL = 418; // { int msgsnd_nocancel(int msqid, void *msgp, size_t msgsz, int msgflg) NO_SYSCALL_STUB; } + SYS_MSGRCV_NOCANCEL = 419; // { user_ssize_t msgrcv_nocancel(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg) NO_SYSCALL_STUB; } + // SYS_NOSYS = 418; // { int nosys(void); } + // SYS_NOSYS = 419; // { int nosys(void); } + SYS_SEM_WAIT_NOCANCEL = 420; // { int sem_wait_nocancel(sem_t *sem) NO_SYSCALL_STUB; } + SYS_AIO_SUSPEND_NOCANCEL = 421; // { int aio_suspend_nocancel(user_addr_t aiocblist, int nent, user_addr_t timeoutp) NO_SYSCALL_STUB; } + SYS___SIGWAIT_NOCANCEL = 422; // { int __sigwait_nocancel(user_addr_t set, user_addr_t sig) NO_SYSCALL_STUB; } + SYS___SEMWAIT_SIGNAL_NOCANCEL = 423; // { int __semwait_signal_nocancel(int cond_sem, int mutex_sem, int timeout, int relative, time_t tv_sec, int32_t tv_nsec) NO_SYSCALL_STUB; } + SYS___MAC_MOUNT = 424; // { int __mac_mount(char *type, char *path, int flags, caddr_t data, struct mac *mac_p); } + SYS___MAC_GET_MOUNT = 425; // { int __mac_get_mount(char *path, struct mac *mac_p); } + SYS___MAC_GETFSSTAT = 426; // { int __mac_getfsstat(user_addr_t buf, int bufsize, user_addr_t mac, int macsize, int flags); } +) diff --git a/src/pkg/syscall/zsysnum_darwin_amd64.go b/src/pkg/syscall/zsysnum_darwin_amd64.go new file mode 100644 index 000000000..c4c48c2a2 --- /dev/null +++ b/src/pkg/syscall/zsysnum_darwin_amd64.go @@ -0,0 +1,485 @@ +// mksysnum_darwin /home/rsc/pub/xnu-1228/bsd/kern/syscalls.master +// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT + +package syscall + +const ( + // SYS_NOSYS = 0; // { int nosys(void); } { indirect syscall } + SYS_EXIT = 1; // { void exit(int rval); } + SYS_FORK = 2; // { int fork(void); } + SYS_READ = 3; // { user_ssize_t read(int fd, user_addr_t cbuf, user_size_t nbyte); } + SYS_WRITE = 4; // { user_ssize_t write(int fd, user_addr_t cbuf, user_size_t nbyte); } + SYS_OPEN = 5; // { int open(user_addr_t path, int flags, int mode); } + SYS_CLOSE = 6; // { int close(int fd); } + SYS_WAIT4 = 7; // { int wait4(int pid, user_addr_t status, int options, user_addr_t rusage); } + // SYS_NOSYS = 8; // { int nosys(void); } { old creat } + SYS_LINK = 9; // { int link(user_addr_t path, user_addr_t link); } + SYS_UNLINK = 10; // { int unlink(user_addr_t path); } + // SYS_NOSYS = 11; // { int nosys(void); } { old execv } + SYS_CHDIR = 12; // { int chdir(user_addr_t path); } + SYS_FCHDIR = 13; // { int fchdir(int fd); } + SYS_MKNOD = 14; // { int mknod(user_addr_t path, int mode, int dev); } + SYS_CHMOD = 15; // { int chmod(user_addr_t path, int mode); } + SYS_CHOWN = 16; // { int chown(user_addr_t path, int uid, int gid); } + SYS_OGETFSSTAT = 18; // { int ogetfsstat(user_addr_t buf, int bufsize, int flags); } + SYS_GETFSSTAT = 18; // { int getfsstat(user_addr_t buf, int bufsize, int flags); } + // SYS_NOSYS = 19; // { int nosys(void); } { old lseek } + SYS_GETPID = 20; // { int getpid(void); } + // SYS_NOSYS = 21; // { int nosys(void); } { old mount } + // SYS_NOSYS = 22; // { int nosys(void); } { old umount } + SYS_SETUID = 23; // { int setuid(uid_t uid); } + SYS_GETUID = 24; // { int getuid(void); } + SYS_GETEUID = 25; // { int geteuid(void); } + SYS_PTRACE = 26; // { int ptrace(int req, pid_t pid, caddr_t addr, int data); } + SYS_RECVMSG = 27; // { int recvmsg(int s, struct msghdr *msg, int flags); } + SYS_SENDMSG = 28; // { int sendmsg(int s, caddr_t msg, int flags); } + SYS_RECVFROM = 29; // { int recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, int *fromlenaddr); } + SYS_ACCEPT = 30; // { int accept(int s, caddr_t name, socklen_t *anamelen); } + SYS_GETPEERNAME = 31; // { int getpeername(int fdes, caddr_t asa, socklen_t *alen); } + SYS_GETSOCKNAME = 32; // { int getsockname(int fdes, caddr_t asa, socklen_t *alen); } + // SYS_NOSYS = 27; // { int nosys(void); } + // SYS_NOSYS = 28; // { int nosys(void); } + // SYS_NOSYS = 29; // { int nosys(void); } + // SYS_NOSYS = 30; // { int nosys(void); } + // SYS_NOSYS = 31; // { int nosys(void); } + // SYS_NOSYS = 32; // { int nosys(void); } + SYS_ACCESS = 33; // { int access(user_addr_t 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, int posix); } + // SYS_NOSYS = 38; // { int nosys(void); } { old stat } + SYS_GETPPID = 39; // { int getppid(void); } + // SYS_NOSYS = 40; // { int nosys(void); } { old lstat } + SYS_DUP = 41; // { int dup(u_int fd); } + SYS_PIPE = 42; // { int pipe(void); } + SYS_GETEGID = 43; // { int getegid(void); } + SYS_PROFIL = 44; // { int profil(short *bufbase, size_t bufsize, u_long pcoffset, u_int pcscale); } + // SYS_NOSYS = 45; // { int nosys(void); } { old ktrace } + SYS_SIGACTION = 46; // { int sigaction(int signum, struct __sigaction *nsa, struct sigaction *osa); } + SYS_GETGID = 47; // { int getgid(void); } + SYS_SIGPROCMASK = 48; // { int sigprocmask(int how, user_addr_t mask, user_addr_t omask); } + SYS_GETLOGIN = 49; // { int getlogin(char *namebuf, u_int namelen); } + SYS_SETLOGIN = 50; // { int setlogin(char *namebuf); } + SYS_ACCT = 51; // { int acct(char *path); } + SYS_SIGPENDING = 52; // { int sigpending(struct sigvec *osv); } + SYS_SIGALTSTACK = 53; // { int sigaltstack(struct sigaltstack *nss, struct sigaltstack *oss); } + SYS_IOCTL = 54; // { int ioctl(int fd, u_long com, caddr_t data); } + SYS_REBOOT = 55; // { int reboot(int opt, char *command); } + SYS_REVOKE = 56; // { int revoke(char *path); } + SYS_SYMLINK = 57; // { int symlink(char *path, char *link); } + SYS_READLINK = 58; // { int readlink(char *path, char *buf, int count); } + SYS_EXECVE = 59; // { int execve(char *fname, char **argp, char **envp); } + SYS_UMASK = 60; // { int umask(int newmask); } + SYS_CHROOT = 61; // { int chroot(user_addr_t path); } + // SYS_NOSYS = 62; // { int nosys(void); } { old fstat } + // SYS_NOSYS = 63; // { int nosys(void); } { used internally, reserved } + // SYS_NOSYS = 64; // { int nosys(void); } { old getpagesize } + SYS_MSYNC = 65; // { int msync(caddr_t addr, size_t len, int flags); } + SYS_VFORK = 66; // { int vfork(void); } + // SYS_NOSYS = 67; // { int nosys(void); } { old vread } + // SYS_NOSYS = 68; // { int nosys(void); } { old vwrite } + SYS_SBRK = 69; // { int sbrk(int incr) NO_SYSCALL_STUB; } + SYS_SSTK = 70; // { int sstk(int incr) NO_SYSCALL_STUB; } + // SYS_NOSYS = 71; // { int nosys(void); } { old mmap } + SYS_OVADVISE = 72; // { int ovadvise(void) NO_SYSCALL_STUB; } { old vadvise } + SYS_MUNMAP = 73; // { int munmap(caddr_t addr, size_t len); } + SYS_MPROTECT = 74; // { int mprotect(caddr_t addr, size_t len, int prot); } + SYS_MADVISE = 75; // { int madvise(caddr_t addr, size_t len, int behav); } + // SYS_NOSYS = 76; // { int nosys(void); } { old vhangup } + // SYS_NOSYS = 77; // { int nosys(void); } { old vlimit } + SYS_MINCORE = 78; // { int mincore(user_addr_t addr, user_size_t len, user_addr_t vec); } + SYS_GETGROUPS = 79; // { int getgroups(u_int gidsetsize, gid_t *gidset); } + SYS_SETGROUPS = 80; // { int setgroups(u_int gidsetsize, gid_t *gidset); } + SYS_GETPGRP = 81; // { int getpgrp(void); } + SYS_SETPGID = 82; // { int setpgid(int pid, int pgid); } + SYS_SETITIMER = 83; // { int setitimer(u_int which, struct itimerval *itv, struct itimerval *oitv); } + // SYS_NOSYS = 84; // { int nosys(void); } { old wait } + SYS_SWAPON = 85; // { int swapon(void); } + SYS_GETITIMER = 86; // { int getitimer(u_int which, struct itimerval *itv); } + // SYS_NOSYS = 87; // { int nosys(void); } { old gethostname } + // SYS_NOSYS = 88; // { int nosys(void); } { old sethostname } + SYS_GETDTABLESIZE = 89; // { int getdtablesize(void); } + SYS_DUP2 = 90; // { int dup2(u_int from, u_int to); } + // SYS_NOSYS = 91; // { int nosys(void); } { old getdopt } + SYS_FCNTL = 92; // { int fcntl(int fd, int cmd, long arg); } + SYS_SELECT = 93; // { int select(int nd, u_int32_t *in, u_int32_t *ou, u_int32_t *ex, struct timeval *tv); } + // SYS_NOSYS = 94; // { int nosys(void); } { old setdopt } + SYS_FSYNC = 95; // { int fsync(int fd); } + SYS_SETPRIORITY = 96; // { int setpriority(int which, id_t who, int prio); } + SYS_SOCKET = 97; // { int socket(int domain, int type, int protocol); } + SYS_CONNECT = 98; // { int connect(int s, caddr_t name, socklen_t namelen); } + // SYS_NOSYS = 97; // { int nosys(void); } + // SYS_NOSYS = 98; // { int nosys(void); } + // SYS_NOSYS = 99; // { int nosys(void); } { old accept } + SYS_GETPRIORITY = 100; // { int getpriority(int which, id_t who); } + // SYS_NOSYS = 101; // { int nosys(void); } { old send } + // SYS_NOSYS = 102; // { int nosys(void); } { old recv } + // SYS_NOSYS = 103; // { int nosys(void); } { old sigreturn } + SYS_BIND = 104; // { int bind(int s, caddr_t name, socklen_t namelen); } + SYS_SETSOCKOPT = 105; // { int setsockopt(int s, int level, int name, caddr_t val, socklen_t valsize); } + SYS_LISTEN = 106; // { int listen(int s, int backlog); } + // SYS_NOSYS = 104; // { int nosys(void); } + // SYS_NOSYS = 105; // { int nosys(void); } + // SYS_NOSYS = 106; // { int nosys(void); } + // SYS_NOSYS = 107; // { int nosys(void); } { old vtimes } + // SYS_NOSYS = 108; // { int nosys(void); } { old sigvec } + // SYS_NOSYS = 109; // { int nosys(void); } { old sigblock } + // SYS_NOSYS = 110; // { int nosys(void); } { old sigsetmask } + SYS_SIGSUSPEND = 111; // { int sigsuspend(sigset_t mask); } + // SYS_NOSYS = 112; // { int nosys(void); } { old sigstack } + // SYS_NOSYS = 113; // { int nosys(void); } { old recvmsg } + // SYS_NOSYS = 114; // { int nosys(void); } { old sendmsg } + // SYS_NOSYS = 113; // { int nosys(void); } + // SYS_NOSYS = 114; // { int nosys(void); } + // SYS_NOSYS = 115; // { int nosys(void); } { old vtrace } + SYS_GETTIMEOFDAY = 116; // { int gettimeofday(struct timeval *tp, struct timezone *tzp); } + SYS_GETRUSAGE = 117; // { int getrusage(int who, struct rusage *rusage); } + SYS_GETSOCKOPT = 118; // { int getsockopt(int s, int level, int name, caddr_t val, socklen_t *avalsize); } + // SYS_NOSYS = 118; // { int nosys(void); } + // SYS_NOSYS = 119; // { int nosys(void); } { old resuba } + SYS_READV = 120; // { user_ssize_t readv(int fd, struct iovec *iovp, u_int iovcnt); } + SYS_WRITEV = 121; // { user_ssize_t writev(int fd, struct iovec *iovp, u_int iovcnt); } + SYS_SETTIMEOFDAY = 122; // { int settimeofday(struct timeval *tv, struct timezone *tzp); } + SYS_FCHOWN = 123; // { int fchown(int fd, int uid, int gid); } + SYS_FCHMOD = 124; // { int fchmod(int fd, int mode); } + // SYS_NOSYS = 125; // { int nosys(void); } { old recvfrom } + SYS_SETREUID = 126; // { int setreuid(uid_t ruid, uid_t euid); } + SYS_SETREGID = 127; // { int setregid(gid_t rgid, gid_t egid); } + SYS_RENAME = 128; // { int rename(char *from, char *to); } + // SYS_NOSYS = 129; // { int nosys(void); } { old truncate } + // SYS_NOSYS = 130; // { int nosys(void); } { old ftruncate } + SYS_FLOCK = 131; // { int flock(int fd, int how); } + SYS_MKFIFO = 132; // { int mkfifo(user_addr_t path, int mode); } + SYS_SENDTO = 133; // { int sendto(int s, caddr_t buf, size_t len, int flags, caddr_t to, socklen_t tolen); } + SYS_SHUTDOWN = 134; // { int shutdown(int s, int how); } + SYS_SOCKETPAIR = 135; // { int socketpair(int domain, int type, int protocol, int *rsv); } + // SYS_NOSYS = 133; // { int nosys(void); } + // SYS_NOSYS = 134; // { int nosys(void); } + // SYS_NOSYS = 135; // { int nosys(void); } + SYS_MKDIR = 136; // { int mkdir(user_addr_t path, int mode); } + SYS_RMDIR = 137; // { int rmdir(char *path); } + SYS_UTIMES = 138; // { int utimes(char *path, struct timeval *tptr); } + SYS_FUTIMES = 139; // { int futimes(int fd, struct timeval *tptr); } + SYS_ADJTIME = 140; // { int adjtime(struct timeval *delta, struct timeval *olddelta); } + // SYS_NOSYS = 141; // { int nosys(void); } { old getpeername } + SYS_GETHOSTUUID = 142; // { int gethostuuid(unsigned char *uuid_buf, const struct timespec *timeoutp); } + // SYS_NOSYS = 143; // { int nosys(void); } { old sethostid } + // SYS_NOSYS = 144; // { int nosys(void); } { old getrlimit } + // SYS_NOSYS = 145; // { int nosys(void); } { old setrlimit } + // SYS_NOSYS = 146; // { int nosys(void); } { old killpg } + SYS_SETSID = 147; // { int setsid(void); } + // SYS_NOSYS = 148; // { int nosys(void); } { old setquota } + // SYS_NOSYS = 149; // { int nosys(void); } { old qquota } + // SYS_NOSYS = 150; // { int nosys(void); } { old getsockname } + SYS_GETPGID = 151; // { int getpgid(pid_t pid); } + SYS_SETPRIVEXEC = 152; // { int setprivexec(int flag); } + SYS_PREAD = 153; // { user_ssize_t pread(int fd, user_addr_t buf, user_size_t nbyte, off_t offset); } + SYS_PWRITE = 154; // { user_ssize_t pwrite(int fd, user_addr_t buf, user_size_t nbyte, off_t offset); } + SYS_NFSSVC = 155; // { int nfssvc(int flag, caddr_t argp); } + // SYS_NOSYS = 155; // { int nosys(void); } + // SYS_NOSYS = 156; // { int nosys(void); } { old getdirentries } + SYS_STATFS = 157; // { int statfs(char *path, struct statfs *buf); } + SYS_FSTATFS = 158; // { int fstatfs(int fd, struct statfs *buf); } + SYS_UNMOUNT = 159; // { int unmount(user_addr_t path, int flags); } + // SYS_NOSYS = 160; // { int nosys(void); } { old async_daemon } + SYS_GETFH = 161; // { int getfh(char *fname, fhandle_t *fhp); } + // SYS_NOSYS = 161; // { int nosys(void); } + // SYS_NOSYS = 162; // { int nosys(void); } { old getdomainname } + // SYS_NOSYS = 163; // { int nosys(void); } { old setdomainname } + // SYS_NOSYS = 164; // { int nosys(void); } + SYS_QUOTACTL = 165; // { int quotactl(const char *path, int cmd, int uid, caddr_t arg); } + // SYS_NOSYS = 166; // { int nosys(void); } { old exportfs } + SYS_MOUNT = 167; // { int mount(char *type, char *path, int flags, caddr_t data); } + // SYS_NOSYS = 168; // { int nosys(void); } { old ustat } + SYS_CSOPS = 169; // { int csops(pid_t pid, uint32_t ops, user_addr_t useraddr, user_size_t usersize); } + // SYS_NOSYS = 171; // { int nosys(void); } { old wait3 } + // SYS_NOSYS = 172; // { int nosys(void); } { old rpause } + SYS_WAITID = 173; // { int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options); } + // SYS_NOSYS = 174; // { int nosys(void); } { old getdents } + // SYS_NOSYS = 175; // { int nosys(void); } { old gc_control } + SYS_ADD_PROFIL = 176; // { int add_profil(short *bufbase, size_t bufsize, u_long pcoffset, u_int pcscale); } + // SYS_NOSYS = 177; // { int nosys(void); } + // SYS_NOSYS = 178; // { int nosys(void); } + // SYS_NOSYS = 179; // { int nosys(void); } + SYS_KDEBUG_TRACE = 180; // { int kdebug_trace(int code, int arg1, int arg2, int arg3, int arg4, int arg5) NO_SYSCALL_STUB; } + 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_SIGRETURN = 184; // { int sigreturn(struct ucontext *uctx, int infostyle); } + // SYS_NOSYS = 186; // { int nosys(void); } + // SYS_NOSYS = 187; // { int nosys(void); } + SYS_STAT = 188; // { int stat(user_addr_t path, user_addr_t ub); } + SYS_FSTAT = 189; // { int fstat(int fd, user_addr_t ub); } + SYS_LSTAT = 190; // { int lstat(user_addr_t path, user_addr_t ub); } + SYS_PATHCONF = 191; // { int pathconf(char *path, int name); } + SYS_FPATHCONF = 192; // { int fpathconf(int fd, int name); } + // SYS_NOSYS = 193; // { int nosys(void); } + SYS_GETRLIMIT = 194; // { int getrlimit(u_int which, struct rlimit *rlp); } + SYS_SETRLIMIT = 195; // { int setrlimit(u_int which, struct rlimit *rlp); } + SYS_GETDIRENTRIES = 196; // { int getdirentries(int fd, char *buf, u_int count, long *basep); } + SYS_MMAP = 197; // { user_addr_t mmap(caddr_t addr, size_t len, int prot, int flags, int fd, off_t pos); } + // SYS_NOSYS = 198; // { int nosys(void); } { __syscall } + SYS_LSEEK = 199; // { off_t lseek(int fd, off_t offset, int whence); } + SYS_TRUNCATE = 200; // { int truncate(char *path, off_t length); } + SYS_FTRUNCATE = 201; // { int ftruncate(int fd, off_t length); } + SYS___SYSCTL = 202; // { int __sysctl(int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen); } + SYS_MLOCK = 203; // { int mlock(caddr_t addr, size_t len); } + SYS_MUNLOCK = 204; // { int munlock(caddr_t addr, size_t len); } + SYS_UNDELETE = 205; // { int undelete(user_addr_t path); } + SYS_ATSOCKET = 206; // { int ATsocket(int proto); } + // SYS_NOSYS = 213; // { int nosys(void); } { Reserved for AppleTalk } + // SYS_NOSYS = 206; // { int nosys(void); } + // SYS_NOSYS = 207; // { int nosys(void); } + // SYS_NOSYS = 208; // { int nosys(void); } + // SYS_NOSYS = 209; // { int nosys(void); } + // SYS_NOSYS = 210; // { int nosys(void); } + // SYS_NOSYS = 211; // { int nosys(void); } + // SYS_NOSYS = 212; // { int nosys(void); } + // SYS_NOSYS = 213; // { int nosys(void); } { Reserved for AppleTalk } + SYS_KQUEUE_FROM_PORTSET_NP = 214; // { int kqueue_from_portset_np(int portset); } + SYS_KQUEUE_PORTSET_NP = 215; // { int kqueue_portset_np(int fd); } + SYS_GETATTRLIST = 220; // { int getattrlist(const char *path, struct attrlist *alist, void *attributeBuffer, size_t bufferSize, u_long options); } + SYS_SETATTRLIST = 221; // { int setattrlist(const char *path, struct attrlist *alist, void *attributeBuffer, size_t bufferSize, u_long options); } + SYS_GETDIRENTRIESATTR = 222; // { int getdirentriesattr(int fd, struct attrlist *alist, void *buffer, size_t buffersize, u_long *count, u_long *basep, u_long *newstate, u_long options); } + SYS_EXCHANGEDATA = 223; // { int exchangedata(const char *path1, const char *path2, u_long options); } + // SYS_NOSYS = 224; // { int nosys(void); } { was checkuseraccess } + SYS_SEARCHFS = 225; // { int searchfs(const char *path, struct fssearchblock *searchblock, u_long *nummatches, u_long scriptcode, u_long options, struct searchstate *state); } + SYS_DELETE = 226; // { int delete(user_addr_t path) NO_SYSCALL_STUB; } { private delete (Carbon semantics) } + SYS_COPYFILE = 227; // { int copyfile(char *from, char *to, int mode, int flags) NO_SYSCALL_STUB; } + // SYS_NOSYS = 228; // { int nosys(void); } + // SYS_NOSYS = 229; // { int nosys(void); } + SYS_POLL = 230; // { int poll(struct pollfd *fds, u_int nfds, int timeout); } + SYS_WATCHEVENT = 231; // { int watchevent(struct eventreq *u_req, int u_eventmask); } + SYS_WAITEVENT = 232; // { int waitevent(struct eventreq *u_req, struct timeval *tv); } + SYS_MODWATCH = 233; // { int modwatch(struct eventreq *u_req, int u_eventmask); } + SYS_GETXATTR = 234; // { user_ssize_t getxattr(user_addr_t path, user_addr_t attrname, user_addr_t value, size_t size, uint32_t position, int options); } + SYS_FGETXATTR = 235; // { user_ssize_t fgetxattr(int fd, user_addr_t attrname, user_addr_t value, size_t size, uint32_t position, int options); } + SYS_SETXATTR = 236; // { int setxattr(user_addr_t path, user_addr_t attrname, user_addr_t value, size_t size, uint32_t position, int options); } + SYS_FSETXATTR = 237; // { int fsetxattr(int fd, user_addr_t attrname, user_addr_t value, size_t size, uint32_t position, int options); } + SYS_REMOVEXATTR = 238; // { int removexattr(user_addr_t path, user_addr_t attrname, int options); } + SYS_FREMOVEXATTR = 239; // { int fremovexattr(int fd, user_addr_t attrname, int options); } + SYS_LISTXATTR = 240; // { user_ssize_t listxattr(user_addr_t path, user_addr_t namebuf, size_t bufsize, int options); } + SYS_FLISTXATTR = 241; // { user_ssize_t flistxattr(int fd, user_addr_t namebuf, size_t bufsize, int options); } + SYS_FSCTL = 242; // { int fsctl(const char *path, u_long cmd, caddr_t data, u_long options); } + SYS_INITGROUPS = 243; // { int initgroups(u_int gidsetsize, gid_t *gidset, int gmuid); } + SYS_POSIX_SPAWN = 244; // { int posix_spawn(pid_t *pid, const char *path, const struct _posix_spawn_args_desc *adesc, char **argv, char **envp); } + // SYS_NOSYS = 245; // { int nosys(void); } + // SYS_NOSYS = 246; // { int nosys(void); } + SYS_NFSCLNT = 247; // { int nfsclnt(int flag, caddr_t argp); } + // SYS_NOSYS = 247; // { int nosys(void); } + SYS_FHOPEN = 248; // { int fhopen(const struct fhandle *u_fhp, int flags); } + // SYS_NOSYS = 248; // { int nosys(void); } + // SYS_NOSYS = 249; // { int nosys(void); } + SYS_MINHERIT = 250; // { int minherit(void *addr, size_t len, int inherit); } + SYS_SEMSYS = 251; // { int semsys(u_int which, int a2, int a3, int a4, int a5); } + // SYS_NOSYS = 251; // { int nosys(void); } + SYS_MSGSYS = 252; // { int msgsys(u_int which, int a2, int a3, int a4, int a5); } + // SYS_NOSYS = 252; // { int nosys(void); } + SYS_SHMSYS = 253; // { int shmsys(u_int which, int a2, int a3, int a4); } + // SYS_NOSYS = 253; // { int nosys(void); } + SYS_SEMCTL = 254; // { int semctl(int semid, int semnum, int cmd, semun_t arg); } + SYS_SEMGET = 255; // { int semget(key_t key, int nsems, int semflg); } + SYS_SEMOP = 256; // { int semop(int semid, struct sembuf *sops, int nsops); } + // SYS_NOSYS = 257; // { int nosys(void); } + // SYS_NOSYS = 254; // { int nosys(void); } + // SYS_NOSYS = 255; // { int nosys(void); } + // SYS_NOSYS = 256; // { int nosys(void); } + // SYS_NOSYS = 257; // { int nosys(void); } + SYS_MSGCTL = 258; // { int msgctl(int msqid, int cmd, struct msqid_ds *buf); } + SYS_MSGGET = 259; // { int msgget(key_t key, int msgflg); } + SYS_MSGSND = 260; // { int msgsnd(int msqid, void *msgp, size_t msgsz, int msgflg); } + SYS_MSGRCV = 261; // { user_ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg); } + // SYS_NOSYS = 258; // { int nosys(void); } + // SYS_NOSYS = 259; // { int nosys(void); } + // SYS_NOSYS = 260; // { int nosys(void); } + // SYS_NOSYS = 261; // { int nosys(void); } + SYS_SHMAT = 262; // { user_addr_t shmat(int shmid, void *shmaddr, int shmflg); } + SYS_SHMCTL = 263; // { int shmctl(int shmid, int cmd, struct shmid_ds *buf); } + SYS_SHMDT = 264; // { int shmdt(void *shmaddr); } + SYS_SHMGET = 265; // { int shmget(key_t key, size_t size, int shmflg); } + // SYS_NOSYS = 262; // { int nosys(void); } + // SYS_NOSYS = 263; // { int nosys(void); } + // SYS_NOSYS = 264; // { int nosys(void); } + // SYS_NOSYS = 265; // { int nosys(void); } + SYS_SHM_OPEN = 266; // { int shm_open(const char *name, int oflag, int mode); } + SYS_SHM_UNLINK = 267; // { int shm_unlink(const char *name); } + SYS_SEM_OPEN = 268; // { user_addr_t sem_open(const char *name, int oflag, int mode, int value); } + SYS_SEM_CLOSE = 269; // { int sem_close(sem_t *sem); } + SYS_SEM_UNLINK = 270; // { int sem_unlink(const char *name); } + SYS_SEM_WAIT = 271; // { int sem_wait(sem_t *sem); } + SYS_SEM_TRYWAIT = 272; // { int sem_trywait(sem_t *sem); } + SYS_SEM_POST = 273; // { int sem_post(sem_t *sem); } + SYS_SEM_GETVALUE = 274; // { int sem_getvalue(sem_t *sem, int *sval); } + SYS_SEM_INIT = 275; // { int sem_init(sem_t *sem, int phsared, u_int value); } + SYS_SEM_DESTROY = 276; // { int sem_destroy(sem_t *sem); } + SYS_OPEN_EXTENDED = 277; // { int open_extended(user_addr_t path, int flags, uid_t uid, gid_t gid, int mode, user_addr_t xsecurity) NO_SYSCALL_STUB; } + SYS_UMASK_EXTENDED = 278; // { int umask_extended(int newmask, user_addr_t xsecurity) NO_SYSCALL_STUB; } + SYS_STAT_EXTENDED = 279; // { int stat_extended(user_addr_t path, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size) NO_SYSCALL_STUB; } + SYS_LSTAT_EXTENDED = 280; // { int lstat_extended(user_addr_t path, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size) NO_SYSCALL_STUB; } + SYS_FSTAT_EXTENDED = 281; // { int fstat_extended(int fd, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size) NO_SYSCALL_STUB; } + SYS_CHMOD_EXTENDED = 282; // { int chmod_extended(user_addr_t path, uid_t uid, gid_t gid, int mode, user_addr_t xsecurity) NO_SYSCALL_STUB; } + SYS_FCHMOD_EXTENDED = 283; // { int fchmod_extended(int fd, uid_t uid, gid_t gid, int mode, user_addr_t xsecurity) NO_SYSCALL_STUB; } + SYS_ACCESS_EXTENDED = 284; // { int access_extended(user_addr_t entries, size_t size, user_addr_t results, uid_t uid) NO_SYSCALL_STUB; } + SYS_SETTID = 285; // { int settid(uid_t uid, gid_t gid) NO_SYSCALL_STUB; } + SYS_GETTID = 286; // { int gettid(uid_t *uidp, gid_t *gidp) NO_SYSCALL_STUB; } + SYS_SETSGROUPS = 287; // { int setsgroups(int setlen, user_addr_t guidset) NO_SYSCALL_STUB; } + SYS_GETSGROUPS = 288; // { int getsgroups(user_addr_t setlen, user_addr_t guidset) NO_SYSCALL_STUB; } + SYS_SETWGROUPS = 289; // { int setwgroups(int setlen, user_addr_t guidset) NO_SYSCALL_STUB; } + SYS_GETWGROUPS = 290; // { int getwgroups(user_addr_t setlen, user_addr_t guidset) NO_SYSCALL_STUB; } + SYS_MKFIFO_EXTENDED = 291; // { int mkfifo_extended(user_addr_t path, uid_t uid, gid_t gid, int mode, user_addr_t xsecurity) NO_SYSCALL_STUB; } + SYS_MKDIR_EXTENDED = 292; // { int mkdir_extended(user_addr_t path, uid_t uid, gid_t gid, int mode, user_addr_t xsecurity) NO_SYSCALL_STUB; } + SYS_IDENTITYSVC = 293; // { int identitysvc(int opcode, user_addr_t message) NO_SYSCALL_STUB; } + SYS_SHARED_REGION_CHECK_NP = 294; // { int shared_region_check_np(uint64_t *start_address) NO_SYSCALL_STUB; } + SYS_SHARED_REGION_MAP_NP = 295; // { int shared_region_map_np(int fd, uint32_t count, const struct shared_file_mapping_np *mappings) NO_SYSCALL_STUB; } + // SYS_NOSYS = 296; // { int nosys(void); } { old load_shared_file } + // SYS_NOSYS = 297; // { int nosys(void); } { old reset_shared_file } + // SYS_NOSYS = 298; // { int nosys(void); } { old new_system_shared_regions } + // SYS_ENOSYS = 299; // { int enosys(void); } { old shared_region_map_file_np } + // SYS_ENOSYS = 300; // { int enosys(void); } { old shared_region_make_private_np } + SYS___PTHREAD_MUTEX_DESTROY = 301; // { int __pthread_mutex_destroy(int mutexid); } + SYS___PTHREAD_MUTEX_INIT = 302; // { int __pthread_mutex_init(user_addr_t mutex, user_addr_t attr); } + SYS___PTHREAD_MUTEX_LOCK = 303; // { int __pthread_mutex_lock(int mutexid); } + SYS___PTHREAD_MUTEX_TRYLOCK = 304; // { int __pthread_mutex_trylock(int mutexid); } + SYS___PTHREAD_MUTEX_UNLOCK = 305; // { int __pthread_mutex_unlock(int mutexid); } + SYS___PTHREAD_COND_INIT = 306; // { int __pthread_cond_init(user_addr_t cond, user_addr_t attr); } + SYS___PTHREAD_COND_DESTROY = 307; // { int __pthread_cond_destroy(int condid); } + SYS___PTHREAD_COND_BROADCAST = 308; // { int __pthread_cond_broadcast(int condid); } + SYS___PTHREAD_COND_SIGNAL = 309; // { int __pthread_cond_signal(int condid); } + SYS_GETSID = 310; // { int getsid(pid_t pid); } + SYS_SETTID_WITH_PID = 311; // { int settid_with_pid(pid_t pid, int assume) NO_SYSCALL_STUB; } + SYS___PTHREAD_COND_TIMEDWAIT = 312; // { int __pthread_cond_timedwait(int condid, int mutexid, user_addr_t abstime); } + SYS_AIO_FSYNC = 313; // { int aio_fsync(int op, user_addr_t aiocbp); } + SYS_AIO_RETURN = 314; // { user_ssize_t aio_return(user_addr_t aiocbp); } + SYS_AIO_SUSPEND = 315; // { int aio_suspend(user_addr_t aiocblist, int nent, user_addr_t timeoutp); } + SYS_AIO_CANCEL = 316; // { int aio_cancel(int fd, user_addr_t aiocbp); } + SYS_AIO_ERROR = 317; // { int aio_error(user_addr_t aiocbp); } + SYS_AIO_READ = 318; // { int aio_read(user_addr_t aiocbp); } + SYS_AIO_WRITE = 319; // { int aio_write(user_addr_t aiocbp); } + SYS_LIO_LISTIO = 320; // { int lio_listio(int mode, user_addr_t aiocblist, int nent, user_addr_t sigp); } + SYS___PTHREAD_COND_WAIT = 321; // { int __pthread_cond_wait(int condid, int mutexid); } + SYS_IOPOLICYSYS = 322; // { int iopolicysys(int cmd, void *arg) NO_SYSCALL_STUB; } + // SYS_NOSYS = 323; // { int nosys(void); } + SYS_MLOCKALL = 324; // { int mlockall(int how); } + SYS_MUNLOCKALL = 325; // { int munlockall(int how); } + // SYS_NOSYS = 326; // { int nosys(void); } + SYS_ISSETUGID = 327; // { int issetugid(void); } + SYS___PTHREAD_KILL = 328; // { int __pthread_kill(int thread_port, int sig); } + SYS___PTHREAD_SIGMASK = 329; // { int __pthread_sigmask(int how, user_addr_t set, user_addr_t oset); } + SYS___SIGWAIT = 330; // { int __sigwait(user_addr_t set, user_addr_t sig); } + SYS___DISABLE_THREADSIGNAL = 331; // { int __disable_threadsignal(int value); } + SYS___PTHREAD_MARKCANCEL = 332; // { int __pthread_markcancel(int thread_port); } + SYS___PTHREAD_CANCELED = 333; // { int __pthread_canceled(int action); } + SYS___SEMWAIT_SIGNAL = 334; // { int __semwait_signal(int cond_sem, int mutex_sem, int timeout, int relative, time_t tv_sec, int32_t tv_nsec); } + // SYS_NOSYS = 335; // { int nosys(void); } { old utrace } + SYS_PROC_INFO = 336; // { int proc_info(int32_t callnum,int32_t pid,uint32_t flavor, uint64_t arg,user_addr_t buffer,int32_t buffersize) NO_SYSCALL_STUB; } + SYS_SENDFILE = 337; // { int sendfile(int fd, int s, off_t offset, off_t *nbytes, struct sf_hdtr *hdtr, int flags); } + // SYS_NOSYS = 337; // { int nosys(void); } + SYS_STAT64 = 338; // { int stat64(user_addr_t path, user_addr_t ub); } + SYS_FSTAT64 = 339; // { int fstat64(int fd, user_addr_t ub); } + SYS_LSTAT64 = 340; // { int lstat64(user_addr_t path, user_addr_t ub); } + SYS_STAT64_EXTENDED = 341; // { int stat64_extended(user_addr_t path, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size) NO_SYSCALL_STUB; } + SYS_LSTAT64_EXTENDED = 342; // { int lstat64_extended(user_addr_t path, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size) NO_SYSCALL_STUB; } + SYS_FSTAT64_EXTENDED = 343; // { int fstat64_extended(int fd, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size) NO_SYSCALL_STUB; } + SYS_GETDIRENTRIES64 = 344; // { user_ssize_t getdirentries64(int fd, void *buf, user_size_t bufsize, off_t *position) NO_SYSCALL_STUB; } + SYS_STATFS64 = 345; // { int statfs64(char *path, struct statfs64 *buf); } + SYS_FSTATFS64 = 346; // { int fstatfs64(int fd, struct statfs64 *buf); } + SYS_GETFSSTAT64 = 347; // { int getfsstat64(user_addr_t buf, int bufsize, int flags); } + SYS___PTHREAD_CHDIR = 348; // { int __pthread_chdir(user_addr_t path); } + SYS___PTHREAD_FCHDIR = 349; // { int __pthread_fchdir(int fd); } + SYS_AUDIT = 350; // { int audit(void *record, int length); } + SYS_AUDITON = 351; // { int auditon(int cmd, void *data, int length); } + // SYS_NOSYS = 352; // { int nosys(void); } + SYS_GETAUID = 353; // { int getauid(au_id_t *auid); } + SYS_SETAUID = 354; // { int setauid(au_id_t *auid); } + SYS_GETAUDIT = 355; // { int getaudit(struct auditinfo *auditinfo); } + SYS_SETAUDIT = 356; // { int setaudit(struct auditinfo *auditinfo); } + SYS_GETAUDIT_ADDR = 357; // { int getaudit_addr(struct auditinfo_addr *auditinfo_addr, int length); } + SYS_SETAUDIT_ADDR = 358; // { int setaudit_addr(struct auditinfo_addr *auditinfo_addr, int length); } + SYS_AUDITCTL = 359; // { int auditctl(char *path); } + // SYS_NOSYS = 350; // { int nosys(void); } + // SYS_NOSYS = 351; // { int nosys(void); } + // SYS_NOSYS = 352; // { int nosys(void); } + // SYS_NOSYS = 353; // { int nosys(void); } + // SYS_NOSYS = 354; // { int nosys(void); } + // SYS_NOSYS = 355; // { int nosys(void); } + // SYS_NOSYS = 356; // { int nosys(void); } + // SYS_NOSYS = 357; // { int nosys(void); } + // SYS_NOSYS = 358; // { int nosys(void); } + // SYS_NOSYS = 359; // { int nosys(void); } + SYS_BSDTHREAD_CREATE = 360; // { user_addr_t bsdthread_create(user_addr_t func, user_addr_t func_arg, user_addr_t stack, user_addr_t pthread, uint32_t flags) NO_SYSCALL_STUB; } + SYS_BSDTHREAD_TERMINATE = 361; // { int bsdthread_terminate(user_addr_t stackaddr, size_t freesize, uint32_t port, uint32_t sem) NO_SYSCALL_STUB; } + SYS_KQUEUE = 362; // { int kqueue(void); } + SYS_KEVENT = 363; // { int kevent(int fd, const struct kevent *changelist, int nchanges, struct kevent *eventlist, int nevents, const struct timespec *timeout); } + SYS_LCHOWN = 364; // { int lchown(user_addr_t path, uid_t owner, gid_t group); } + SYS_STACK_SNAPSHOT = 365; // { int stack_snapshot(pid_t pid, user_addr_t tracebuf, uint32_t tracebuf_size, uint32_t options) NO_SYSCALL_STUB; } + SYS_BSDTHREAD_REGISTER = 366; // { int bsdthread_register(user_addr_t threadstart, user_addr_t wqthread, int pthsize) NO_SYSCALL_STUB; } + SYS_WORKQ_OPEN = 367; // { int workq_open(void) NO_SYSCALL_STUB; } + SYS_WORKQ_OPS = 368; // { int workq_ops(int options, user_addr_t item, int prio) NO_SYSCALL_STUB; } + // SYS_NOSYS = 369; // { int nosys(void); } + // SYS_NOSYS = 370; // { int nosys(void); } + // SYS_NOSYS = 371; // { int nosys(void); } + // SYS_NOSYS = 372; // { int nosys(void); } + // SYS_NOSYS = 373; // { int nosys(void); } + // SYS_NOSYS = 374; // { int nosys(void); } + // SYS_NOSYS = 375; // { int nosys(void); } + // SYS_NOSYS = 376; // { int nosys(void); } + // SYS_NOSYS = 377; // { int nosys(void); } + // SYS_NOSYS = 378; // { int nosys(void); } + // SYS_NOSYS = 379; // { int nosys(void); } + SYS___MAC_EXECVE = 380; // { int __mac_execve(char *fname, char **argp, char **envp, struct mac *mac_p); } + SYS___MAC_SYSCALL = 381; // { int __mac_syscall(char *policy, int call, user_addr_t arg); } + SYS___MAC_GET_FILE = 382; // { int __mac_get_file(char *path_p, struct mac *mac_p); } + SYS___MAC_SET_FILE = 383; // { int __mac_set_file(char *path_p, struct mac *mac_p); } + SYS___MAC_GET_LINK = 384; // { int __mac_get_link(char *path_p, struct mac *mac_p); } + SYS___MAC_SET_LINK = 385; // { int __mac_set_link(char *path_p, struct mac *mac_p); } + SYS___MAC_GET_PROC = 386; // { int __mac_get_proc(struct mac *mac_p); } + SYS___MAC_SET_PROC = 387; // { int __mac_set_proc(struct mac *mac_p); } + SYS___MAC_GET_FD = 388; // { int __mac_get_fd(int fd, struct mac *mac_p); } + SYS___MAC_SET_FD = 389; // { int __mac_set_fd(int fd, struct mac *mac_p); } + SYS___MAC_GET_PID = 390; // { int __mac_get_pid(pid_t pid, struct mac *mac_p); } + SYS___MAC_GET_LCID = 391; // { int __mac_get_lcid(pid_t lcid, struct mac *mac_p); } + SYS___MAC_GET_LCTX = 392; // { int __mac_get_lctx(struct mac *mac_p); } + SYS___MAC_SET_LCTX = 393; // { int __mac_set_lctx(struct mac *mac_p); } + SYS_SETLCID = 394; // { int setlcid(pid_t pid, pid_t lcid) NO_SYSCALL_STUB; } + SYS_GETLCID = 395; // { int getlcid(pid_t pid) NO_SYSCALL_STUB; } + SYS_READ_NOCANCEL = 396; // { user_ssize_t read_nocancel(int fd, user_addr_t cbuf, user_size_t nbyte) NO_SYSCALL_STUB; } + SYS_WRITE_NOCANCEL = 397; // { user_ssize_t write_nocancel(int fd, user_addr_t cbuf, user_size_t nbyte) NO_SYSCALL_STUB; } + SYS_OPEN_NOCANCEL = 398; // { int open_nocancel(user_addr_t path, int flags, int mode) NO_SYSCALL_STUB; } + SYS_CLOSE_NOCANCEL = 399; // { int close_nocancel(int fd) NO_SYSCALL_STUB; } + SYS_WAIT4_NOCANCEL = 400; // { int wait4_nocancel(int pid, user_addr_t status, int options, user_addr_t rusage) NO_SYSCALL_STUB; } + SYS_RECVMSG_NOCANCEL = 401; // { int recvmsg_nocancel(int s, struct msghdr *msg, int flags) NO_SYSCALL_STUB; } + SYS_SENDMSG_NOCANCEL = 402; // { int sendmsg_nocancel(int s, caddr_t msg, int flags) NO_SYSCALL_STUB; } + SYS_RECVFROM_NOCANCEL = 403; // { int recvfrom_nocancel(int s, void *buf, size_t len, int flags, struct sockaddr *from, int *fromlenaddr) NO_SYSCALL_STUB; } + SYS_ACCEPT_NOCANCEL = 404; // { int accept_nocancel(int s, caddr_t name, socklen_t *anamelen) NO_SYSCALL_STUB; } + // SYS_NOSYS = 401; // { int nosys(void); } + // SYS_NOSYS = 402; // { int nosys(void); } + // SYS_NOSYS = 403; // { int nosys(void); } + // SYS_NOSYS = 404; // { int nosys(void); } + SYS_MSYNC_NOCANCEL = 405; // { int msync_nocancel(caddr_t addr, size_t len, int flags) NO_SYSCALL_STUB; } + SYS_FCNTL_NOCANCEL = 406; // { int fcntl_nocancel(int fd, int cmd, long arg) NO_SYSCALL_STUB; } + SYS_SELECT_NOCANCEL = 407; // { int select_nocancel(int nd, u_int32_t *in, u_int32_t *ou, u_int32_t *ex, struct timeval *tv) NO_SYSCALL_STUB; } + SYS_FSYNC_NOCANCEL = 408; // { int fsync_nocancel(int fd) NO_SYSCALL_STUB; } + SYS_CONNECT_NOCANCEL = 409; // { int connect_nocancel(int s, caddr_t name, socklen_t namelen) NO_SYSCALL_STUB; } + // SYS_NOSYS = 409; // { int nosys(void); } + SYS_SIGSUSPEND_NOCANCEL = 410; // { int sigsuspend_nocancel(sigset_t mask) NO_SYSCALL_STUB; } + SYS_READV_NOCANCEL = 411; // { user_ssize_t readv_nocancel(int fd, struct iovec *iovp, u_int iovcnt) NO_SYSCALL_STUB; } + SYS_WRITEV_NOCANCEL = 412; // { user_ssize_t writev_nocancel(int fd, struct iovec *iovp, u_int iovcnt) NO_SYSCALL_STUB; } + SYS_SENDTO_NOCANCEL = 413; // { int sendto_nocancel(int s, caddr_t buf, size_t len, int flags, caddr_t to, socklen_t tolen) NO_SYSCALL_STUB; } + // SYS_NOSYS = 413; // { int nosys(void); } + SYS_PREAD_NOCANCEL = 414; // { user_ssize_t pread_nocancel(int fd, user_addr_t buf, user_size_t nbyte, off_t offset) NO_SYSCALL_STUB; } + SYS_PWRITE_NOCANCEL = 415; // { user_ssize_t pwrite_nocancel(int fd, user_addr_t buf, user_size_t nbyte, off_t offset) NO_SYSCALL_STUB; } + SYS_WAITID_NOCANCEL = 416; // { int waitid_nocancel(idtype_t idtype, id_t id, siginfo_t *infop, int options) NO_SYSCALL_STUB; } + SYS_POLL_NOCANCEL = 417; // { int poll_nocancel(struct pollfd *fds, u_int nfds, int timeout) NO_SYSCALL_STUB; } + SYS_MSGSND_NOCANCEL = 418; // { int msgsnd_nocancel(int msqid, void *msgp, size_t msgsz, int msgflg) NO_SYSCALL_STUB; } + SYS_MSGRCV_NOCANCEL = 419; // { user_ssize_t msgrcv_nocancel(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg) NO_SYSCALL_STUB; } + // SYS_NOSYS = 418; // { int nosys(void); } + // SYS_NOSYS = 419; // { int nosys(void); } + SYS_SEM_WAIT_NOCANCEL = 420; // { int sem_wait_nocancel(sem_t *sem) NO_SYSCALL_STUB; } + SYS_AIO_SUSPEND_NOCANCEL = 421; // { int aio_suspend_nocancel(user_addr_t aiocblist, int nent, user_addr_t timeoutp) NO_SYSCALL_STUB; } + SYS___SIGWAIT_NOCANCEL = 422; // { int __sigwait_nocancel(user_addr_t set, user_addr_t sig) NO_SYSCALL_STUB; } + SYS___SEMWAIT_SIGNAL_NOCANCEL = 423; // { int __semwait_signal_nocancel(int cond_sem, int mutex_sem, int timeout, int relative, time_t tv_sec, int32_t tv_nsec) NO_SYSCALL_STUB; } + SYS___MAC_MOUNT = 424; // { int __mac_mount(char *type, char *path, int flags, caddr_t data, struct mac *mac_p); } + SYS___MAC_GET_MOUNT = 425; // { int __mac_get_mount(char *path, struct mac *mac_p); } + SYS___MAC_GETFSSTAT = 426; // { int __mac_getfsstat(user_addr_t buf, int bufsize, user_addr_t mac, int macsize, int flags); } +) diff --git a/src/pkg/syscall/zsysnum_linux_386.go b/src/pkg/syscall/zsysnum_linux_386.go new file mode 100644 index 000000000..46c1112f8 --- /dev/null +++ b/src/pkg/syscall/zsysnum_linux_386.go @@ -0,0 +1,319 @@ +// Generated by mklinux; DO NOT EDIT. +// mklinux /usr/include/asm/unistd_32.h + +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_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_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 = 322; + SYS_EVENTFD = 323; + SYS_FALLOCATE = 324; +) + +func _darwin_system_call_conflict() { +} diff --git a/src/pkg/syscall/zsysnum_linux_amd64.go b/src/pkg/syscall/zsysnum_linux_amd64.go new file mode 100644 index 000000000..94424f3f3 --- /dev/null +++ b/src/pkg/syscall/zsysnum_linux_amd64.go @@ -0,0 +1,296 @@ +// Generated by mklinux; DO NOT EDIT. +// mklinux /usr/include/asm/unistd_64.h + +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 = 283; + SYS_EVENTFD = 284; + SYS_FALLOCATE = 285; +) + +func _darwin_system_call_conflict() { +} diff --git a/src/pkg/syscall/ztypes_darwin_386.go b/src/pkg/syscall/ztypes_darwin_386.go new file mode 100644 index 000000000..29d0d9676 --- /dev/null +++ b/src/pkg/syscall/ztypes_darwin_386.go @@ -0,0 +1,246 @@ +// godefs -gsyscall -f-m32 types_darwin.c types_darwin_386.c + +// MACHINE GENERATED - DO NOT EDIT. + +package syscall + +// Constants +const ( + sizeofPtr = 0x4; + sizeofShort = 0x2; + sizeofInt = 0x4; + sizeofLong = 0x4; + sizeofLongLong = 0x8; + O_RDONLY = 0; + O_WRONLY = 0x1; + O_RDWR = 0x2; + O_APPEND = 0x8; + O_ASYNC = 0x40; + O_CREAT = 0x200; + O_NOCTTY = 0x20000; + O_NONBLOCK = 0x4; + O_SYNC = 0x80; + O_TRUNC = 0x400; + O_CLOEXEC = 0; + F_GETFD = 0x1; + F_SETFD = 0x2; + F_GETFL = 0x3; + F_SETFL = 0x4; + FD_CLOEXEC = 0x1; + NAME_MAX = 0xff; + 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_IFWHT = 0xe000; + S_ISUID = 0x800; + S_ISGID = 0x400; + S_ISVTX = 0x200; + S_IRUSR = 0x100; + S_IWUSR = 0x80; + S_IXUSR = 0x40; + WNOHANG = 0x1; + WUNTRACED = 0x2; + WEXITED = 0x4; + WSTOPPED = 0x7f; + WCONTINUED = 0x10; + WNOWAIT = 0x20; + AF_UNIX = 0x1; + AF_INET = 0x2; + AF_DATAKIT = 0x9; + AF_INET6 = 0x1e; + SOCK_STREAM = 0x1; + SOCK_DGRAM = 0x2; + SOCK_RAW = 0x3; + SOCK_SEQPACKET = 0x5; + SOL_SOCKET = 0xffff; + SO_REUSEADDR = 0x4; + SO_KEEPALIVE = 0x8; + SO_DONTROUTE = 0x10; + SO_BROADCAST = 0x20; + SO_USELOOPBACK = 0x40; + SO_LINGER = 0x80; + SO_REUSEPORT = 0x200; + SO_SNDBUF = 0x1001; + SO_RCVBUF = 0x1002; + SO_SNDTIMEO = 0x1005; + SO_RCVTIMEO = 0x1006; + SO_NOSIGPIPE = 0x1022; + IPPROTO_TCP = 0x6; + IPPROTO_UDP = 0x11; + TCP_NODELAY = 0x1; + SOMAXCONN = 0x80; + SizeofSockaddrInet4 = 0x10; + SizeofSockaddrInet6 = 0x1c; + SizeofSockaddrAny = 0x1c; + SizeofSockaddrUnix = 0x6a; + EVFILT_READ = -0x1; + EVFILT_WRITE = -0x2; + EVFILT_AIO = -0x3; + EVFILT_VNODE = -0x4; + EVFILT_PROC = -0x5; + EVFILT_SIGNAL = -0x6; + EVFILT_TIMER = -0x7; + EVFILT_MACHPORT = -0x8; + EVFILT_FS = -0x9; + EVFILT_SYSCOUNT = 0x9; + EV_ADD = 0x1; + EV_DELETE = 0x2; + EV_DISABLE = 0x8; + EV_RECEIPT = 0x40; + EV_ONESHOT = 0x10; + EV_CLEAR = 0x20; + EV_SYSFLAGS = 0xf000; + EV_FLAG0 = 0x1000; + EV_FLAG1 = 0x2000; + EV_EOF = 0x8000; + EV_ERROR = 0x4000; +) + +// Types + +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 _C_int int32 + +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 Dirent struct { + Ino uint64; + Seekoff uint64; + Reclen uint16; + Namlen uint16; + Type uint8; + Name [1024]int8; + Pad0 [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 RawSockaddr struct { + Len uint8; + Family uint8; + Data [14]int8; +} + +type RawSockaddrAny struct { + Addr RawSockaddr; + Pad [12]int8; +} + +type _Socklen uint32 + +type Linger struct { + Onoff int32; + Linger int32; +} + +type Kevent_t struct { + Ident uint32; + Filter int16; + Flags uint16; + Fflags uint32; + Data int32; + Udata *byte; +} + +type FdSet struct { + Bits [32]int32; +} diff --git a/src/pkg/syscall/ztypes_darwin_amd64.go b/src/pkg/syscall/ztypes_darwin_amd64.go new file mode 100644 index 000000000..0523c50a4 --- /dev/null +++ b/src/pkg/syscall/ztypes_darwin_amd64.go @@ -0,0 +1,248 @@ +// godefs -gsyscall -f-m64 types_darwin.c types_darwin_amd64.c + +// MACHINE GENERATED - DO NOT EDIT. + +package syscall + +// Constants +const ( + sizeofPtr = 0x8; + sizeofShort = 0x2; + sizeofInt = 0x4; + sizeofLong = 0x8; + sizeofLongLong = 0x8; + O_RDONLY = 0; + O_WRONLY = 0x1; + O_RDWR = 0x2; + O_APPEND = 0x8; + O_ASYNC = 0x40; + O_CREAT = 0x200; + O_NOCTTY = 0x20000; + O_NONBLOCK = 0x4; + O_SYNC = 0x80; + O_TRUNC = 0x400; + O_CLOEXEC = 0; + F_GETFD = 0x1; + F_SETFD = 0x2; + F_GETFL = 0x3; + F_SETFL = 0x4; + FD_CLOEXEC = 0x1; + NAME_MAX = 0xff; + 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_IFWHT = 0xe000; + S_ISUID = 0x800; + S_ISGID = 0x400; + S_ISVTX = 0x200; + S_IRUSR = 0x100; + S_IWUSR = 0x80; + S_IXUSR = 0x40; + WNOHANG = 0x1; + WUNTRACED = 0x2; + WEXITED = 0x4; + WSTOPPED = 0x7f; + WCONTINUED = 0x10; + WNOWAIT = 0x20; + AF_UNIX = 0x1; + AF_INET = 0x2; + AF_DATAKIT = 0x9; + AF_INET6 = 0x1e; + SOCK_STREAM = 0x1; + SOCK_DGRAM = 0x2; + SOCK_RAW = 0x3; + SOCK_SEQPACKET = 0x5; + SOL_SOCKET = 0xffff; + SO_REUSEADDR = 0x4; + SO_KEEPALIVE = 0x8; + SO_DONTROUTE = 0x10; + SO_BROADCAST = 0x20; + SO_USELOOPBACK = 0x40; + SO_LINGER = 0x80; + SO_REUSEPORT = 0x200; + SO_SNDBUF = 0x1001; + SO_RCVBUF = 0x1002; + SO_SNDTIMEO = 0x1005; + SO_RCVTIMEO = 0x1006; + SO_NOSIGPIPE = 0x1022; + IPPROTO_TCP = 0x6; + IPPROTO_UDP = 0x11; + TCP_NODELAY = 0x1; + SOMAXCONN = 0x80; + SizeofSockaddrInet4 = 0x10; + SizeofSockaddrInet6 = 0x1c; + SizeofSockaddrAny = 0x1c; + SizeofSockaddrUnix = 0x6a; + EVFILT_READ = -0x1; + EVFILT_WRITE = -0x2; + EVFILT_AIO = -0x3; + EVFILT_VNODE = -0x4; + EVFILT_PROC = -0x5; + EVFILT_SIGNAL = -0x6; + EVFILT_TIMER = -0x7; + EVFILT_MACHPORT = -0x8; + EVFILT_FS = -0x9; + EVFILT_SYSCOUNT = 0x9; + EV_ADD = 0x1; + EV_DELETE = 0x2; + EV_DISABLE = 0x8; + EV_RECEIPT = 0x40; + EV_ONESHOT = 0x10; + EV_CLEAR = 0x20; + EV_SYSFLAGS = 0xf000; + EV_FLAG0 = 0x1000; + EV_FLAG1 = 0x2000; + EV_EOF = 0x8000; + EV_ERROR = 0x4000; +) + +// Types + +type Timespec struct { + Sec int64; + Nsec int64; +} + +type Timeval struct { + Sec int64; + Usec int32; + Pad0 [4]byte; +} + +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 _C_int int32 + +type _Gid_t uint32 + +type Stat_t struct { + Dev int32; + Mode uint16; + Nlink uint16; + Ino uint64; + Uid uint32; + Gid uint32; + Rdev int32; + Pad0 [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 Dirent struct { + Ino uint64; + Seekoff uint64; + Reclen uint16; + Namlen uint16; + Type uint8; + Name [1024]int8; + Pad0 [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 RawSockaddr struct { + Len uint8; + Family uint8; + Data [14]int8; +} + +type RawSockaddrAny struct { + Addr RawSockaddr; + Pad [12]int8; +} + +type _Socklen uint32 + +type Linger struct { + Onoff int32; + Linger int32; +} + +type Kevent_t struct { + Ident uint64; + Filter int16; + Flags uint16; + Fflags uint32; + Data int64; + Udata *byte; +} + +type FdSet struct { + Bits [32]int32; +} diff --git a/src/pkg/syscall/ztypes_linux_386.go b/src/pkg/syscall/ztypes_linux_386.go new file mode 100644 index 000000000..c3a083762 --- /dev/null +++ b/src/pkg/syscall/ztypes_linux_386.go @@ -0,0 +1,297 @@ +// godefs -gsyscall -f-m32 types_linux.c types_linux_386.c + +// MACHINE GENERATED - DO NOT EDIT. + +package syscall + +// Constants +const ( + sizeofPtr = 0x4; + sizeofShort = 0x2; + sizeofInt = 0x4; + sizeofLong = 0x4; + sizeofLongLong = 0x8; + PathMax = 0x1000; + O_RDONLY = 0; + O_WRONLY = 0x1; + O_RDWR = 0x2; + O_APPEND = 0x400; + O_ASYNC = 0x2000; + O_CREAT = 0x40; + O_NOCTTY = 0x100; + O_NONBLOCK = 0x800; + O_SYNC = 0x1000; + O_TRUNC = 0x200; + O_CLOEXEC = 0; + F_GETFD = 0x1; + F_SETFD = 0x2; + F_GETFL = 0x3; + F_SETFL = 0x4; + FD_CLOEXEC = 0x1; + NAME_MAX = 0xff; + 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; + WNOHANG = 0x1; + WUNTRACED = 0x2; + WEXITED = 0x4; + WSTOPPED = 0x2; + WCONTINUED = 0x8; + WNOWAIT = 0x1000000; + AF_UNIX = 0x1; + AF_INET = 0x2; + AF_INET6 = 0xa; + SOCK_STREAM = 0x1; + SOCK_DGRAM = 0x2; + SOCK_RAW = 0x3; + SOCK_SEQPACKET = 0x5; + SOL_SOCKET = 0x1; + SO_REUSEADDR = 0x2; + SO_KEEPALIVE = 0x9; + SO_DONTROUTE = 0x5; + SO_BROADCAST = 0x6; + SO_LINGER = 0xd; + SO_SNDBUF = 0x7; + SO_RCVBUF = 0x8; + SO_SNDTIMEO = 0x15; + SO_RCVTIMEO = 0x14; + IPPROTO_TCP = 0x6; + IPPROTO_UDP = 0x11; + TCP_NODELAY = 0x1; + SOMAXCONN = 0x80; + SizeofSockaddrInet4 = 0x10; + SizeofSockaddrInet6 = 0x1c; + SizeofSockaddrAny = 0x1c; + SizeofSockaddrUnix = 0x6e; + EPOLLIN = 0x1; + EPOLLRDHUP = 0x2000; + EPOLLOUT = 0x4; + EPOLLONESHOT = 0x40000000; + EPOLL_CTL_MOD = 0x3; + EPOLL_CTL_ADD = 0x1; + EPOLL_CTL_DEL = 0x2; +) + +// Types + +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; + int32; + int32; + int32; + int32; + int32; + int32; + int32; + int32; + int32; + int32; + int32; + 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 uint32; + Max uint32; +} + +type _C_int int32 + +type _Gid_t uint32 + +type Stat_t struct { + Dev uint64; + __pad1 uint16; + Pad0 [2]byte; + Ino uint32; + Mode uint32; + Nlink uint32; + Uid uint32; + Gid uint32; + Rdev uint64; + __pad2 uint16; + Pad1 [2]byte; + Size int32; + Blksize int32; + Blocks int32; + Atim Timespec; + Mtim Timespec; + Ctim Timespec; + __unused4 uint32; + __unused5 uint32; +} + +type Statfs_t struct { + Type int32; + Bsize int32; + Blocks uint32; + Bfree uint32; + Bavail uint32; + Files uint32; + Ffree uint32; + Fsid [8]byte /* __fsid_t */; + Namelen int32; + Frsize int32; + Spare [5]int32; +} + +type Dirent struct { + Ino uint32; + Off int32; + Reclen uint16; + Type uint8; + Name [256]int8; + Pad0 [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 RawSockaddr struct { + Family uint16; + Data [14]int8; +} + +type RawSockaddrAny struct { + Addr RawSockaddr; + Pad [12]int8; +} + +type _Socklen uint32 + +type Linger struct { + Onoff int32; + Linger int32; +} + +type FdSet struct { + __fds_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; + _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..f17ebe139 --- /dev/null +++ b/src/pkg/syscall/ztypes_linux_amd64.go @@ -0,0 +1,300 @@ +// godefs -gsyscall -f-m64 types_linux.c types_linux_amd64.c + +// MACHINE GENERATED - DO NOT EDIT. + +package syscall + +// Constants +const ( + sizeofPtr = 0x8; + sizeofShort = 0x2; + sizeofInt = 0x4; + sizeofLong = 0x8; + sizeofLongLong = 0x8; + PathMax = 0x1000; + O_RDONLY = 0; + O_WRONLY = 0x1; + O_RDWR = 0x2; + O_APPEND = 0x400; + O_ASYNC = 0x2000; + O_CREAT = 0x40; + O_NOCTTY = 0x100; + O_NONBLOCK = 0x800; + O_SYNC = 0x1000; + O_TRUNC = 0x200; + O_CLOEXEC = 0; + F_GETFD = 0x1; + F_SETFD = 0x2; + F_GETFL = 0x3; + F_SETFL = 0x4; + FD_CLOEXEC = 0x1; + NAME_MAX = 0xff; + 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; + WNOHANG = 0x1; + WUNTRACED = 0x2; + WEXITED = 0x4; + WSTOPPED = 0x2; + WCONTINUED = 0x8; + WNOWAIT = 0x1000000; + AF_UNIX = 0x1; + AF_INET = 0x2; + AF_INET6 = 0xa; + SOCK_STREAM = 0x1; + SOCK_DGRAM = 0x2; + SOCK_RAW = 0x3; + SOCK_SEQPACKET = 0x5; + SOL_SOCKET = 0x1; + SO_REUSEADDR = 0x2; + SO_KEEPALIVE = 0x9; + SO_DONTROUTE = 0x5; + SO_BROADCAST = 0x6; + SO_LINGER = 0xd; + SO_SNDBUF = 0x7; + SO_RCVBUF = 0x8; + SO_SNDTIMEO = 0x15; + SO_RCVTIMEO = 0x14; + IPPROTO_TCP = 0x6; + IPPROTO_UDP = 0x11; + TCP_NODELAY = 0x1; + SOMAXCONN = 0x80; + SizeofSockaddrInet4 = 0x10; + SizeofSockaddrInet6 = 0x1c; + SizeofSockaddrAny = 0x1c; + SizeofSockaddrUnix = 0x6e; + EPOLLIN = 0x1; + EPOLLRDHUP = 0x2000; + EPOLLOUT = 0x4; + EPOLLONESHOT = 0x40000000; + EPOLL_CTL_MOD = 0x3; + EPOLL_CTL_ADD = 0x1; + EPOLL_CTL_DEL = 0x2; +) + +// Types + +type Timespec struct { + Sec int64; + Nsec int64; +} + +type Timeval struct { + Sec int64; + Usec int64; +} + +type Timex struct { + Modes uint32; + Pad0 [4]byte; + Offset int64; + Freq int64; + Maxerror int64; + Esterror int64; + Status int32; + Pad1 [4]byte; + Constant int64; + Precision int64; + Tolerance int64; + Time Timeval; + Tick int64; + Ppsfreq int64; + Jitter int64; + Shift int32; + Pad2 [4]byte; + Stabil int64; + Jitcnt int64; + Calcnt int64; + Errcnt int64; + Stbcnt int64; + int32; + int32; + int32; + int32; + int32; + int32; + int32; + int32; + int32; + int32; + int32; + 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 _C_int int32 + +type _Gid_t uint32 + +type Stat_t struct { + Dev uint64; + Ino uint64; + Nlink uint64; + Mode uint32; + Uid uint32; + Gid uint32; + Pad0 int32; + Rdev uint64; + Size int64; + Blksize int64; + Blocks int64; + Atim Timespec; + Mtim Timespec; + Ctim Timespec; + __unused [3]int64; +} + +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; + Pad0 [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 RawSockaddr struct { + Family uint16; + Data [14]int8; +} + +type RawSockaddrAny struct { + Addr RawSockaddr; + Pad [12]int8; +} + +type _Socklen uint32 + +type Linger struct { + Onoff int32; + Linger int32; +} + +type FdSet struct { + __fds_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; + Pad0 [4]byte; + Totalhigh uint64; + Freehigh uint64; + Unit uint32; + _f [2]int8; + Pad1 [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; + Pad0 [4]byte; + Tinode uint64; + Fname [6]int8; + Fpack [6]int8; + Pad1 [4]byte; +} + +type EpollEvent struct { + Events uint32; + Fd int32; + Pad int32; +} diff --git a/src/pkg/tabwriter/Makefile b/src/pkg/tabwriter/Makefile new file mode 100644 index 000000000..1c4518066 --- /dev/null +++ b/src/pkg/tabwriter/Makefile @@ -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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D= + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + tabwriter.$O\ + + +phases: a1 +_obj$D/tabwriter.a: phases + +a1: $(O1) + $(AR) grc _obj$D/tabwriter.a tabwriter.$O + rm -f $(O1) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/tabwriter.a + +$(O1): newpkg +$(O2): a1 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/tabwriter.a + +packages: _obj$D/tabwriter.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/tabwriter.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/tabwriter.a diff --git a/src/pkg/tabwriter/tabwriter.go b/src/pkg/tabwriter/tabwriter.go new file mode 100644 index 000000000..6799f72d1 --- /dev/null +++ b/src/pkg/tabwriter/tabwriter.go @@ -0,0 +1,437 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// The tabwriter package implements a write filter (tabwriter.Writer) +// that translates tabbed columns in input into properly aligned text, +// using the Elastic Tabstops algorithm described at +// http://nickgravgaard.com/elastictabstops/index.html. +// +package tabwriter + +import ( + "container/vector"; + "io"; + "os"; + "utf8"; +) + + +// ---------------------------------------------------------------------------- +// Filter implementation + +// 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 tab-terminated cells. 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. Note that cells are tab-terminated, +// not tab-separated: trailing non-tab text at the end of a line +// is not part of any cell. +// +// The Writer assumes that all characters have the same width; +// this may not be true in some fonts, especially with certain +// UTF-8 characters. +// +// If a Writer is configured to filter HTML, HTML tags and entities +// are simply passed through and their widths are assumed to be zero +// for formatting purposes. +// +// The form feed 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, form feed 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; + cellwidth int; + padding int; + padbytes [8]byte; + flags uint; + + // current state + html_char byte; // terminating char of html tag/entity, or 0 ('>', ';', or 0) + buf io.ByteBuffer; // collected text w/o tabs, newlines, or form feed chars + size int; // size of incomplete cell in bytes + width int; // width of incomplete cell in runes up to buf[pos] w/o ignored sections + pos int; // buffer position up to which width of incomplete cell has been computed + lines_size vector.Vector; // list of lines; each line is a list of cell sizes in bytes + lines_width vector.Vector; // list of lines; each line is a list of cell widths in runes + widths vector.IntVector; // list of column widths in runes - re-used during formatting +} + + +// Internal representation (current state): +// +// - all text written is appended to buf; form feed chars, tabs and newlines are stripped away +// - at any given time there is a (possibly empty) incomplete cell at the end +// (the cell starts after a tab or newline) +// - size is the number of bytes belonging to the cell so far +// - 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_size and +// lines_width arrays, which contain an array of sizes or widths for each line +// - the widths array is a temporary array with current widths used during +// formatting; it is kept in Writer because it's re-used +// +// |<---------- size ---------->| +// | | +// |<- width ->|<- ignored ->| | +// | | | | +// [---processed---tab------------......] +// ^ ^ ^ +// | | | +// buf start of incomplete cell pos + + +func (b *Writer) addLine() { + b.lines_size.Push(vector.NewIntVector(0)); + b.lines_width.Push(vector.NewIntVector(0)); +} + + +// 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 = 1 << iota; + + // Force right-alignment of cell content. + // Default is left-alignment. + AlignRight; +) + + +// A Writer must be initialized with a call to Init. The first parameter (output) +// specifies the filter output. The remaining parameters control the formatting: +// +// cellwidth minimal cell width +// padding additional cell padding +// padchar ASCII char used for padding +// if padchar == '\t', the Writer will assume that the +// width of a '\t' in the formatted output is cellwidth, +// and cells are left-aligned independent of align_left +// (for correct-looking results, cellwidth must correspond +// to the tab width in the viewer displaying the result) +// flags formatting control +// +func (b *Writer) Init(output io.Writer, cellwidth, padding int, padchar byte, flags uint) *Writer { + if cellwidth < 0 { + panic("negative cellwidth"); + } + if padding < 0 { + panic("negative padding"); + } + b.output = output; + b.cellwidth = cellwidth; + b.padding = padding; + for i := len(b.padbytes) - 1; i >= 0; i-- { + b.padbytes[i] = padchar; + } + if padchar == '\t' { + // tab enforces left-alignment + flags &^= AlignRight; + } + b.flags = flags; + + b.lines_size.Init(0); + b.lines_width.Init(0); + b.widths.Init(0); + b.addLine(); // the very first line + + return b; +} + + +func (b *Writer) line(i int) (*vector.IntVector, *vector.IntVector) { + return + b.lines_size.At(i).(*vector.IntVector), + b.lines_width.At(i).(*vector.IntVector); +} + + +// debugging support (keep code around) +/* +func (b *Writer) dump() { + pos := 0; + for i := 0; i < b.lines_size.Len(); i++ { + line_size, line_width := b.line(i); + print("(", i, ") "); + for j := 0; j < line_size.Len(); j++ { + s := line_size.At(j); + print("[", string(b.buf.slice(pos, pos + s)), "]"); + pos += s; + } + print("\n"); + } + print("\n"); +} +*/ + + +func (b *Writer) write0(buf []byte) os.Error { + n, err := b.output.Write(buf); + if n != len(buf) && err == nil { + err = os.EIO; + } + return err; +} + + +var newline = []byte{'\n'} + +func (b *Writer) writePadding(textw, cellw int) os.Error { + if b.padbytes[0] == '\t' { + // make cell width a multiple of cellwidth + cellw = ((cellw + b.cellwidth - 1) / b.cellwidth) * b.cellwidth; + } + + n := cellw - textw; + if n < 0 { + panic("internal error"); + } + + if b.padbytes[0] == '\t' { + n = (n + b.cellwidth - 1) / b.cellwidth; + } + + for n > len(b.padbytes) { + if err := b.write0(&b.padbytes); err != nil { + return err; + } + n -= len(b.padbytes); + } + + return b.write0(b.padbytes[0 : n]); +} + + +func (b *Writer) writeLines(pos0 int, line0, line1 int) (int, os.Error) { + pos := pos0; + for i := line0; i < line1; i++ { + line_size, line_width := b.line(i); + for j := 0; j < line_size.Len(); j++ { + s, w := line_size.At(j), line_width.At(j); + + switch { + default: // align left + + if err := b.write0(b.buf.Data()[pos : pos + s]); err != nil { + return pos, err; + } + pos += s; + if j < b.widths.Len() { + if err := b.writePadding(w, b.widths.At(j)); err != nil { + return pos, err; + } + } + + case b.flags & AlignRight != 0: // align right + + if j < b.widths.Len() { + if err := b.writePadding(w, b.widths.At(j)); err != nil { + return pos, err; + } + } + if err := b.write0(b.buf.Data()[pos : pos + s]); err != nil { + return pos, err; + } + pos += s; + } + } + + if i+1 == b.lines_size.Len() { + // last buffered line - we don't have a newline, so just write + // any outstanding buffered data + if err := b.write0(b.buf.Data()[pos : pos + b.size]); err != nil { + return pos, err; + } + pos += b.size; + } else { + // not the last line - write newline + if err := b.write0(newline); err != nil { + return pos, err; + } + } + } + return pos, nil; +} + + +func (b *Writer) format(pos0 int, line0, line1 int) (pos int, err os.Error) { + pos = pos0; + column := b.widths.Len(); + last := line0; + for this := line0; this < line1; this++ { + line_size, line_width := b.line(this); + + if column < line_size.Len() - 1 { + // cell exists in this column + // (note that the last cell per line is ignored) + + // print unprinted lines until beginning of block + pos, err = b.writeLines(pos, last, this); + if err != nil { + return pos, err; + } + last = this; + + // column block begin + width := b.cellwidth; // minimal width + for ; this < line1; this++ { + line_size, line_width = b.line(this); + if column < line_size.Len() - 1 { + // cell exists in this column => update width + w := line_width.At(column) + b.padding; + if w > width { + width = w; + } + } else { + break + } + } + // column block end + + // format and print all columns to the right of this column + // (we know the widths of this column and all columns to the left) + b.widths.Push(width); + pos, err = b.format(pos, last, this); + b.widths.Pop(); + last = this; + } + } + + // print unprinted lines until end + return b.writeLines(pos, last, line1); +} + + +// Flush should be called after the last call to Write to ensure +// that any data buffered in the Writer is written to output. +// +func (b *Writer) Flush() os.Error { + _, err := b.format(0, 0, b.lines_size.Len()); + // reset (even in the presence of errors) + b.buf.Reset(); + b.size, b.width = 0, 0; + b.pos = 0; + b.lines_size.Init(0); + b.lines_width.Init(0); + b.addLine(); + return err; +} + + +func unicodeLen(buf []byte) int { + l := 0; + for i := 0; i < len(buf); { + if buf[i] < utf8.RuneSelf { + i++; + } else { + rune, size := utf8.DecodeRune(buf[i : len(buf)]); + i += size; + } + l++; + } + return l; +} + + +func (b *Writer) append(buf []byte) { + b.buf.Write(buf); + b.size += len(buf); +} + + +// 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) (written int, err os.Error) { + i0, n := 0, len(buf); + + // split text into cells + for i := 0; i < n; i++ { + ch := buf[i]; + + if b.html_char == 0 { + // outside html tag/entity + switch ch { + case '\t', '\n', '\f': + b.append(buf[i0 : i]); + i0 = i + 1; // exclude ch from (next) cell + b.width += unicodeLen(b.buf.Data()[b.pos : b.buf.Len()]); + b.pos = b.buf.Len(); + + // terminate cell + last_size, last_width := b.line(b.lines_size.Len() - 1); + last_size.Push(b.size); + last_width.Push(b.width); + b.size, b.width = 0, 0; + + if ch != '\t' { + // terminate line + b.addLine(); + if ch == '\f' || last_size.Len() == 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 i0, err; + } + } + } + + case '<', '&': + if b.flags & FilterHTML != 0 { + b.append(buf[i0 : i]); + i0 = i; + b.width += unicodeLen(b.buf.Data()[b.pos : b.buf.Len()]); + b.pos = -1; // preventative - should not be used (will cause index out of bounds) + if ch == '<' { + b.html_char = '>'; + } else { + b.html_char = ';'; + } + } + } + + } else { + // inside html tag/entity + if ch == b.html_char { + // reached the end of tag/entity + b.append(buf[i0 : i + 1]); + i0 = i + 1; + if b.html_char == ';' { + b.width++; // count as one char + } + b.pos = b.buf.Len(); + b.html_char = 0; + } + } + } + + // append leftover text + b.append(buf[i0 : n]); + return n, nil; +} + + +// NewWriter allocates and initializes a new tabwriter.Writer. +// The parameters are the same as for the the Init function. +// +func NewWriter(output io.Writer, cellwidth, padding int, padchar byte, flags uint) *Writer { + return new(Writer).Init(output, cellwidth, 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..7026446e6 --- /dev/null +++ b/src/pkg/tabwriter/tabwriter_test.go @@ -0,0 +1,380 @@ +// Copyright 2009 The Go Authors. 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"; + "tabwriter"; + "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 { + panicln("buffer too small", n, m, cap(b.a)); + } + return len(buf), nil; +} + + +func (b *buffer) String() string { + return string(b.a); +} + + +func write(t *testing.T, w *tabwriter.Writer, src string) { + written, err := io.WriteString(w, src); + if err != nil { + t.Errorf("--- src:\n%s\n--- write error: %v\n", src, err); + } + if written != len(src) { + t.Errorf("--- src:\n%s\n--- written = %d, len(src) = %d\n", src, written, len(src)); + } +} + + +func verify(t *testing.T, w *tabwriter.Writer, b *buffer, src, expected string) { + err := w.Flush(); + if err != nil { + t.Errorf("--- src:\n%s\n--- flush error: %v\n", src, err); + } + + res := b.String(); + if res != expected { + t.Errorf("--- src:\n%s\n--- found:\n%s\n--- expected:\n%s\n", src, res, expected) + } +} + + +func check(t *testing.T, tabwidth, padding int, padchar byte, flags uint, src, expected string) { + var b buffer; + b.init(1000); + + var w tabwriter.Writer; + w.Init(&b, tabwidth, padding, padchar, flags); + + // write all at once + b.clear(); + write(t, &w, src); + verify(t, &w, &b, src, expected); + + // write byte-by-byte + b.clear(); + for i := 0; i < len(src); i++ { + write(t, &w, src[i : i+1]); + } + verify(t, &w, &b, src, expected); + + // write using Fibonacci slice sizes + b.clear(); + for i, d := 0, 0; i < len(src); { + write(t, &w, src[i : i+d]); + i, d = i+d, d+1; + if i+d > len(src) { + d = len(src) - i; + } + } + verify(t, &w, &b, src, expected); +} + + +type entry struct { + tabwidth, padding int; + padchar byte; + flags uint; + src, expected string; +} + + +var tests = []entry { + entry{ + 8, 1, '.', 0, + "", + "" + }, + + entry{ + 8, 1, '.', 0, + "\n\n\n", + "\n\n\n" + }, + + entry{ + 8, 1, '.', 0, + "a\nb\nc", + "a\nb\nc" + }, + + entry{ + 8, 1, '.', 0, + "\t", // '\t' terminates an empty cell on last line - nothing to print + "" + }, + + entry{ + 8, 1, '.', tabwriter.AlignRight, + "\t", // '\t' terminates an empty cell on last line - nothing to print + "" + }, + + entry{ + 8, 1, '.', 0, + "*\t*", + "**" + }, + + entry{ + 8, 1, '.', 0, + "*\t*\n", + "*.......*\n" + }, + + entry{ + 8, 1, '.', 0, + "*\t*\t", + "*.......*" + }, + + entry{ + 8, 1, '.', tabwriter.AlignRight, + "*\t*\t", + ".......**" + }, + + entry{ + 8, 1, '.', 0, + "\t\n", + "........\n" + }, + + entry{ + 8, 1, '.', 0, + "a) foo", + "a) foo" + }, + + entry{ + 8, 1, ' ', 0, + "b) foo\tbar", // "bar" is not in any cell - not formatted, just flushed + "b) foobar" + }, + + entry{ + 8, 1, '.', 0, + "c) foo\tbar\t", + "c) foo..bar" + }, + + entry{ + 8, 1, '.', 0, + "d) foo\tbar\n", + "d) foo..bar\n" + }, + + entry{ + 8, 1, '.', 0, + "e) foo\tbar\t\n", + "e) foo..bar.....\n" + }, + + entry{ + 8, 1, '.', tabwriter.FilterHTML, + "f) f<o\tbar\t\n", + "f) f<o..bar.....\n" + }, + + entry{ + 8, 1, '*', 0, + "Hello, world!\n", + "Hello, world!\n" + }, + + entry{ + 0, 0, '.', 0, + "1\t2\t3\t4\n" + "11\t222\t3333\t44444\n", + + "1.2..3...4\n" + "11222333344444\n" + }, + + entry{ + 0, 0, '.', tabwriter.FilterHTML, + "1\t2\t3\t4\n" // \f inside HTML is ignored + "11\t222\t3333\t44444\n", + + "1.2..3...4\n" + "11222333344444\n" + }, + + entry{ + 0, 0, '.', 0, + "1\t2\t3\t4\f" // \f causes a newline and flush + "11\t222\t3333\t44444\n", + + "1234\n" + "11222333344444\n" + }, + + entry{ + 5, 0, '.', 0, + "1\t2\t3\t4\n", + "1....2....3....4\n" + }, + + entry{ + 5, 0, '.', 0, + "1\t2\t3\t4\t\n", + "1....2....3....4....\n" + }, + + entry{ + 8, 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" + }, + + entry{ + 8, 1, ' ', tabwriter.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" + }, + + entry{ + 2, 0, ' ', 0, + "a\tb\tc\n" + "aa\tbbb\tcccc\n" + "aaa\tbbbb\n", + + "a b c\n" + "aa bbbcccc\n" + "aaabbbb\n" + }, + + entry{ + 8, 1, '_', 0, + "a\tb\tc\n" + "aa\tbbb\tcccc\n" + "aaa\tbbbb\n", + + "a_______b_______c\n" + "aa______bbb_____cccc\n" + "aaa_____bbbb\n" + }, + + entry{ + 4, 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" + }, + + entry{ + 4, 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" + }, + + entry{ + 8, 1, '\t', tabwriter.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\t999999999\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\t999999999\t0000000000\n" + }, + + entry{ + 0, 2, ' ', tabwriter.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" + }, +} + + +func Test(t *testing.T) { + for _, e := range tests { + check(t, 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..e91c08818 --- /dev/null +++ b/src/pkg/template/Makefile @@ -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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D= + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + format.$O\ + +O2=\ + template.$O\ + + +phases: a1 a2 +_obj$D/template.a: phases + +a1: $(O1) + $(AR) grc _obj$D/template.a format.$O + rm -f $(O1) + +a2: $(O2) + $(AR) grc _obj$D/template.a template.$O + rm -f $(O2) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/template.a + +$(O1): newpkg +$(O2): a1 +$(O3): a2 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/template.a + +packages: _obj$D/template.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/template.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/template.a diff --git a/src/pkg/template/format.go b/src/pkg/template/format.go new file mode 100644 index 000000000..4fb5393b9 --- /dev/null +++ b/src/pkg/template/format.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. + +// Template library: default formatters + +package template + +import ( + "fmt"; + "io"; + "reflect"; +) + +// 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, value interface{}, format string) { + fmt.Fprint(w, value); +} + + +var esc_amp = io.StringBytes("&") +var esc_lt = io.StringBytes("<") +var esc_gt = io.StringBytes(">") + +// HtmlEscape writes to w the properly escaped HTML equivalent +// of the plain text data s. +func HtmlEscape(w io.Writer, s []byte) { + last := 0; + for i, c := range s { + if c == '&' || c == '<' || c == '>' { + w.Write(s[last:i]); + switch c { + case '&': + w.Write(esc_amp); + case '<': + w.Write(esc_lt); + case '>': + w.Write(esc_gt); + } + last = i+1; + } + } + w.Write(s[last:len(s)]); +} + +// HtmlFormatter formats arbitrary values for HTML +func HtmlFormatter(w io.Writer, value interface{}, format string) { + var b io.ByteBuffer; + fmt.Fprint(&b, value); + HtmlEscape(w, b.Data()); +} diff --git a/src/pkg/template/template.go b/src/pkg/template/template.go new file mode 100644 index 000000000..a5e9b0c7d --- /dev/null +++ b/src/pkg/template/template.go @@ -0,0 +1,808 @@ +// Copyright 2009 The Go 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. See + http://code.google.com/p/json-template/wiki/Reference + for full documentation of the template language. A summary: + + 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) 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. + + Major constructs ({} are metacharacters; [] marks optional elements): + + {# comment } + + A one-line comment. + + {.section field} XXX [ {.or} YYY ] {.end} + + Set @ to the value of the field. It may be an explicit @ + to stay at the same point in the data. If the field is nil + or empty, execute YYY; otherwise execute XXX. + + {.repeated section field} XXX [ {.alternates with} ZZZ ] [ {.or} YYY ] {.end} + + Like .section, but field must be an array or slice. XXX + is executed for each element. If the array is nil or empty, + YYY is executed instead. If the {.alternates with} marker + is present, ZZZ is executed between iterations of XXX. + + {field} + {field|formatter} + + Insert the value of the field into the output. Field is + first looked for in the cursor, as in .section and .repeated. + If it is not found, the search continues in outer sections + until the top level is reached. + + If a formatter is specified, it must be named in the formatter + map passed to the template set up routines or in the default + set ("html","str","") and is used to process the data for + output. The formatter function has signature + func(wr io.Write, data interface{}, formatter string) + where wr is the destination for output, data is the field + value, and formatter is its name at the invocation site. +*/ +package template + +import ( + "container/vector"; + "fmt"; + "io"; + "os"; + "reflect"; + "runtime"; + "strings"; + "template"; +) + +// 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, interface{}, string) + +// 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 to be evaluated +type variableElement struct { + linenum int; + name string; + formatter string; // TODO(r): implement pipelines +} + +// A .section block, possibly with a .or +type sectionElement struct { + linenum int; // of .section itself + field string; // cursor field for this block + start int; // first element + or int; // first element of .or block + end int; // one beyond last element +} + +// A .repeated block, possibly with a .or and a .alternates +type repeatedElement struct { + sectionElement; // It has the same structure... + altstart int; // ... except for alternates + altend int; +} + +// Template is the type that represents a template definition. +// It is unchanged after parsing. +type Template struct { + fmap FormatterMap; // formatters for variables + // Used during parsing: + ldelim, rdelim []byte; // delimiters; default {} + buf []byte; // input text to process + p int; // position in buf + linenum int; // position in input + errors chan os.Error; // for error reporting during parsing (only) + // 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 + errors chan os.Error; // for reporting errors during execute +} + +func (parent *state) clone(data reflect.Value) *state { + return &state{parent, data, parent.wr, parent.errors} +} + +// 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.errors = make(chan os.Error); + t.elems = vector.New(0); + return t; +} + +// Generic error handler, called only from execError or parseError. +func error(errors chan os.Error, line int, err string, args ...) { + errors <- &Error{line, fmt.Sprintf(err, args)}; + runtime.Goexit(); +} + +// Report error and stop executing. The line number must be provided explicitly. +func (t *Template) execError(st *state, line int, err string, args ...) { + error(st.errors, line, err, args); +} + +// Report error and stop parsing. The line number comes from the template state. +func (t *Template) parseError(err string, args ...) { + error(t.errors, t.linenum, err, args) +} + +// -- 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:len(s)]; + 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 the white space on +// either side, up to and including the newline. +func (t *Template) nextItem() []byte { + sawLeft := false; // are we waiting for an opening delimiter? + special := false; // is this a {.foo} directive, which means trim white space? + // Delete surrounding white space if this {.foo} is the only thing on the line. + trim_white := t.p == 0 || t.buf[t.p-1] == '\n'; + only_white := true; // we have seen only white space so far + var i int; + start := t.p; +Loop: + for i = t.p; i < len(t.buf); i++ { + switch { + case t.buf[i] == '\n': + t.linenum++; + i++; + break Loop; + case white(t.buf[i]): + // white space, do nothing + case !sawLeft && equal(t.buf, i, t.ldelim): // sawLeft checked because delims may be equal + // anything interesting already on the line? + if !only_white { + break Loop; + } + // is it a directive or comment? + j := i + len(t.ldelim); // position after delimiter + if j+1 < len(t.buf) && (t.buf[j] == '.' || t.buf[j] == '#') { + special = true; + if trim_white && only_white { + start = i; + } + } else if i > t.p { // have some text accumulated so stop before delimiter + break Loop; + } + sawLeft = true; + i = j - 1; + case equal(t.buf, i, t.rdelim): + if !sawLeft { + t.parseError("unmatched closing delimiter") + } + sawLeft = false; + i += len(t.rdelim); + break Loop; + default: + only_white = false; + } + } + if sawLeft { + t.parseError("unmatched opening delimiter") + } + item := t.buf[start:i]; + if special && trim_white { + // consume trailing white space + for ; i < len(t.buf) && white(t.buf[i]); i++ { + if t.buf[i] == '\n' { + i++; + break // stop after newline + } + } + } + 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 + } + if i == cap(s) { + ns := make([]string, 2*cap(s)); + for j := range s { + ns[j] = s[j] + } + s = ns; + } + s = s[0:i+1]; + s[i] = string(buf[start:p]) + } + 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 + } + if len(item) <= len(t.ldelim)+len(t.rdelim) { // no contents + t.parseError("empty directive") + } + // 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") + } + if len(w) == 1 && 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) + } + tok = tokSection; + return; + case ".repeated": + if len(w) != 3 || w[1] != "section" { + t.parseError("incorrect fields for .repeated: %s", item) + } + tok = tokRepeated; + return; + case ".alternates": + if len(w) != 2 || w[1] != "with" { + t.parseError("incorrect fields for .alternates: %s", item) + } + tok = tokAlternates; + return; + } + t.parseError("bad directive: %s", item); + return +} + +// -- Parsing + +// Allocate a new variable-evaluation element. +func (t *Template) newVariable(name_formatter string) (v *variableElement) { + name := name_formatter; + formatter := ""; + bar := strings.Index(name_formatter, "|"); + if bar >= 0 { + name = name_formatter[0:bar]; + formatter = name_formatter[bar+1:len(name_formatter)]; + } + // Probably ok, so let's build it. + v = &variableElement{t.linenum, name, formatter}; + + // We could remember the function address here and avoid the lookup later, + // but it's more dynamic to let the user change the map contents underfoot. + // We do require the name to be present, though. + + // Is it in user-supplied map? + if t.fmap != nil { + if fn, ok := t.fmap[formatter]; ok { + return + } + } + // Is it in builtin map? + if fn, ok := builtins[formatter]; ok { + return + } + t.parseError("unknown formatter: %s", formatter); + return +} + +// Grab the next item. If it's simple, just append it to the template. +// Otherwise return its details. +func (t *Template) parseSimple(item []byte) (done bool, tok int, w []string) { + tok, w = t.analyze(item); + done = true; // assume for simplicity + switch tok { + case tokComment: + return; + case tokText: + t.elems.Push(&textElement{item}); + return; + case tokLiteral: + switch w[0] { + case ".meta-left": + t.elems.Push(&literalElement{t.ldelim}); + case ".meta-right": + t.elems.Push(&literalElement{t.rdelim}); + case ".space": + t.elems.Push(&literalElement{space}); + case ".tab": + t.elems.Push(&literalElement{tab}); + default: + t.parseError("internal error: unknown literal: %s", w[0]); + } + return; + case tokVariable: + t.elems.Push(t.newVariable(w[0])); + return; + } + return false, tok, w +} + +// parseSection and parseRepeated are mutually recursive +func (t *Template) parseSection(words []string) *sectionElement + +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") + } + 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"); + } + 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"); + } + if r.or >= 0 { + t.parseError(".alternates inside .or block in .repeated section"); + } + r.altstart = t.elems.Len(); + default: + t.parseError("internal error: unknown repeated section item: %s", item); + } + } + 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") + } + 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"); + } + 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 + +// If the data for this template is a struct, find the named variable. +// The special name "@" (the "cursor") denotes the current data. +func (st *state) findVar(s string) reflect.Value { + if s == "@" { + return st.data + } + data := reflect.Indirect(st.data); + typ, ok := data.Type().(reflect.StructType); + if ok { + for i := 0; i < typ.Len(); i++ { + name, ftyp, tag, offset := typ.Field(i); + if name == s { + return data.(reflect.StructValue).Field(i) + } + } + } + return nil +} + +// Is there no data to look at? +func empty(v reflect.Value, indirect_ok bool) bool { + v = reflect.Indirect(v); + if v == nil { + return true + } + switch v.Type().Kind() { + case reflect.StringKind: + return v.(reflect.StringValue).Get() == ""; + case reflect.StructKind: + return false; + case reflect.ArrayKind: + return v.(reflect.ArrayValue).Len() == 0; + } + return true; +} + +// Look up a variable, up through the parent if necessary. +func (t *Template) varValue(v *variableElement, st *state) reflect.Value { + field := st.findVar(v.name); + if field == nil { + if st.parent == nil { + t.execError(st, t.linenum, "name not found: %s", v.name) + } + return t.varValue(v, st.parent); + } + return field; +} + +// Evaluate a variable, looking up through the parent if necessary. +// If it has a formatter attached ({var|formatter}) run that too. +func (t *Template) writeVariable(v *variableElement, st *state) { + formatter := v.formatter; + val := t.varValue(v, st).Interface(); + // is it in user-supplied map? + if t.fmap != nil { + if fn, ok := t.fmap[v.formatter]; ok { + fn(st.wr, val, v.formatter); + return; + } + } + // is it in builtin map? + if fn, ok := builtins[v.formatter]; ok { + fn(st.wr, val, v.formatter); + return; + } + t.execError(st, v.linenum, "missing formatter %s for variable %s", v.formatter, v.name) +} + +// execute{|Element|Section|Repeated} are mutually recursive +func (t *Template) executeSection(s *sectionElement, st *state) +func (t *Template) executeRepeated(r *repeatedElement, st *state) + +// 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 := st.findVar(s.field); + if field == nil { + t.execError(st, s.linenum, ".section: cannot find field %s in %s", s.field, reflect.Indirect(st.data).Type()); + } + st = st.clone(field); + start, end := s.start, s.or; + if !empty(field, true) { + // 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) + } +} + +// 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 := st.findVar(r.field); + if field == nil { + t.execError(st, r.linenum, ".repeated: cannot find field %s in %s", r.field, reflect.Indirect(st.data).Type()); + } + field = reflect.Indirect(field); + + // Must be an array/slice + if field != nil && field.Kind() != reflect.ArrayKind { + t.execError(st, r.linenum, ".repeated: %s has bad type %s", r.field, field.Type()); + } + if empty(field, true) { + // 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 + } + // Execute the normal block. + start, end := r.start, r.or; + if end < 0 { + end = r.end + } + if r.altstart >= 0 { + end = r.altstart + } + if field != nil { + array := field.(reflect.ArrayValue); + for j := 0; j < array.Len(); j++ { + newst := st.clone(array.Elem(j)); + for i := start; i < end; { + i = t.executeElement(i, newst) + } + // If appropriate, do .alternates between elements + if j < array.Len() - 1 && r.altstart >= 0 { + for i := r.altstart; i < r.altend; i++ { + i = t.executeElement(i, newst) + } + } + } + } +} + +// A valid delimiter must contain no white space and be non-empty. +func validDelim(d []byte) bool { + if len(d) == 0 { + return false + } + for i, c := range d { + if white(c) { + return false + } + } + return true; +} + +// -- 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) os.Error { + if !validDelim(t.ldelim) || !validDelim(t.rdelim) { + return &Error{1, fmt.Sprintf("bad delimiter strings %q %q", t.ldelim, t.rdelim)} + } + t.buf = io.StringBytes(s); + t.p = 0; + t.linenum = 0; + go func() { + t.parse(); + t.errors <- nil; // clean return; + }(); + return <-t.errors; +} + +// Execute applies a parsed template to the specified data object, +// generating output to wr. +func (t *Template) Execute(data interface{}, wr io.Writer) os.Error { + // Extract the driver data. + val := reflect.NewValue(data); + errors := make(chan os.Error); + go func() { + t.p = 0; + t.execute(0, t.elems.Len(), &state{nil, val, wr, errors}); + errors <- nil; // clean return; + }(); + return <-errors; +} + +// 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 = io.StringBytes(left); + t.rdelim = io.StringBytes(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); + return +} diff --git a/src/pkg/template/template_test.go b/src/pkg/template/template_test.go new file mode 100644 index 000000000..9a81d274c --- /dev/null +++ b/src/pkg/template/template_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. + +package template + +import ( + "fmt"; + "io"; + "os"; + "reflect"; + "template"; + "testing"; +) + +type Test struct { + in, out string +} + +type T struct { + item string; + value string; +} + +type S struct { + header string; + integer int; + raw string; + data []T; + pdata []*T; + empty []*T; + emptystring string; + null []*T; +} + +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, interface{}, string)) { + return func(w io.Writer, v interface{}, format string) { + io.WriteString(w, f(v)); + } +} + + +var formatters = FormatterMap { + "uppercase" : writer(uppercase), + "+1" : writer(plus1), +} + +var tests = []*Test { + // Simple + &Test{ "", "" }, + &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", "" }, + + // Variables at top level + &Test{ + "{header}={integer}\n", + + "Header=77\n" + }, + + // Section + &Test{ + "{.section data }\n" + "some text for the section\n" + "{.end}\n", + + "some text for the section\n" + }, + &Test{ + "{.section data }\n" + "{header}={integer}\n" + "{.end}\n", + + "Header=77\n" + }, + &Test{ + "{.section pdata }\n" + "{header}={integer}\n" + "{.end}\n", + + "Header=77\n" + }, + &Test{ + "{.section pdata }\n" + "data present\n" + "{.or}\n" + "data not present\n" + "{.end}\n", + + "data present\n" + }, + &Test{ + "{.section empty }\n" + "data present\n" + "{.or}\n" + "data not present\n" + "{.end}\n", + + "data not present\n" + }, + &Test{ + "{.section null }\n" + "data present\n" + "{.or}\n" + "data not present\n" + "{.end}\n", + + "data not present\n" + }, + &Test{ + "{.section pdata }\n" + "{header}={integer}\n" + "{.section @ }\n" + "{header}={integer}\n" + "{.end}\n" + "{.end}\n", + + "Header=77\n" + "Header=77\n" + }, + &Test{ + "{.section data}{.end} {header}\n", + + " Header\n" + }, + + // Repeated + &Test{ + "{.section pdata }\n" + "{.repeated section @ }\n" + "{item}={value}\n" + "{.end}\n" + "{.end}\n", + + "ItemNumber1=ValueNumber1\n" + "ItemNumber2=ValueNumber2\n" + }, + &Test{ + "{.section pdata }\n" + "{.repeated section @ }\n" + "{item}={value}\n" + "{.or}\n" + "this should not appear\n" + "{.end}\n" + "{.end}\n", + + "ItemNumber1=ValueNumber1\n" + "ItemNumber2=ValueNumber2\n" + }, + &Test{ + "{.section @ }\n" + "{.repeated section empty }\n" + "{item}={value}\n" + "{.or}\n" + "this should appear: empty field\n" + "{.end}\n" + "{.end}\n", + + "this should appear: empty field\n" + }, + &Test{ + "{.section pdata }\n" + "{.repeated section @ }\n" + "{item}={value}\n" + "{.alternates with}DIVIDER\n" + "{.or}\n" + "this should not appear\n" + "{.end}\n" + "{.end}\n", + + "ItemNumber1=ValueNumber1\n" + "DIVIDER\n" + "ItemNumber2=ValueNumber2\n" + }, + + // Formatters + &Test{ + "{.section pdata }\n" + "{header|uppercase}={integer|+1}\n" + "{header|html}={integer|str}\n" + "{.end}\n", + + "HEADER=78\n" + "Header=77\n" + }, + + &Test{ + "{raw}\n" + "{raw|html}\n", + + "&<>!@ #$%^\n" + "&<>!@ #$%^\n" + }, + + &Test{ + "{.section emptystring}emptystring{.end}\n" + "{.section header}header{.end}\n", + + "\nheader\n" + }, +} + +func TestAll(t *testing.T) { + s := new(S); + // initialized by hand for clarity. + s.header = "Header"; + s.integer = 77; + s.raw = "&<>!@ #$%^"; + s.data = []T{ t1, t2 }; + s.pdata = []*T{ &t1, &t2 }; + s.empty = []*T{ }; + s.null = nil; + + var buf io.ByteBuffer; + for i, test := range tests { + buf.Reset(); + tmpl, err := Parse(test.in, formatters); + if err != nil { + t.Error("unexpected parse error:", err); + continue; + } + err = tmpl.Execute(s, &buf); + if err != nil { + t.Error("unexpected execute error:", err) + } + if string(buf.Data()) != test.out { + t.Errorf("for %q: expected %q got %q", test.in, test.out, string(buf.Data())); + } + } +} + +func TestStringDriverType(t *testing.T) { + tmpl, err := Parse("template: {@}", nil); + if err != nil { + t.Error("unexpected parse error:", err) + } + var b io.ByteBuffer; + err = tmpl.Execute("hello", &b); + if err != nil { + t.Error("unexpected execute error:", err) + } + s := string(b.Data()); + if s != "template: hello" { + t.Errorf("failed passing string as data: expected %q got %q", "template: hello", s) + } +} + +func TestTwice(t *testing.T) { + tmpl, err := Parse("template: {@}", nil); + if err != nil { + t.Error("unexpected parse error:", err) + } + var b io.ByteBuffer; + err = tmpl.Execute("hello", &b); + if err != nil { + t.Error("unexpected parse error:", err) + } + s := string(b.Data()); + text := "template: hello"; + if s != text { + t.Errorf("failed passing string as data: expected %q got %q", text, s); + } + err = tmpl.Execute("hello", &b); + if err != nil { + t.Error("unexpected parse error:", err) + } + s = string(b.Data()); + text += text; + if s != text { + t.Errorf("failed passing string as data: expected %q got %q", text, s); + } +} + +func TestCustomDelims(t *testing.T) { + // try various lengths. zero should catch error. + for i := 0; i < 7; i++ { + for j := 0; j < 7; j++ { + tmpl := New(nil); + // first two chars deliberately the same to test equal left and right delims + ldelim := "$!#$%^&"[0:i]; + rdelim := "$*&^%$!"[0:j]; + tmpl.SetDelims(ldelim, rdelim); + // if braces, this would be template: {@}{.meta-left}{.meta-right} + text := "template: " + + ldelim + "@" + rdelim + + ldelim + ".meta-left" + rdelim + + ldelim + ".meta-right" + rdelim; + err := tmpl.Parse(text); + if err != nil { + if i == 0 || j == 0 { // expected + continue + } + t.Error("unexpected parse error:", err) + } else if i == 0 || j == 0 { + t.Errorf("expected parse error for empty delimiter: %d %d %q %q", i, j, ldelim, rdelim); + continue; + } + var b io.ByteBuffer; + err = tmpl.Execute("hello", &b); + s := string(b.Data()); + if s != "template: hello" + ldelim + rdelim { + t.Errorf("failed delim check(%q %q) %q got %q", ldelim, rdelim, text, s) + } + } + } +} diff --git a/src/pkg/testing/Makefile b/src/pkg/testing/Makefile new file mode 100644 index 000000000..493eba6f2 --- /dev/null +++ b/src/pkg/testing/Makefile @@ -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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D= + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + testing.$O\ + + +phases: a1 +_obj$D/testing.a: phases + +a1: $(O1) + $(AR) grc _obj$D/testing.a testing.$O + rm -f $(O1) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/testing.a + +$(O1): newpkg +$(O2): a1 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/testing.a + +packages: _obj$D/testing.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/testing.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/testing.a diff --git a/src/pkg/testing/iotest/Makefile b/src/pkg/testing/iotest/Makefile new file mode 100644 index 000000000..1d01041f5 --- /dev/null +++ b/src/pkg/testing/iotest/Makefile @@ -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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D=/testing/ + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + logger.$O\ + reader.$O\ + + +phases: a1 +_obj$D/iotest.a: phases + +a1: $(O1) + $(AR) grc _obj$D/iotest.a logger.$O reader.$O + rm -f $(O1) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/iotest.a + +$(O1): newpkg +$(O2): a1 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/iotest.a + +packages: _obj$D/iotest.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/iotest.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/iotest.a diff --git a/src/pkg/testing/iotest/logger.go b/src/pkg/testing/iotest/logger.go new file mode 100644 index 000000000..8ee574080 --- /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.Stdoutf("%s %x: %v", l.prefix, p[0:n], err); + } else { + log.Stdoutf("%s %x", l.prefix, p[0:n]); + } + return; +} + +// NewWriteLogger returns a writer that behaves like w except +// that it logs (using log.Stdout) each write to standard output, +// 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.Stdoutf("%s %x: %v", l.prefix, p[0:n], err); + } else { + log.Stdoutf("%s %x", l.prefix, p[0:n]); + } + return; +} + +// NewReadLogger returns a writer that behaves like w except +// that it logs (using log.Stdout) each write to standard output, +// 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..0bb863338 --- /dev/null +++ b/src/pkg/testing/iotest/reader.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. + +// The iotest package implements Readers and Writers +// useful only for testing. +package iotest + +import ( + "io"; + "os"; +) + +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]); +} + +// 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 halfReader struct { + r io.Reader; +} + +func (r *halfReader) Read(p []byte) (int, os.Error) { + return r.r.Read(p[0:(len(p)+1)/2]); +} + +// 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}; +} + diff --git a/src/pkg/testing/testing.go b/src/pkg/testing/testing.go new file mode 100644 index 000000000..330fadd3a --- /dev/null +++ b/src/pkg/testing/testing.go @@ -0,0 +1,155 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// The testing package provides support for automated testing of Go packages. +// It is intended to be used in concert with the ``gotest'' utility, which automates +// execution of any function of the form +// func TestXxx(*testing.T) +// where Xxx can by 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. +package testing + +import ( + "flag"; + "fmt"; + "os"; + "regexp"; + "runtime"; +) + +// Report as tests are run; default is silent for success. +var chatty = flag.Bool("v", false, "verbose: print additional output") +var match = flag.String("match", "", "regular expression to select tests to run") + + +// Insert final newline if needed and tabs after internal newlines. +func tabify(s string) string { + n := len(s); + if n > 0 && s[n-1] != '\n' { + s += "\n"; + n++; + } + for i := 0; i < n - 1; i++ { // -1 to avoid final newline + if s[i] == '\n' { + return s[0:i+1] + "\t" + tabify(s[i+1:n]); + } + } + return s +} + +// T is a type passed to Test functions to manage test state and support formatted test logs. +// Logs are accumulated during execution and dumped to standard error when done. +type T struct { + errors string; + failed bool; + ch chan *T; +} + +// Fail marks the Test function as having failed but continues execution. +func (t *T) Fail() { + t.failed = true +} + +// Failed returns whether the Test function has failed. +func (t *T) Failed() bool { + return t.failed +} + +// FailNow marks the Test function as having failed and stops its execution. +// Execution will continue at the next Test. +func (t *T) FailNow() { + t.Fail(); + t.ch <- t; + runtime.Goexit(); +} + +// Log formats its arguments using default formatting, analogous to Print(), +// and records the text in the error log. +func (t *T) Log(args ...) { + t.errors += "\t" + tabify(fmt.Sprintln(args)); +} + +// Log formats its arguments according to the format, analogous to Printf(), +// and records the text in the error log. +func (t *T) Logf(format string, args ...) { + t.errors += "\t" + tabify(fmt.Sprintf(format, args)); +} + +// Error is equivalent to Log() followed by Fail(). +func (t *T) Error(args ...) { + t.Log(args); + t.Fail(); +} + +// Errorf is equivalent to Logf() followed by Fail(). +func (t *T) Errorf(format string, args ...) { + t.Logf(format, args); + t.Fail(); +} + +// Fatal is equivalent to Log() followed by FailNow(). +func (t *T) Fatal(args ...) { + t.Log(args); + t.FailNow(); +} + +// Fatalf is equivalent to Logf() followed by FailNow(). +func (t *T) Fatalf(format string, args ...) { + t.Logf(format, args); + t.FailNow(); +} + +// An internal type but exported because it is cross-package; part of the implementation +// of gotest. +type Test struct { + Name string; + F func(*T); +} + +func tRunner(t *T, test *Test) { + test.F(t); + t.ch <- t; +} + +// An internal function but exported because it is cross-package; part of the implementation +// of gotest. +func Main(tests []Test) { + flag.Parse(); + args := flag.Args(); + ok := true; + if len(tests) == 0 { + println("testing: warning: no tests to run"); + } + re, err := regexp.Compile(*match); + if err != nil { + println("invalid regexp for -match:", err.String()); + os.Exit(1); + } + for i := 0; i < len(tests); i++ { + if !re.Match(tests[i].Name) { + continue; + } + if *chatty { + println("=== RUN ", tests[i].Name); + } + t := new(T); + t.ch = make(chan *T); + go tRunner(t, &tests[i]); + <-t.ch; + if t.failed { + println("--- FAIL:", tests[i].Name); + print(t.errors); + ok = false; + } else if *chatty { + println("--- PASS:", tests[i].Name); + print(t.errors); + } + } + if !ok { + println("FAIL"); + os.Exit(1); + } + println("PASS"); +} diff --git a/src/pkg/time/Makefile b/src/pkg/time/Makefile new file mode 100644 index 000000000..8d3c3b65f --- /dev/null +++ b/src/pkg/time/Makefile @@ -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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D= + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + sleep.$O\ + zoneinfo.$O\ + +O2=\ + time.$O\ + +O3=\ + tick.$O\ + + +phases: a1 a2 a3 +_obj$D/time.a: phases + +a1: $(O1) + $(AR) grc _obj$D/time.a sleep.$O zoneinfo.$O + rm -f $(O1) + +a2: $(O2) + $(AR) grc _obj$D/time.a time.$O + rm -f $(O2) + +a3: $(O3) + $(AR) grc _obj$D/time.a tick.$O + rm -f $(O3) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/time.a + +$(O1): newpkg +$(O2): a1 +$(O3): a2 +$(O4): a3 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/time.a + +packages: _obj$D/time.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/time.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/time.a diff --git a/src/pkg/time/sleep.go b/src/pkg/time/sleep.go new file mode 100644 index 000000000..3bb76cf47 --- /dev/null +++ b/src/pkg/time/sleep.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 time + +import ( + "os"; + "syscall"; + "unsafe"; +) + +// Sleep pauses the current goroutine for ns nanoseconds. +// It returns os.EINTR if interrupted. +func Sleep(ns int64) os.Error { + return os.ErrnoToError(syscall.Sleep(ns)); +} diff --git a/src/pkg/time/tick.go b/src/pkg/time/tick.go new file mode 100644 index 000000000..53e2234f8 --- /dev/null +++ b/src/pkg/time/tick.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 time + +import ( + "syscall"; + "time"; + "unsafe"; +) + +// TODO(rsc): This implementation of time.Tick is a +// simple placeholder. Eventually, there will need to be +// a single central time server no matter how many tickers +// are active. There also needs to be a way to cancel a ticker. +// +// Also, if timeouts become part of the select statement, +// perhaps the Ticker is just: +// +// func Ticker(ns int64, c chan int64) { +// for { +// select { timeout ns: } +// nsec, err := time.Nanoseconds(); +// c <- nsec; +// } + +func ticker(ns int64, c chan int64) { + var tv syscall.Timeval; + now := time.Nanoseconds(); + when := now; + for { + when += ns; // next alarm + + // if c <- now took too long, skip ahead + if when < now { + // one big step + when += (now-when)/ns * ns; + } + for when <= now { + // little steps until when > now + when += ns + } + + time.Sleep(when - now); + now = time.Nanoseconds(); + c <- now; + } +} + +// Tick creates a synchronous 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. +func Tick(ns int64) chan int64 { + if ns <= 0 { + return nil + } + c := make(chan int64); + go ticker(ns, c); + return c; +} + diff --git a/src/pkg/time/tick_test.go b/src/pkg/time/tick_test.go new file mode 100644 index 000000000..0667be679 --- /dev/null +++ b/src/pkg/time/tick_test.go @@ -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. + +package time + +import ( + "testing"; + "time"; +) + +func TestTick(t *testing.T) { + const ( + Delta = 100*1e6; + Count = 10; + ); + c := Tick(Delta); + t0 := Nanoseconds(); + for i := 0; i < Count; i++ { + <-c; + } + 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)); + } +} diff --git a/src/pkg/time/time.go b/src/pkg/time/time.go new file mode 100644 index 000000000..ea9b66cbc --- /dev/null +++ b/src/pkg/time/time.go @@ -0,0 +1,372 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// The time package provides functionality for measuring and +// displaying time. +package time + +import ( + "os"; + "time" +) + +// Seconds reports the number of seconds since the Unix epoch, +// January 1, 1970 00:00:00 UTC. +func Seconds() int64 { + sec, nsec, err := os.Time(); + if err != nil { + panic("time: os.Time: ", err.String()); + } + 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("time: os.Time: ", err.String()); + } + return sec*1e9 + nsec +} + +// Days of the week. +const ( + Sunday = iota; + Monday; + Tuesday; + Wednesday; + Thursday; + Friday; + Saturday; +) + +// Time is the struct representing a parsed time value. +type Time struct { + Year int64; // 2008 is 2008 + Month, Day int; // Sep-17 is 9, 17 + Hour, Minute, Second int; // 10:43:12 is 10, 43, 12 + Weekday int; // Sunday, Monday, ... + ZoneOffset int; // seconds west of UTC + Zone string; +} + +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; + } else { + // Cut off 400 year cycles. + n := day/daysPer400Years; + year += 400*n; + day -= daysPer400Years*n; + } + + // Cut off 100-year cycles + n := day/daysPer100Years; + year += 100*n; + day -= daysPer100Years*n; + + // Cut off 4-year cycles + n = day/daysPer4Years; + year += 4*n; + day -= daysPer4Years*n; + + // Cut off non-leap years. + n = day/365; + year += n; + day -= 365*n; + + t.Year = year; + + // If someone ever needs yearday, + // tyearday = day (+1?) + + months := months(year); + var m int; + yday := int(day); + for m = 0; m < 12 && yday >= months[m]; m++ { + yday -= months[m] + } + t.Month = m+1; + t.Day = yday+1; + t.Zone = "UTC"; + + return t; +} + +// UTC returns the current time as a parsed Time value in the UTC time zone. +func UTC() *Time { + return SecondsToUTC(Seconds()) +} + +// SecondsToLocalTime converts sec, in number of seconds since the Unix epoch, +// into a parsed Time value in the local time zone. +func SecondsToLocalTime(sec int64) *Time { + z, offset, err := time.lookupTimezone(sec); + if err != nil { + return SecondsToUTC(sec) + } + t := SecondsToUTC(sec+int64(offset)); + t.Zone = z; + t.ZoneOffset = offset; + return t +} + +// LocalTime returns the current time as a parsed Time value in the local time zone. +func LocalTime() *Time { + return SecondsToLocalTime(Seconds()) +} + +// Seconds returns the number of seconds since January 1, 1970 represented by the +// parsed Time value. +func (t *Time) Seconds() int64 { + // First, accumulate days since January 1, 2001. + // Using 2001 instead of 1970 makes the leap-year + // handling easier (see SecondsToUTC), because + // it is at the beginning of the 4-, 100-, and 400-year cycles. + day := int64(0); + + // Rewrite year to be >= 2001. + year := t.Year; + if year < 2001 { + n := (2001 - year)/400 + 1; + year += 400*n; + day -= daysPer400Years*n; + } + + // Add in days from 400-year cycles. + n := (year - 2001) / 400; + year -= 400*n; + day += daysPer400Years*n; + + // Add in 100-year cycles. + n = (year - 2001) / 100; + year -= 100*n; + day += daysPer100Years*n; + + // Add in 4-year cycles. + n = (year - 2001) / 4; + year -= 4*n; + day += daysPer4Years*n; + + // Add in non-leap years. + n = year - 2001; + day += 365*n; + + // Add in days this year. + months := months(t.Year); + for m := 0; m < t.Month-1; m++ { + day += int64(months[m]) + } + day += int64(t.Day - 1); + + // Convert days to seconds since January 1, 2001. + sec := day * secondsPerDay; + + // Add in time elapsed today. + sec += int64(t.Hour) * 3600; + sec += int64(t.Minute) * 60; + sec += int64(t.Second); + + // Convert from seconds since 2001 to seconds since 1970. + sec += days1970To2001 * secondsPerDay; + + // Account for local time zone. + sec -= int64(t.ZoneOffset); + return sec +} + +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" +} + +func copy(dst []byte, s string) { + for i := 0; i < len(s); i++ { + dst[i] = s[i] + } +} + +func decimal(dst []byte, n int) { + if n < 0 { + n = 0 + } + for i := len(dst)-1; i >= 0; i-- { + dst[i] = byte(n%10 + '0'); + n /= 10 + } +} + +func addString(buf []byte, bp int, s string) int { + n := len(s); + copy(buf[bp:bp+n], s); + return bp+n +} + +// Just enough of strftime to implement the date formats below. +// Not exported. +func format(t *Time, fmt string) string { + buf := make([]byte, 128); + bp := 0; + + for i := 0; i < len(fmt); i++ { + if fmt[i] == '%' { + i++; + switch fmt[i] { + case 'A': // %A full weekday name + bp = addString(buf, bp, longDayNames[t.Weekday]); + case 'a': // %a abbreviated weekday name + bp = addString(buf, bp, shortDayNames[t.Weekday]); + case 'b': // %b abbreviated month name + bp = addString(buf, bp, shortMonthNames[t.Month-1]); + case 'd': // %d day of month (01-31) + decimal(buf[bp:bp+2], t.Day); + bp += 2; + case 'e': // %e day of month ( 1-31) + if t.Day >= 10 { + decimal(buf[bp:bp+2], t.Day) + } else { + buf[bp] = ' '; + buf[bp+1] = byte(t.Day + '0') + } + bp += 2; + case 'H': // %H hour 00-23 + decimal(buf[bp:bp+2], t.Hour); + bp += 2; + case 'M': // %M minute 00-59 + decimal(buf[bp:bp+2], t.Minute); + bp += 2; + case 'S': // %S second 00-59 + decimal(buf[bp:bp+2], t.Second); + bp += 2; + case 'Y': // %Y year 2008 + decimal(buf[bp:bp+4], int(t.Year)); + bp += 4; + case 'y': // %y year 08 + decimal(buf[bp:bp+2], int(t.Year%100)); + bp += 2; + case 'Z': + bp = addString(buf, bp, t.Zone); + default: + buf[bp] = '%'; + buf[bp+1] = fmt[i]; + bp += 2 + } + } else { + buf[bp] = fmt[i]; + bp++; + } + } + return string(buf[0:bp]) +} + +// Asctime formats the parsed time value in the style of +// ANSI C asctime: Sun Nov 6 08:49:37 1994 +func (t *Time) Asctime() string { + return format(t, "%a %b %e %H:%M:%S %Y") +} + +// RFC850 formats the parsed time value in the style of +// RFC 850: Sunday, 06-Nov-94 08:49:37 UTC +func (t *Time) RFC850() string { + return format(t, "%A, %d-%b-%y %H:%M:%S %Z") +} + +// RFC1123 formats the parsed time value in the style of +// RFC 1123: Sun, 06 Nov 1994 08:49:37 UTC +func (t *Time) RFC1123() string { + return format(t, "%a, %d %b %Y %H:%M:%S %Z") +} + +// String formats the parsed time value in the style of +// date(1) - Sun Nov 6 08:49:37 UTC 1994 +func (t *Time) String() string { + return format(t, "%a %b %e %H:%M:%S %Z %Y") +} diff --git a/src/pkg/time/time_test.go b/src/pkg/time/time_test.go new file mode 100644 index 000000000..41e6736e8 --- /dev/null +++ b/src/pkg/time/time_test.go @@ -0,0 +1,85 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package time + +import ( + "os"; + "testing"; + "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", "US/Pacific"); +} + +type TimeTest struct { + seconds int64; + golden Time; +} + +var utctests = []TimeTest { + TimeTest{0, Time{1970, 1, 1, 0, 0, 0, Thursday, 0, "UTC"}}, + TimeTest{1221681866, Time{2008, 9, 17, 20, 4, 26, Wednesday, 0, "UTC"}}, + TimeTest{-1221681866, Time{1931, 4, 16, 3, 55, 34, Thursday, 0, "UTC"}}, + TimeTest{1e18, Time{31688740476, 10, 23, 1, 46, 40, Friday, 0, "UTC"}}, + TimeTest{-1e18, Time{-31688736537, 3, 10, 22, 13, 20, Tuesday, 0, "UTC"}}, + TimeTest{0x7fffffffffffffff, Time{292277026596, 12, 4, 15, 30, 7, Sunday, 0, "UTC"}}, + TimeTest{-0x8000000000000000, Time{-292277022657, 1, 27, 8, 29, 52, Sunday, 0, "UTC"}} +} + +var localtests = []TimeTest { + TimeTest{0, Time{1969, 12, 31, 16, 0, 0, Wednesday, -8*60*60, "PST"}}, + TimeTest{1221681866, Time{2008, 9, 17, 13, 4, 26, Wednesday, -7*60*60, "PDT"}} +} + +func same(t, u *Time) bool { + return t.Year == u.Year + && t.Month == u.Month + && t.Day == u.Day + && t.Hour == u.Hour + && t.Minute == u.Minute + && t.Second == u.Second + && t.Weekday == u.Weekday + && t.ZoneOffset == u.ZoneOffset + && t.Zone == u.Zone +} + +func TestSecondsToUTC(t *testing.T) { + for i := 0; i < len(utctests); i++ { + sec := utctests[i].seconds; + golden := &utctests[i].golden; + tm := SecondsToUTC(sec); + newsec := tm.Seconds(); + if newsec != sec { + t.Errorf("SecondsToUTC(%d).Seconds() = %d", sec, newsec); + } + if !same(tm, golden) { + t.Errorf("SecondsToUTC(%d):", sec); + t.Errorf(" want=%v", *golden); + t.Errorf(" have=%v", *tm); + } + } +} + +func TestSecondsToLocalTime(t *testing.T) { + for i := 0; i < len(localtests); i++ { + sec := localtests[i].seconds; + golden := &localtests[i].golden; + tm := SecondsToLocalTime(sec); + newsec := tm.Seconds(); + if newsec != sec { + t.Errorf("SecondsToLocalTime(%d).Seconds() = %d", sec, newsec); + } + if !same(tm, golden) { + t.Errorf("SecondsToLocalTime(%d):", sec); + t.Errorf(" want=%v", *golden); + t.Errorf(" have=%v", *tm); + } + } +} + diff --git a/src/pkg/time/zoneinfo.go b/src/pkg/time/zoneinfo.go new file mode 100644 index 000000000..751afc931 --- /dev/null +++ b/src/pkg/time/zoneinfo.go @@ -0,0 +1,285 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// 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"; + "once"; + "os" +) + +const ( + maxFileSize = 8192; // actual files are closer to 1K + headerSize = 4+16+4*7; + + zoneDir = "/usr/share/zoneinfo/"; +) + +// Errors that can be generated recovering time zone information. +type TimeZoneError struct { + os.ErrorString +} + +var errShort = TimeZoneError{ "time: short zone file" } +var errInvalid = TimeZoneError{ "time: invalid zone file" } +var errLong = TimeZoneError{ "time: zone file too long" } + +// 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:len(d.p)]; + return p +} + +func (d *data) big4() (n uint32, ok bool) { + p := d.read(4); + if len(p) < 4 { + d.error = true; + return 0, false + } + return uint32(p[0]) << 24 | uint32(p[1]) << 16 | uint32(p[2]) << 8 | uint32(p[3]), true +} + +func (d *data) byte() (n byte, ok bool) { + p := d.read(1); + if len(p) < 1 { + d.error = true; + return 0, false + } + return p[0], true +} + + +// Make a string by stopping at the first NUL +func byteString(p []byte) string { + for i := 0; i < len(p); i++ { + if p[i] == 0 { + return string(p[0:i]) + } + } + return string(p) +} + +// Parsed representation +type zone struct { + utcoff int; + isdst bool; + name string; +} + +type zonetime struct { + time int32; // transition time, in seconds since 1970 GMT + zone *zone; // the zone that goes into effect at that time + isstd, isutc bool; // ignored - no idea what these mean +} + +func parseinfo(bytes []byte) (zt []zonetime, err os.Error) { + d := data{bytes, false}; + + // 4-byte magic "TZif" + if magic := d.read(4); string(magic) != "TZif" { + return nil, TimeZoneError{ "time: bad zone magic" } + } + + // 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, TimeZoneError { "time: bad zone file version" } + } + vers := p[0]; + + // 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, errShort + } + 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 + leapdata := data{d.read(n[NLeap]*8), false}; + + // 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, errShort + } + + // 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, errShort + } + z[i].utcoff = int(n); + var b byte; + if b, ok = zonedata.byte(); !ok { + return nil, errShort + } + z[i].isdst = b != 0; + if b, ok = zonedata.byte(); !ok || int(b) >= len(abbrev) { + return nil, errInvalid + } + z[i].name = byteString(abbrev[b:len(abbrev)]) + } + + // 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, errShort + } + zt[i].time = int32(n); + if int(txzones[i]) >= len(z) { + return nil, errInvalid + } + 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, nil +} + +func readfile(name string, max int) (p []byte, err os.Error) { + f, e := os.Open(name, os.O_RDONLY, 0); + if e != nil { + return nil, e; + } + p = make([]byte, max); + n, err1 := io.FullRead(f, p); + f.Close(); + if err1 == nil { // too long + return nil, errLong; + } + if err1 != io.ErrEOF { + return nil, err1; + } + return p[0:n], nil; +} + +func readinfofile(name string) ([]zonetime, os.Error) { + buf, err := readfile(name, maxFileSize); + if err != nil { + goto Error; + } + tx, err := parseinfo(buf); + if err != nil { + goto Error; + } + return tx, nil; + +Error: + if tzerr, ok := err.(TimeZoneError); ok { + tzerr.ErrorString = os.ErrorString(tzerr.String() + ": " + name) + } + return nil, err +} + +var zones []zonetime +var zoneerr os.Error + +func setupZone() { + // consult $TZ to find the time zone to use. + // no $TZ means use the system default /etc/localtime. + // $TZ="" means use UTC. + // $TZ="foo" means use /usr/share/zoneinfo/foo. + + tz, err := os.Getenv("TZ"); + var file string; + switch { + case err == os.ENOENV: + zones, zoneerr = readinfofile("/etc/localtime"); + case err != nil: + zoneerr = err; + case len(tz) > 0: + zones, zoneerr = readinfofile(zoneDir + tz); + case len(tz) == 0: + // do nothing: use UTC + } +} + +func lookupTimezone(sec int64) (zone string, offset int, err os.Error) { + once.Do(setupZone); + if zoneerr != nil || len(zones) == 0 { + return "UTC", 0, zoneerr + } + + // 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:len(tz)] + } + } + z := tz[0].zone; + return z.name, z.utcoff, nil +} diff --git a/src/pkg/unicode/Makefile b/src/pkg/unicode/Makefile new file mode 100644 index 000000000..de1677b8d --- /dev/null +++ b/src/pkg/unicode/Makefile @@ -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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D= + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + letter.$O\ + +O2=\ + decimaldigit.$O\ + + +phases: a1 a2 +_obj$D/unicode.a: phases + +a1: $(O1) + $(AR) grc _obj$D/unicode.a letter.$O + rm -f $(O1) + +a2: $(O2) + $(AR) grc _obj$D/unicode.a decimaldigit.$O + rm -f $(O2) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/unicode.a + +$(O1): newpkg +$(O2): a1 +$(O3): a2 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/unicode.a + +packages: _obj$D/unicode.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/unicode.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/unicode.a diff --git a/src/pkg/unicode/decimaldigit.go b/src/pkg/unicode/decimaldigit.go new file mode 100644 index 000000000..1165e3ae1 --- /dev/null +++ b/src/pkg/unicode/decimaldigit.go @@ -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. + +package unicode + +// TODO: Generated by hand starting with +// http://www.unicode.org/Public/UNIDATA/UnicodeData.txt +// These ranges are the characters with the third field "Nd". +// Should generate automatically etc. + +import "unicode" + +// Decimal digit is the set of Unicode characters with the "decimal digit" property. +var DecimalDigit = []Range{ + Range{0x0030, 0x0039, 1}, + Range{0x0660, 0x0669, 1}, + Range{0x06F0, 0x06F9, 1}, + Range{0x07C0, 0x07C9, 1}, + Range{0x0966, 0x096F, 1}, + Range{0x09E6, 0x09EF, 1}, + Range{0x0A66, 0x0A6F, 1}, + Range{0x0AE6, 0x0AEF, 1}, + Range{0x0B66, 0x0B6F, 1}, + Range{0x0BE6, 0x0BEF, 1}, + Range{0x0C66, 0x0C6F, 1}, + Range{0x0CE6, 0x0CEF, 1}, + Range{0x0D66, 0x0D6F, 1}, + Range{0x0E50, 0x0E59, 1}, + Range{0x0ED0, 0x0ED9, 1}, + Range{0x0F20, 0x0F29, 1}, + Range{0x1040, 0x1049, 1}, + Range{0x1090, 0x1099, 1}, + Range{0x17E0, 0x17E9, 1}, + Range{0x1810, 0x1819, 1}, + Range{0x1946, 0x194F, 1}, + Range{0x19D0, 0x19D9, 1}, + Range{0x1B50, 0x1B59, 1}, + Range{0x1BB0, 0x1BB9, 1}, + Range{0x1C40, 0x1C49, 1}, + Range{0x1C50, 0x1C59, 1}, + Range{0xA620, 0xA629, 1}, + Range{0xA8D0, 0xA8D9, 1}, + Range{0xA900, 0xA909, 1}, + Range{0xAA50, 0xAA59, 1}, + Range{0xFF10, 0xFF19, 1}, +} + +// IsDecimalDigit reports whether the rune is a decimal digit. +func IsDecimalDigit(rune int) bool { + return Is(DecimalDigit, rune); +} diff --git a/src/pkg/unicode/decimaldigit_test.go b/src/pkg/unicode/decimaldigit_test.go new file mode 100644 index 000000000..f7b470c67 --- /dev/null +++ b/src/pkg/unicode/decimaldigit_test.go @@ -0,0 +1,375 @@ +// Copyright 2009 The Go Authors. 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 + +import ( + "testing"; + "unicode"; +) + +// To get data: +// grep '^....;[^;]*;Nd;' UnicodeData.txt +// To generate this table: +// ,s/([^;]+).+/ 0x\1, \/\/ &/g +var testDecimal = []int{ + 0x0030, // 0030;DIGIT ZERO;Nd;0;EN;;0;0;0;N;;;;; + 0x0031, // 0031;DIGIT ONE;Nd;0;EN;;1;1;1;N;;;;; + 0x0032, // 0032;DIGIT TWO;Nd;0;EN;;2;2;2;N;;;;; + 0x0033, // 0033;DIGIT THREE;Nd;0;EN;;3;3;3;N;;;;; + 0x0034, // 0034;DIGIT FOUR;Nd;0;EN;;4;4;4;N;;;;; + 0x0035, // 0035;DIGIT FIVE;Nd;0;EN;;5;5;5;N;;;;; + 0x0036, // 0036;DIGIT SIX;Nd;0;EN;;6;6;6;N;;;;; + 0x0037, // 0037;DIGIT SEVEN;Nd;0;EN;;7;7;7;N;;;;; + 0x0038, // 0038;DIGIT EIGHT;Nd;0;EN;;8;8;8;N;;;;; + 0x0039, // 0039;DIGIT NINE;Nd;0;EN;;9;9;9;N;;;;; + 0x0660, // 0660;ARABIC-INDIC DIGIT ZERO;Nd;0;AN;;0;0;0;N;;;;; + 0x0661, // 0661;ARABIC-INDIC DIGIT ONE;Nd;0;AN;;1;1;1;N;;;;; + 0x0662, // 0662;ARABIC-INDIC DIGIT TWO;Nd;0;AN;;2;2;2;N;;;;; + 0x0663, // 0663;ARABIC-INDIC DIGIT THREE;Nd;0;AN;;3;3;3;N;;;;; + 0x0664, // 0664;ARABIC-INDIC DIGIT FOUR;Nd;0;AN;;4;4;4;N;;;;; + 0x0665, // 0665;ARABIC-INDIC DIGIT FIVE;Nd;0;AN;;5;5;5;N;;;;; + 0x0666, // 0666;ARABIC-INDIC DIGIT SIX;Nd;0;AN;;6;6;6;N;;;;; + 0x0667, // 0667;ARABIC-INDIC DIGIT SEVEN;Nd;0;AN;;7;7;7;N;;;;; + 0x0668, // 0668;ARABIC-INDIC DIGIT EIGHT;Nd;0;AN;;8;8;8;N;;;;; + 0x0669, // 0669;ARABIC-INDIC DIGIT NINE;Nd;0;AN;;9;9;9;N;;;;; + 0x06F0, // 06F0;EXTENDED ARABIC-INDIC DIGIT ZERO;Nd;0;EN;;0;0;0;N;EASTERN ARABIC-INDIC DIGIT ZERO;;;; + 0x06F1, // 06F1;EXTENDED ARABIC-INDIC DIGIT ONE;Nd;0;EN;;1;1;1;N;EASTERN ARABIC-INDIC DIGIT ONE;;;; + 0x06F2, // 06F2;EXTENDED ARABIC-INDIC DIGIT TWO;Nd;0;EN;;2;2;2;N;EASTERN ARABIC-INDIC DIGIT TWO;;;; + 0x06F3, // 06F3;EXTENDED ARABIC-INDIC DIGIT THREE;Nd;0;EN;;3;3;3;N;EASTERN ARABIC-INDIC DIGIT THREE;;;; + 0x06F4, // 06F4;EXTENDED ARABIC-INDIC DIGIT FOUR;Nd;0;EN;;4;4;4;N;EASTERN ARABIC-INDIC DIGIT FOUR;;;; + 0x06F5, // 06F5;EXTENDED ARABIC-INDIC DIGIT FIVE;Nd;0;EN;;5;5;5;N;EASTERN ARABIC-INDIC DIGIT FIVE;;;; + 0x06F6, // 06F6;EXTENDED ARABIC-INDIC DIGIT SIX;Nd;0;EN;;6;6;6;N;EASTERN ARABIC-INDIC DIGIT SIX;;;; + 0x06F7, // 06F7;EXTENDED ARABIC-INDIC DIGIT SEVEN;Nd;0;EN;;7;7;7;N;EASTERN ARABIC-INDIC DIGIT SEVEN;;;; + 0x06F8, // 06F8;EXTENDED ARABIC-INDIC DIGIT EIGHT;Nd;0;EN;;8;8;8;N;EASTERN ARABIC-INDIC DIGIT EIGHT;;;; + 0x06F9, // 06F9;EXTENDED ARABIC-INDIC DIGIT NINE;Nd;0;EN;;9;9;9;N;EASTERN ARABIC-INDIC DIGIT NINE;;;; + 0x07C0, // 07C0;NKO DIGIT ZERO;Nd;0;R;;0;0;0;N;;;;; + 0x07C1, // 07C1;NKO DIGIT ONE;Nd;0;R;;1;1;1;N;;;;; + 0x07C2, // 07C2;NKO DIGIT TWO;Nd;0;R;;2;2;2;N;;;;; + 0x07C3, // 07C3;NKO DIGIT THREE;Nd;0;R;;3;3;3;N;;;;; + 0x07C4, // 07C4;NKO DIGIT FOUR;Nd;0;R;;4;4;4;N;;;;; + 0x07C5, // 07C5;NKO DIGIT FIVE;Nd;0;R;;5;5;5;N;;;;; + 0x07C6, // 07C6;NKO DIGIT SIX;Nd;0;R;;6;6;6;N;;;;; + 0x07C7, // 07C7;NKO DIGIT SEVEN;Nd;0;R;;7;7;7;N;;;;; + 0x07C8, // 07C8;NKO DIGIT EIGHT;Nd;0;R;;8;8;8;N;;;;; + 0x07C9, // 07C9;NKO DIGIT NINE;Nd;0;R;;9;9;9;N;;;;; + 0x0966, // 0966;DEVANAGARI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; + 0x0967, // 0967;DEVANAGARI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; + 0x0968, // 0968;DEVANAGARI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; + 0x0969, // 0969;DEVANAGARI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; + 0x096A, // 096A;DEVANAGARI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; + 0x096B, // 096B;DEVANAGARI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; + 0x096C, // 096C;DEVANAGARI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; + 0x096D, // 096D;DEVANAGARI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; + 0x096E, // 096E;DEVANAGARI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; + 0x096F, // 096F;DEVANAGARI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; + 0x09E6, // 09E6;BENGALI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; + 0x09E7, // 09E7;BENGALI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; + 0x09E8, // 09E8;BENGALI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; + 0x09E9, // 09E9;BENGALI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; + 0x09EA, // 09EA;BENGALI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; + 0x09EB, // 09EB;BENGALI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; + 0x09EC, // 09EC;BENGALI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; + 0x09ED, // 09ED;BENGALI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; + 0x09EE, // 09EE;BENGALI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; + 0x09EF, // 09EF;BENGALI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; + 0x0A66, // 0A66;GURMUKHI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; + 0x0A67, // 0A67;GURMUKHI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; + 0x0A68, // 0A68;GURMUKHI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; + 0x0A69, // 0A69;GURMUKHI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; + 0x0A6A, // 0A6A;GURMUKHI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; + 0x0A6B, // 0A6B;GURMUKHI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; + 0x0A6C, // 0A6C;GURMUKHI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; + 0x0A6D, // 0A6D;GURMUKHI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; + 0x0A6E, // 0A6E;GURMUKHI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; + 0x0A6F, // 0A6F;GURMUKHI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; + 0x0AE6, // 0AE6;GUJARATI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; + 0x0AE7, // 0AE7;GUJARATI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; + 0x0AE8, // 0AE8;GUJARATI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; + 0x0AE9, // 0AE9;GUJARATI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; + 0x0AEA, // 0AEA;GUJARATI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; + 0x0AEB, // 0AEB;GUJARATI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; + 0x0AEC, // 0AEC;GUJARATI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; + 0x0AED, // 0AED;GUJARATI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; + 0x0AEE, // 0AEE;GUJARATI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; + 0x0AEF, // 0AEF;GUJARATI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; + 0x0B66, // 0B66;ORIYA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; + 0x0B67, // 0B67;ORIYA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; + 0x0B68, // 0B68;ORIYA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; + 0x0B69, // 0B69;ORIYA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; + 0x0B6A, // 0B6A;ORIYA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; + 0x0B6B, // 0B6B;ORIYA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; + 0x0B6C, // 0B6C;ORIYA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; + 0x0B6D, // 0B6D;ORIYA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; + 0x0B6E, // 0B6E;ORIYA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; + 0x0B6F, // 0B6F;ORIYA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; + 0x0BE6, // 0BE6;TAMIL DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; + 0x0BE7, // 0BE7;TAMIL DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; + 0x0BE8, // 0BE8;TAMIL DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; + 0x0BE9, // 0BE9;TAMIL DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; + 0x0BEA, // 0BEA;TAMIL DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; + 0x0BEB, // 0BEB;TAMIL DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; + 0x0BEC, // 0BEC;TAMIL DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; + 0x0BED, // 0BED;TAMIL DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; + 0x0BEE, // 0BEE;TAMIL DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; + 0x0BEF, // 0BEF;TAMIL DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; + 0x0C66, // 0C66;TELUGU DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; + 0x0C67, // 0C67;TELUGU DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; + 0x0C68, // 0C68;TELUGU DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; + 0x0C69, // 0C69;TELUGU DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; + 0x0C6A, // 0C6A;TELUGU DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; + 0x0C6B, // 0C6B;TELUGU DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; + 0x0C6C, // 0C6C;TELUGU DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; + 0x0C6D, // 0C6D;TELUGU DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; + 0x0C6E, // 0C6E;TELUGU DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; + 0x0C6F, // 0C6F;TELUGU DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; + 0x0CE6, // 0CE6;KANNADA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; + 0x0CE7, // 0CE7;KANNADA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; + 0x0CE8, // 0CE8;KANNADA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; + 0x0CE9, // 0CE9;KANNADA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; + 0x0CEA, // 0CEA;KANNADA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; + 0x0CEB, // 0CEB;KANNADA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; + 0x0CEC, // 0CEC;KANNADA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; + 0x0CED, // 0CED;KANNADA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; + 0x0CEE, // 0CEE;KANNADA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; + 0x0CEF, // 0CEF;KANNADA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; + 0x0D66, // 0D66;MALAYALAM DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; + 0x0D67, // 0D67;MALAYALAM DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; + 0x0D68, // 0D68;MALAYALAM DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; + 0x0D69, // 0D69;MALAYALAM DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; + 0x0D6A, // 0D6A;MALAYALAM DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; + 0x0D6B, // 0D6B;MALAYALAM DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; + 0x0D6C, // 0D6C;MALAYALAM DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; + 0x0D6D, // 0D6D;MALAYALAM DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; + 0x0D6E, // 0D6E;MALAYALAM DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; + 0x0D6F, // 0D6F;MALAYALAM DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; + 0x0E50, // 0E50;THAI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; + 0x0E51, // 0E51;THAI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; + 0x0E52, // 0E52;THAI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; + 0x0E53, // 0E53;THAI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; + 0x0E54, // 0E54;THAI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; + 0x0E55, // 0E55;THAI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; + 0x0E56, // 0E56;THAI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; + 0x0E57, // 0E57;THAI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; + 0x0E58, // 0E58;THAI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; + 0x0E59, // 0E59;THAI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; + 0x0ED0, // 0ED0;LAO DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; + 0x0ED1, // 0ED1;LAO DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; + 0x0ED2, // 0ED2;LAO DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; + 0x0ED3, // 0ED3;LAO DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; + 0x0ED4, // 0ED4;LAO DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; + 0x0ED5, // 0ED5;LAO DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; + 0x0ED6, // 0ED6;LAO DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; + 0x0ED7, // 0ED7;LAO DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; + 0x0ED8, // 0ED8;LAO DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; + 0x0ED9, // 0ED9;LAO DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; + 0x0F20, // 0F20;TIBETAN DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; + 0x0F21, // 0F21;TIBETAN DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; + 0x0F22, // 0F22;TIBETAN DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; + 0x0F23, // 0F23;TIBETAN DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; + 0x0F24, // 0F24;TIBETAN DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; + 0x0F25, // 0F25;TIBETAN DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; + 0x0F26, // 0F26;TIBETAN DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; + 0x0F27, // 0F27;TIBETAN DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; + 0x0F28, // 0F28;TIBETAN DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; + 0x0F29, // 0F29;TIBETAN DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; + 0x1040, // 1040;MYANMAR DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; + 0x1041, // 1041;MYANMAR DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; + 0x1042, // 1042;MYANMAR DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; + 0x1043, // 1043;MYANMAR DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; + 0x1044, // 1044;MYANMAR DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; + 0x1045, // 1045;MYANMAR DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; + 0x1046, // 1046;MYANMAR DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; + 0x1047, // 1047;MYANMAR DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; + 0x1048, // 1048;MYANMAR DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; + 0x1049, // 1049;MYANMAR DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; + 0x1090, // 1090;MYANMAR SHAN DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; + 0x1091, // 1091;MYANMAR SHAN DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; + 0x1092, // 1092;MYANMAR SHAN DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; + 0x1093, // 1093;MYANMAR SHAN DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; + 0x1094, // 1094;MYANMAR SHAN DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; + 0x1095, // 1095;MYANMAR SHAN DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; + 0x1096, // 1096;MYANMAR SHAN DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; + 0x1097, // 1097;MYANMAR SHAN DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; + 0x1098, // 1098;MYANMAR SHAN DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; + 0x1099, // 1099;MYANMAR SHAN DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; + 0x17E0, // 17E0;KHMER DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; + 0x17E1, // 17E1;KHMER DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; + 0x17E2, // 17E2;KHMER DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; + 0x17E3, // 17E3;KHMER DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; + 0x17E4, // 17E4;KHMER DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; + 0x17E5, // 17E5;KHMER DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; + 0x17E6, // 17E6;KHMER DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; + 0x17E7, // 17E7;KHMER DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; + 0x17E8, // 17E8;KHMER DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; + 0x17E9, // 17E9;KHMER DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; + 0x1810, // 1810;MONGOLIAN DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; + 0x1811, // 1811;MONGOLIAN DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; + 0x1812, // 1812;MONGOLIAN DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; + 0x1813, // 1813;MONGOLIAN DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; + 0x1814, // 1814;MONGOLIAN DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; + 0x1815, // 1815;MONGOLIAN DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; + 0x1816, // 1816;MONGOLIAN DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; + 0x1817, // 1817;MONGOLIAN DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; + 0x1818, // 1818;MONGOLIAN DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; + 0x1819, // 1819;MONGOLIAN DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; + 0x1946, // 1946;LIMBU DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; + 0x1947, // 1947;LIMBU DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; + 0x1948, // 1948;LIMBU DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; + 0x1949, // 1949;LIMBU DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; + 0x194A, // 194A;LIMBU DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; + 0x194B, // 194B;LIMBU DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; + 0x194C, // 194C;LIMBU DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; + 0x194D, // 194D;LIMBU DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; + 0x194E, // 194E;LIMBU DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; + 0x194F, // 194F;LIMBU DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; + 0x19D0, // 19D0;NEW TAI LUE DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; + 0x19D1, // 19D1;NEW TAI LUE DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; + 0x19D2, // 19D2;NEW TAI LUE DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; + 0x19D3, // 19D3;NEW TAI LUE DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; + 0x19D4, // 19D4;NEW TAI LUE DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; + 0x19D5, // 19D5;NEW TAI LUE DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; + 0x19D6, // 19D6;NEW TAI LUE DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; + 0x19D7, // 19D7;NEW TAI LUE DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; + 0x19D8, // 19D8;NEW TAI LUE DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; + 0x19D9, // 19D9;NEW TAI LUE DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; + 0x1B50, // 1B50;BALINESE DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; + 0x1B51, // 1B51;BALINESE DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; + 0x1B52, // 1B52;BALINESE DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; + 0x1B53, // 1B53;BALINESE DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; + 0x1B54, // 1B54;BALINESE DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; + 0x1B55, // 1B55;BALINESE DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; + 0x1B56, // 1B56;BALINESE DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; + 0x1B57, // 1B57;BALINESE DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; + 0x1B58, // 1B58;BALINESE DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; + 0x1B59, // 1B59;BALINESE DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; + 0x1BB0, // 1BB0;SUNDANESE DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; + 0x1BB1, // 1BB1;SUNDANESE DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; + 0x1BB2, // 1BB2;SUNDANESE DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; + 0x1BB3, // 1BB3;SUNDANESE DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; + 0x1BB4, // 1BB4;SUNDANESE DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; + 0x1BB5, // 1BB5;SUNDANESE DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; + 0x1BB6, // 1BB6;SUNDANESE DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; + 0x1BB7, // 1BB7;SUNDANESE DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; + 0x1BB8, // 1BB8;SUNDANESE DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; + 0x1BB9, // 1BB9;SUNDANESE DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; + 0x1C40, // 1C40;LEPCHA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; + 0x1C41, // 1C41;LEPCHA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; + 0x1C42, // 1C42;LEPCHA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; + 0x1C43, // 1C43;LEPCHA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; + 0x1C44, // 1C44;LEPCHA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; + 0x1C45, // 1C45;LEPCHA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; + 0x1C46, // 1C46;LEPCHA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; + 0x1C47, // 1C47;LEPCHA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; + 0x1C48, // 1C48;LEPCHA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; + 0x1C49, // 1C49;LEPCHA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; + 0x1C50, // 1C50;OL CHIKI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; + 0x1C51, // 1C51;OL CHIKI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; + 0x1C52, // 1C52;OL CHIKI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; + 0x1C53, // 1C53;OL CHIKI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; + 0x1C54, // 1C54;OL CHIKI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; + 0x1C55, // 1C55;OL CHIKI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; + 0x1C56, // 1C56;OL CHIKI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; + 0x1C57, // 1C57;OL CHIKI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; + 0x1C58, // 1C58;OL CHIKI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; + 0x1C59, // 1C59;OL CHIKI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; + 0xA620, // A620;VAI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; + 0xA621, // A621;VAI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; + 0xA622, // A622;VAI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; + 0xA623, // A623;VAI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; + 0xA624, // A624;VAI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; + 0xA625, // A625;VAI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; + 0xA626, // A626;VAI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; + 0xA627, // A627;VAI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; + 0xA628, // A628;VAI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; + 0xA629, // A629;VAI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; + 0xA8D0, // A8D0;SAURASHTRA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; + 0xA8D1, // A8D1;SAURASHTRA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; + 0xA8D2, // A8D2;SAURASHTRA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; + 0xA8D3, // A8D3;SAURASHTRA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; + 0xA8D4, // A8D4;SAURASHTRA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; + 0xA8D5, // A8D5;SAURASHTRA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; + 0xA8D6, // A8D6;SAURASHTRA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; + 0xA8D7, // A8D7;SAURASHTRA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; + 0xA8D8, // A8D8;SAURASHTRA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; + 0xA8D9, // A8D9;SAURASHTRA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; + 0xA900, // A900;KAYAH LI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; + 0xA901, // A901;KAYAH LI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; + 0xA902, // A902;KAYAH LI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; + 0xA903, // A903;KAYAH LI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; + 0xA904, // A904;KAYAH LI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; + 0xA905, // A905;KAYAH LI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; + 0xA906, // A906;KAYAH LI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; + 0xA907, // A907;KAYAH LI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; + 0xA908, // A908;KAYAH LI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; + 0xA909, // A909;KAYAH LI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; + 0xAA50, // AA50;CHAM DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;; + 0xAA51, // AA51;CHAM DIGIT ONE;Nd;0;L;;1;1;1;N;;;;; + 0xAA52, // AA52;CHAM DIGIT TWO;Nd;0;L;;2;2;2;N;;;;; + 0xAA53, // AA53;CHAM DIGIT THREE;Nd;0;L;;3;3;3;N;;;;; + 0xAA54, // AA54;CHAM DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;; + 0xAA55, // AA55;CHAM DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;; + 0xAA56, // AA56;CHAM DIGIT SIX;Nd;0;L;;6;6;6;N;;;;; + 0xAA57, // AA57;CHAM DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;; + 0xAA58, // AA58;CHAM DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;; + 0xAA59, // AA59;CHAM DIGIT NINE;Nd;0;L;;9;9;9;N;;;;; + 0xFF10, // FF10;FULLWIDTH DIGIT ZERO;Nd;0;EN; 0030;0;0;0;N;;;;; + 0xFF11, // FF11;FULLWIDTH DIGIT ONE;Nd;0;EN; 0031;1;1;1;N;;;;; + 0xFF12, // FF12;FULLWIDTH DIGIT TWO;Nd;0;EN; 0032;2;2;2;N;;;;; + 0xFF13, // FF13;FULLWIDTH DIGIT THREE;Nd;0;EN; 0033;3;3;3;N;;;;; + 0xFF14, // FF14;FULLWIDTH DIGIT FOUR;Nd;0;EN; 0034;4;4;4;N;;;;; + 0xFF15, // FF15;FULLWIDTH DIGIT FIVE;Nd;0;EN; 0035;5;5;5;N;;;;; + 0xFF16, // FF16;FULLWIDTH DIGIT SIX;Nd;0;EN; 0036;6;6;6;N;;;;; + 0xFF17, // FF17;FULLWIDTH DIGIT SEVEN;Nd;0;EN; 0037;7;7;7;N;;;;; + 0xFF18, // FF18;FULLWIDTH DIGIT EIGHT;Nd;0;EN; 0038;8;8;8;N;;;;; + 0xFF19, // FF19;FULLWIDTH DIGIT NINE;Nd;0;EN; 0039;9;9;9;N;;;;; +} + +var testLetter = []int{ + 0x41, + 0x61, + 0xaa, + 0xba, + 0xc8, + 0xdb, + 0xf9, + 0x2ec, + 0x535, + 0x6e6, + 0x93d, + 0xa15, + 0xb99, + 0xdc0, + 0xedd, + 0x1000, + 0x1200, + 0x1312, + 0x1401, + 0x1885, + 0x2c00, + 0xa800, + 0xf900, + 0xfa30, + 0xffda, + 0xffdc, + 0x10000, + 0x10300, + 0x10400, + 0x20000, + 0x2f800, + 0x2fa1d, +} + +func TestIsDecimalDigit(t *testing.T) { + for i, r := range(testDecimal) { + if !IsDecimalDigit(r) { + t.Errorf("IsDecimalDigit(%#x) = false, want true\n", r); + } + } + for i, r := range(testLetter) { + if IsDecimalDigit(r) { + t.Errorf("IsDecimalDigit(%#x) = true, want false\n", r); + } + } +} diff --git a/src/pkg/unicode/letter.go b/src/pkg/unicode/letter.go new file mode 100644 index 000000000..d7aa678c9 --- /dev/null +++ b/src/pkg/unicode/letter.go @@ -0,0 +1,578 @@ +// Copyright 2009 The Go 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 access. A quick start for now. + +// TODO: Generated by hand. +// Should generate automatically from Unicode +// tables, expand to other properties, split into files, +// link in only the tables that are used by the program, +// etc. + +// This package provides data and functions to test some properties of Unicode code points. +// It is rudimentary but will improve. +package unicode + +// The representation of a range of Unicode code points. The range runs from Lo to Hi +// inclusive and has the specified stride. +type Range struct { + Lo int; + Hi int; + Stride int; +} + +// Upper is the set of Unicode upper case letters. +var Upper = []Range{ + Range{0x0041, 0x005a, 1}, + Range{0x00c0, 0x00d6, 1}, + Range{0x00d8, 0x00de, 1}, + Range{0x0100, 0x0136, 2}, + Range{0x0139, 0x0147, 2}, + Range{0x014a, 0x0176, 2}, + Range{0x0178, 0x0179, 1}, + Range{0x017b, 0x017d, 2}, + Range{0x0181, 0x0182, 1}, + Range{0x0184, 0x0184, 1}, + Range{0x0186, 0x0187, 1}, + Range{0x0189, 0x018b, 1}, + Range{0x018e, 0x0191, 1}, + Range{0x0193, 0x0194, 1}, + Range{0x0196, 0x0198, 1}, + Range{0x019c, 0x019d, 1}, + Range{0x019f, 0x01a0, 1}, + Range{0x01a2, 0x01a4, 2}, + Range{0x01a6, 0x01a7, 1}, + Range{0x01a9, 0x01ac, 3}, + Range{0x01ae, 0x01af, 1}, + Range{0x01b1, 0x01b3, 1}, + Range{0x01b5, 0x01b5, 1}, + Range{0x01b7, 0x01b8, 1}, + Range{0x01bc, 0x01c4, 8}, + Range{0x01c7, 0x01cd, 3}, + Range{0x01cf, 0x01db, 2}, + Range{0x01de, 0x01ee, 2}, + Range{0x01f1, 0x01f4, 3}, + Range{0x01f6, 0x01f8, 1}, + Range{0x01fa, 0x0232, 2}, + Range{0x023a, 0x023b, 1}, + Range{0x023d, 0x023e, 1}, + Range{0x0241, 0x0241, 1}, + Range{0x0243, 0x0246, 1}, + Range{0x0248, 0x024e, 2}, + Range{0x0370, 0x0372, 2}, + Range{0x0376, 0x0386, 16}, + Range{0x0388, 0x038a, 1}, + Range{0x038c, 0x038c, 1}, + Range{0x038e, 0x038f, 1}, + Range{0x0391, 0x03a1, 1}, + Range{0x03a3, 0x03ab, 1}, + Range{0x03cf, 0x03cf, 1}, + Range{0x03d2, 0x03d4, 1}, + Range{0x03d8, 0x03ee, 2}, + Range{0x03f4, 0x03f7, 3}, + Range{0x03f9, 0x03fa, 1}, + Range{0x03fd, 0x042f, 1}, + Range{0x0460, 0x0480, 2}, + Range{0x048a, 0x04be, 2}, + Range{0x04c0, 0x04c1, 1}, + Range{0x04c3, 0x04cd, 2}, + Range{0x04d0, 0x0522, 2}, + Range{0x0531, 0x0556, 1}, + Range{0x10a0, 0x10c5, 1}, + Range{0x1e00, 0x1e94, 2}, + Range{0x1e9e, 0x1efe, 2}, + Range{0x1f08, 0x1f0f, 1}, + Range{0x1f18, 0x1f1d, 1}, + Range{0x1f28, 0x1f2f, 1}, + Range{0x1f38, 0x1f3f, 1}, + Range{0x1f48, 0x1f4d, 1}, + Range{0x1f59, 0x1f5f, 2}, + Range{0x1f68, 0x1f6f, 1}, + Range{0x1fb8, 0x1fbb, 1}, + Range{0x1fc8, 0x1fcb, 1}, + Range{0x1fd8, 0x1fdb, 1}, + Range{0x1fe8, 0x1fec, 1}, + Range{0x1ff8, 0x1ffb, 1}, + Range{0x2102, 0x2107, 5}, + Range{0x210b, 0x210d, 1}, + Range{0x2110, 0x2112, 1}, + Range{0x2115, 0x2115, 1}, + Range{0x2119, 0x211d, 1}, + Range{0x2124, 0x2128, 2}, + Range{0x212a, 0x212d, 1}, + Range{0x2130, 0x2133, 1}, + Range{0x213e, 0x213f, 1}, + Range{0x2145, 0x2183, 62}, + Range{0x2c00, 0x2c2e, 1}, + Range{0x2c60, 0x2c60, 1}, + Range{0x2c62, 0x2c64, 1}, + Range{0x2c67, 0x2c6b, 2}, + Range{0x2c6d, 0x2c6f, 1}, + Range{0x2c72, 0x2c75, 3}, + Range{0x2c80, 0x2ce2, 2}, + Range{0xa640, 0xa65e, 2}, + Range{0xa662, 0xa66c, 2}, + Range{0xa680, 0xa696, 2}, + Range{0xa722, 0xa72e, 2}, + Range{0xa732, 0xa76e, 2}, + Range{0xa779, 0xa77b, 2}, + Range{0xa77d, 0xa77e, 1}, + Range{0xa780, 0xa786, 2}, + Range{0xa78b, 0xa78b, 1}, + Range{0xff21, 0xff3a, 1}, + Range{0x10400, 0x10427, 1}, + Range{0x1d400, 0x1d419, 1}, + Range{0x1d434, 0x1d44d, 1}, + Range{0x1d468, 0x1d481, 1}, + Range{0x1d49c, 0x1d49c, 1}, + Range{0x1d49e, 0x1d49f, 1}, + Range{0x1d4a2, 0x1d4a2, 1}, + Range{0x1d4a5, 0x1d4a6, 1}, + Range{0x1d4a9, 0x1d4ac, 1}, + Range{0x1d4ae, 0x1d4b5, 1}, + Range{0x1d4d0, 0x1d4e9, 1}, + Range{0x1d504, 0x1d505, 1}, + Range{0x1d507, 0x1d50a, 1}, + Range{0x1d50d, 0x1d514, 1}, + Range{0x1d516, 0x1d51c, 1}, + Range{0x1d538, 0x1d539, 1}, + Range{0x1d53b, 0x1d53e, 1}, + Range{0x1d540, 0x1d544, 1}, + Range{0x1d546, 0x1d546, 1}, + Range{0x1d54a, 0x1d550, 1}, + Range{0x1d56c, 0x1d585, 1}, + Range{0x1d5a0, 0x1d5b9, 1}, + Range{0x1d5d4, 0x1d5ed, 1}, + Range{0x1d608, 0x1d621, 1}, + Range{0x1d63c, 0x1d655, 1}, + Range{0x1d670, 0x1d689, 1}, + Range{0x1d6a8, 0x1d6c0, 1}, + Range{0x1d6e2, 0x1d6fa, 1}, + Range{0x1d71c, 0x1d734, 1}, + Range{0x1d756, 0x1d76e, 1}, + Range{0x1d790, 0x1d7a8, 1}, + Range{0x1d7ca, 0x1d7ca, 1}, +} + +// Letter is the set of Unicode letters. +var Letter = []Range { + Range{0x0041, 0x005a, 1}, + Range{0x0061, 0x007a, 1}, + Range{0x00aa, 0x00b5, 11}, + Range{0x00ba, 0x00ba, 1}, + Range{0x00c0, 0x00d6, 1}, + Range{0x00d8, 0x00f6, 1}, + Range{0x00f8, 0x02c1, 1}, + Range{0x02c6, 0x02d1, 1}, + Range{0x02e0, 0x02e4, 1}, + Range{0x02ec, 0x02ee, 2}, + Range{0x0370, 0x0374, 1}, + Range{0x0376, 0x0377, 1}, + Range{0x037a, 0x037d, 1}, + Range{0x0386, 0x0386, 1}, + Range{0x0388, 0x038a, 1}, + Range{0x038c, 0x038c, 1}, + Range{0x038e, 0x03a1, 1}, + Range{0x03a3, 0x03f5, 1}, + Range{0x03f7, 0x0481, 1}, + Range{0x048a, 0x0523, 1}, + Range{0x0531, 0x0556, 1}, + Range{0x0559, 0x0559, 1}, + Range{0x0561, 0x0587, 1}, + Range{0x05d0, 0x05ea, 1}, + Range{0x05f0, 0x05f2, 1}, + Range{0x0621, 0x064a, 1}, + Range{0x066e, 0x066f, 1}, + Range{0x0671, 0x06d3, 1}, + Range{0x06d5, 0x06d5, 1}, + Range{0x06e5, 0x06e6, 1}, + Range{0x06ee, 0x06ef, 1}, + Range{0x06fa, 0x06fc, 1}, + Range{0x06ff, 0x0710, 17}, + Range{0x0712, 0x072f, 1}, + Range{0x074d, 0x07a5, 1}, + Range{0x07b1, 0x07b1, 1}, + Range{0x07ca, 0x07ea, 1}, + Range{0x07f4, 0x07f5, 1}, + Range{0x07fa, 0x07fa, 1}, + Range{0x0904, 0x0939, 1}, + Range{0x093d, 0x0950, 19}, + Range{0x0958, 0x0961, 1}, + Range{0x0971, 0x0972, 1}, + Range{0x097b, 0x097f, 1}, + Range{0x0985, 0x098c, 1}, + Range{0x098f, 0x0990, 1}, + Range{0x0993, 0x09a8, 1}, + Range{0x09aa, 0x09b0, 1}, + Range{0x09b2, 0x09b2, 1}, + Range{0x09b6, 0x09b9, 1}, + Range{0x09bd, 0x09ce, 17}, + Range{0x09dc, 0x09dd, 1}, + Range{0x09df, 0x09e1, 1}, + Range{0x09f0, 0x09f1, 1}, + Range{0x0a05, 0x0a0a, 1}, + Range{0x0a0f, 0x0a10, 1}, + Range{0x0a13, 0x0a28, 1}, + Range{0x0a2a, 0x0a30, 1}, + Range{0x0a32, 0x0a33, 1}, + Range{0x0a35, 0x0a36, 1}, + Range{0x0a38, 0x0a39, 1}, + Range{0x0a59, 0x0a5c, 1}, + Range{0x0a5e, 0x0a5e, 1}, + Range{0x0a72, 0x0a74, 1}, + Range{0x0a85, 0x0a8d, 1}, + Range{0x0a8f, 0x0a91, 1}, + Range{0x0a93, 0x0aa8, 1}, + Range{0x0aaa, 0x0ab0, 1}, + Range{0x0ab2, 0x0ab3, 1}, + Range{0x0ab5, 0x0ab9, 1}, + Range{0x0abd, 0x0ad0, 19}, + Range{0x0ae0, 0x0ae1, 1}, + Range{0x0b05, 0x0b0c, 1}, + Range{0x0b0f, 0x0b10, 1}, + Range{0x0b13, 0x0b28, 1}, + Range{0x0b2a, 0x0b30, 1}, + Range{0x0b32, 0x0b33, 1}, + Range{0x0b35, 0x0b39, 1}, + Range{0x0b3d, 0x0b3d, 1}, + Range{0x0b5c, 0x0b5d, 1}, + Range{0x0b5f, 0x0b61, 1}, + Range{0x0b71, 0x0b83, 18}, + Range{0x0b85, 0x0b8a, 1}, + Range{0x0b8e, 0x0b90, 1}, + Range{0x0b92, 0x0b95, 1}, + Range{0x0b99, 0x0b9a, 1}, + Range{0x0b9c, 0x0b9c, 1}, + Range{0x0b9e, 0x0b9f, 1}, + Range{0x0ba3, 0x0ba4, 1}, + Range{0x0ba8, 0x0baa, 1}, + Range{0x0bae, 0x0bb9, 1}, + Range{0x0bd0, 0x0bd0, 1}, + Range{0x0c05, 0x0c0c, 1}, + Range{0x0c0e, 0x0c10, 1}, + Range{0x0c12, 0x0c28, 1}, + Range{0x0c2a, 0x0c33, 1}, + Range{0x0c35, 0x0c39, 1}, + Range{0x0c3d, 0x0c3d, 1}, + Range{0x0c58, 0x0c59, 1}, + Range{0x0c60, 0x0c61, 1}, + Range{0x0c85, 0x0c8c, 1}, + Range{0x0c8e, 0x0c90, 1}, + Range{0x0c92, 0x0ca8, 1}, + Range{0x0caa, 0x0cb3, 1}, + Range{0x0cb5, 0x0cb9, 1}, + Range{0x0cbd, 0x0cde, 33}, + Range{0x0ce0, 0x0ce1, 1}, + Range{0x0d05, 0x0d0c, 1}, + Range{0x0d0e, 0x0d10, 1}, + Range{0x0d12, 0x0d28, 1}, + Range{0x0d2a, 0x0d39, 1}, + Range{0x0d3d, 0x0d3d, 1}, + Range{0x0d60, 0x0d61, 1}, + Range{0x0d7a, 0x0d7f, 1}, + Range{0x0d85, 0x0d96, 1}, + Range{0x0d9a, 0x0db1, 1}, + Range{0x0db3, 0x0dbb, 1}, + Range{0x0dbd, 0x0dbd, 1}, + Range{0x0dc0, 0x0dc6, 1}, + Range{0x0e01, 0x0e30, 1}, + Range{0x0e32, 0x0e33, 1}, + Range{0x0e40, 0x0e46, 1}, + Range{0x0e81, 0x0e82, 1}, + Range{0x0e84, 0x0e84, 1}, + Range{0x0e87, 0x0e88, 1}, + Range{0x0e8a, 0x0e8d, 3}, + Range{0x0e94, 0x0e97, 1}, + Range{0x0e99, 0x0e9f, 1}, + Range{0x0ea1, 0x0ea3, 1}, + Range{0x0ea5, 0x0ea7, 2}, + Range{0x0eaa, 0x0eab, 1}, + Range{0x0ead, 0x0eb0, 1}, + Range{0x0eb2, 0x0eb3, 1}, + Range{0x0ebd, 0x0ebd, 1}, + Range{0x0ec0, 0x0ec4, 1}, + Range{0x0ec6, 0x0ec6, 1}, + Range{0x0edc, 0x0edd, 1}, + Range{0x0f00, 0x0f00, 1}, + Range{0x0f40, 0x0f47, 1}, + Range{0x0f49, 0x0f6c, 1}, + Range{0x0f88, 0x0f8b, 1}, + Range{0x1000, 0x102a, 1}, + Range{0x103f, 0x103f, 1}, + Range{0x1050, 0x1055, 1}, + Range{0x105a, 0x105d, 1}, + Range{0x1061, 0x1061, 1}, + Range{0x1065, 0x1066, 1}, + Range{0x106e, 0x1070, 1}, + Range{0x1075, 0x1081, 1}, + Range{0x108e, 0x108e, 1}, + Range{0x10a0, 0x10c5, 1}, + Range{0x10d0, 0x10fa, 1}, + Range{0x10fc, 0x10fc, 1}, + Range{0x1100, 0x1159, 1}, + Range{0x115f, 0x11a2, 1}, + Range{0x11a8, 0x11f9, 1}, + Range{0x1200, 0x1248, 1}, + Range{0x124a, 0x124d, 1}, + Range{0x1250, 0x1256, 1}, + Range{0x1258, 0x1258, 1}, + Range{0x125a, 0x125d, 1}, + Range{0x1260, 0x1288, 1}, + Range{0x128a, 0x128d, 1}, + Range{0x1290, 0x12b0, 1}, + Range{0x12b2, 0x12b5, 1}, + Range{0x12b8, 0x12be, 1}, + Range{0x12c0, 0x12c0, 1}, + Range{0x12c2, 0x12c5, 1}, + Range{0x12c8, 0x12d6, 1}, + Range{0x12d8, 0x1310, 1}, + Range{0x1312, 0x1315, 1}, + Range{0x1318, 0x135a, 1}, + Range{0x1380, 0x138f, 1}, + Range{0x13a0, 0x13f4, 1}, + Range{0x1401, 0x166c, 1}, + Range{0x166f, 0x1676, 1}, + Range{0x1681, 0x169a, 1}, + Range{0x16a0, 0x16ea, 1}, + Range{0x1700, 0x170c, 1}, + Range{0x170e, 0x1711, 1}, + Range{0x1720, 0x1731, 1}, + Range{0x1740, 0x1751, 1}, + Range{0x1760, 0x176c, 1}, + Range{0x176e, 0x1770, 1}, + Range{0x1780, 0x17b3, 1}, + Range{0x17d7, 0x17dc, 5}, + Range{0x1820, 0x1877, 1}, + Range{0x1880, 0x18a8, 1}, + Range{0x18aa, 0x18aa, 1}, + Range{0x1900, 0x191c, 1}, + Range{0x1950, 0x196d, 1}, + Range{0x1970, 0x1974, 1}, + Range{0x1980, 0x19a9, 1}, + Range{0x19c1, 0x19c7, 1}, + Range{0x1a00, 0x1a16, 1}, + Range{0x1b05, 0x1b33, 1}, + Range{0x1b45, 0x1b4b, 1}, + Range{0x1b83, 0x1ba0, 1}, + Range{0x1bae, 0x1baf, 1}, + Range{0x1c00, 0x1c23, 1}, + Range{0x1c4d, 0x1c4f, 1}, + Range{0x1c5a, 0x1c7d, 1}, + Range{0x1d00, 0x1dbf, 1}, + Range{0x1e00, 0x1f15, 1}, + Range{0x1f18, 0x1f1d, 1}, + Range{0x1f20, 0x1f45, 1}, + Range{0x1f48, 0x1f4d, 1}, + Range{0x1f50, 0x1f57, 1}, + Range{0x1f59, 0x1f5d, 2}, + Range{0x1f5f, 0x1f7d, 1}, + Range{0x1f80, 0x1fb4, 1}, + Range{0x1fb6, 0x1fbc, 1}, + Range{0x1fbe, 0x1fbe, 1}, + Range{0x1fc2, 0x1fc4, 1}, + Range{0x1fc6, 0x1fcc, 1}, + Range{0x1fd0, 0x1fd3, 1}, + Range{0x1fd6, 0x1fdb, 1}, + Range{0x1fe0, 0x1fec, 1}, + Range{0x1ff2, 0x1ff4, 1}, + Range{0x1ff6, 0x1ffc, 1}, + Range{0x2071, 0x207f, 14}, + Range{0x2090, 0x2094, 1}, + Range{0x2102, 0x2107, 5}, + Range{0x210a, 0x2113, 1}, + Range{0x2115, 0x2115, 1}, + Range{0x2119, 0x211d, 1}, + Range{0x2124, 0x2128, 2}, + Range{0x212a, 0x212d, 1}, + Range{0x212f, 0x2139, 1}, + Range{0x213c, 0x213f, 1}, + Range{0x2145, 0x2149, 1}, + Range{0x214e, 0x214e, 1}, + Range{0x2183, 0x2184, 1}, + Range{0x2c00, 0x2c2e, 1}, + Range{0x2c30, 0x2c5e, 1}, + Range{0x2c60, 0x2c6f, 1}, + Range{0x2c71, 0x2c7d, 1}, + Range{0x2c80, 0x2ce4, 1}, + Range{0x2d00, 0x2d25, 1}, + Range{0x2d30, 0x2d65, 1}, + Range{0x2d6f, 0x2d6f, 1}, + Range{0x2d80, 0x2d96, 1}, + Range{0x2da0, 0x2da6, 1}, + Range{0x2da8, 0x2dae, 1}, + Range{0x2db0, 0x2db6, 1}, + Range{0x2db8, 0x2dbe, 1}, + Range{0x2dc0, 0x2dc6, 1}, + Range{0x2dc8, 0x2dce, 1}, + Range{0x2dd0, 0x2dd6, 1}, + Range{0x2dd8, 0x2dde, 1}, + Range{0x2e2f, 0x2e2f, 1}, + Range{0x3005, 0x3006, 1}, + Range{0x3031, 0x3035, 1}, + Range{0x303b, 0x303c, 1}, + Range{0x3041, 0x3096, 1}, + Range{0x309d, 0x309f, 1}, + Range{0x30a1, 0x30fa, 1}, + Range{0x30fc, 0x30ff, 1}, + Range{0x3105, 0x312d, 1}, + Range{0x3131, 0x318e, 1}, + Range{0x31a0, 0x31b7, 1}, + Range{0x31f0, 0x31ff, 1}, + Range{0x3400, 0x4db5, 1}, + Range{0x4e00, 0x9fc3, 1}, + Range{0xa000, 0xa48c, 1}, + Range{0xa500, 0xa60c, 1}, + Range{0xa610, 0xa61f, 1}, + Range{0xa62a, 0xa62b, 1}, + Range{0xa640, 0xa65f, 1}, + Range{0xa662, 0xa66e, 1}, + Range{0xa67f, 0xa697, 1}, + Range{0xa717, 0xa71f, 1}, + Range{0xa722, 0xa788, 1}, + Range{0xa78b, 0xa78c, 1}, + Range{0xa7fb, 0xa801, 1}, + Range{0xa803, 0xa805, 1}, + Range{0xa807, 0xa80a, 1}, + Range{0xa80c, 0xa822, 1}, + Range{0xa840, 0xa873, 1}, + Range{0xa882, 0xa8b3, 1}, + Range{0xa90a, 0xa925, 1}, + Range{0xa930, 0xa946, 1}, + Range{0xaa00, 0xaa28, 1}, + Range{0xaa40, 0xaa42, 1}, + Range{0xaa44, 0xaa4b, 1}, + Range{0xac00, 0xd7a3, 1}, + Range{0xf900, 0xfa2d, 1}, + Range{0xfa30, 0xfa6a, 1}, + Range{0xfa70, 0xfad9, 1}, + Range{0xfb00, 0xfb06, 1}, + Range{0xfb13, 0xfb17, 1}, + Range{0xfb1d, 0xfb1d, 1}, + Range{0xfb1f, 0xfb28, 1}, + Range{0xfb2a, 0xfb36, 1}, + Range{0xfb38, 0xfb3c, 1}, + Range{0xfb3e, 0xfb3e, 1}, + Range{0xfb40, 0xfb41, 1}, + Range{0xfb43, 0xfb44, 1}, + Range{0xfb46, 0xfbb1, 1}, + Range{0xfbd3, 0xfd3d, 1}, + Range{0xfd50, 0xfd8f, 1}, + Range{0xfd92, 0xfdc7, 1}, + Range{0xfdf0, 0xfdfb, 1}, + Range{0xfe70, 0xfe74, 1}, + Range{0xfe76, 0xfefc, 1}, + Range{0xff21, 0xff3a, 1}, + Range{0xff41, 0xff5a, 1}, + Range{0xff66, 0xffbe, 1}, + Range{0xffc2, 0xffc7, 1}, + Range{0xffca, 0xffcf, 1}, + Range{0xffd2, 0xffd7, 1}, + Range{0xffda, 0xffdc, 1}, + Range{0x10000, 0x1000b, 1}, + Range{0x1000d, 0x10026, 1}, + Range{0x10028, 0x1003a, 1}, + Range{0x1003c, 0x1003d, 1}, + Range{0x1003f, 0x1004d, 1}, + Range{0x10050, 0x1005d, 1}, + Range{0x10080, 0x100fa, 1}, + Range{0x10280, 0x1029c, 1}, + Range{0x102a0, 0x102d0, 1}, + Range{0x10300, 0x1031e, 1}, + Range{0x10330, 0x10340, 1}, + Range{0x10342, 0x10349, 1}, + Range{0x10380, 0x1039d, 1}, + Range{0x103a0, 0x103c3, 1}, + Range{0x103c8, 0x103cf, 1}, + Range{0x10400, 0x1049d, 1}, + Range{0x10800, 0x10805, 1}, + Range{0x10808, 0x10808, 1}, + Range{0x1080a, 0x10835, 1}, + Range{0x10837, 0x10838, 1}, + Range{0x1083c, 0x1083f, 3}, + Range{0x10900, 0x10915, 1}, + Range{0x10920, 0x10939, 1}, + Range{0x10a00, 0x10a00, 1}, + Range{0x10a10, 0x10a13, 1}, + Range{0x10a15, 0x10a17, 1}, + Range{0x10a19, 0x10a33, 1}, + Range{0x12000, 0x1236e, 1}, + Range{0x1d400, 0x1d454, 1}, + Range{0x1d456, 0x1d49c, 1}, + Range{0x1d49e, 0x1d49f, 1}, + Range{0x1d4a2, 0x1d4a2, 1}, + Range{0x1d4a5, 0x1d4a6, 1}, + Range{0x1d4a9, 0x1d4ac, 1}, + Range{0x1d4ae, 0x1d4b9, 1}, + Range{0x1d4bb, 0x1d4bb, 1}, + Range{0x1d4bd, 0x1d4c3, 1}, + Range{0x1d4c5, 0x1d505, 1}, + Range{0x1d507, 0x1d50a, 1}, + Range{0x1d50d, 0x1d514, 1}, + Range{0x1d516, 0x1d51c, 1}, + Range{0x1d51e, 0x1d539, 1}, + Range{0x1d53b, 0x1d53e, 1}, + Range{0x1d540, 0x1d544, 1}, + Range{0x1d546, 0x1d546, 1}, + Range{0x1d54a, 0x1d550, 1}, + Range{0x1d552, 0x1d6a5, 1}, + Range{0x1d6a8, 0x1d6c0, 1}, + Range{0x1d6c2, 0x1d6da, 1}, + Range{0x1d6dc, 0x1d6fa, 1}, + Range{0x1d6fc, 0x1d714, 1}, + Range{0x1d716, 0x1d734, 1}, + Range{0x1d736, 0x1d74e, 1}, + Range{0x1d750, 0x1d76e, 1}, + Range{0x1d770, 0x1d788, 1}, + Range{0x1d78a, 0x1d7a8, 1}, + Range{0x1d7aa, 0x1d7c2, 1}, + Range{0x1d7c4, 0x1d7cb, 1}, + Range{0x20000, 0x2a6d6, 1}, + Range{0x2f800, 0x2fa1d, 1}, +} + +// Is tests whether rune is in the specified table of ranges. +func Is(ranges []Range, rune int) bool { + // common case: rune is ASCII or Latin-1 + if rune < 0x100 { + for i := 0; i < len(ranges); i++ { + r := ranges[i]; + if rune > r.Hi { + continue; + } + if rune < r.Lo { + return false; + } + return (rune - r.Lo) % r.Stride == 0; + } + return false; + } + + // binary search over ranges + lo := 0; + hi := len(ranges); + for lo < hi { + m := lo + (hi - lo)/2; + r := ranges[m]; + if r.Lo <= rune && rune <= r.Hi { + return (rune - r.Lo) % r.Stride == 0; + } + if rune < r.Lo { + hi = m; + } else { + lo = m+1; + } + } + return false; +} + +// IsLetter reports whether the rune is an upper case letter. +func IsUpper(rune int) bool { + return Is(Upper, rune); +} + +// IsLetter reports whether the rune is a letter. +func IsLetter(rune int) bool { + return Is(Letter, rune); +} + diff --git a/src/pkg/unicode/letter_test.go b/src/pkg/unicode/letter_test.go new file mode 100644 index 000000000..d39d74e6b --- /dev/null +++ b/src/pkg/unicode/letter_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 unicode + +import ( + "testing"; + "unicode"; +) + +var upper = []int{ + 0x41, + 0xc0, + 0xd8, + 0x100, + 0x139, + 0x14a, + 0x178, + 0x181, + 0x376, + 0x3cf, + 0x1f2a, + 0x2102, + 0x2c00, + 0x2c10, + 0x2c20, + 0xa650, + 0xa722, + 0xff3a, + 0x10400, + 0x1d400, + 0x1d7ca, +} + +var notupper = []int{ + 0x40, + 0x5b, + 0x61, + 0x185, + 0x1b0, + 0x377, + 0x387, + 0x2150, + 0xffff, + 0x10000, +} + +var letter = []int{ + 0x41, + 0x61, + 0xaa, + 0xba, + 0xc8, + 0xdb, + 0xf9, + 0x2ec, + 0x535, + 0x6e6, + 0x93d, + 0xa15, + 0xb99, + 0xdc0, + 0xedd, + 0x1000, + 0x1200, + 0x1312, + 0x1401, + 0x1885, + 0x2c00, + 0xa800, + 0xf900, + 0xfa30, + 0xffda, + 0xffdc, + 0x10000, + 0x10300, + 0x10400, + 0x20000, + 0x2f800, + 0x2fa1d, +} + +var notletter = []int{ + 0x20, + 0x35, + 0x375, + 0x620, + 0x700, + 0xfffe, + 0x1ffff, + 0x10ffff, +} + +func TestIsLetter(t *testing.T) { + for i, r := range(upper) { + if !IsLetter(r) { + t.Errorf("IsLetter(%#x) = false, want true\n", r); + } + } + for i, r := range(letter) { + if !IsLetter(r) { + t.Errorf("IsLetter(%#x) = false, want true\n", r); + } + } + for i, r := range(notletter) { + if IsLetter(r) { + t.Errorf("IsLetter(%#x) = true, want false\n", r); + } + } +} + +func TestIsUpper(t *testing.T) { + for i, r := range(upper) { + if !IsUpper(r) { + t.Errorf("IsUpper(%#x) = false, want true\n", r); + } + } + for i, r := range(notupper) { + if IsUpper(r) { + t.Errorf("IsUpper(%#x) = true, want false\n", r); + } + } + for i, r := range(notletter) { + if IsUpper(r) { + t.Errorf("IsUpper(%#x) = true, want false\n", r); + } + } +} diff --git a/src/pkg/unsafe/unsafe.go b/src/pkg/unsafe/unsafe.go new file mode 100644 index 000000000..b19af405b --- /dev/null +++ b/src/pkg/unsafe/unsafe.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. + +/* + The unsafe package 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 uintptr can be converted to a Pointer. +// 3) 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 minimum 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 + +// Reflect unpacks an interface value into its internal value word and its type string. +// The boolean indir is true if the value is a pointer to the real value. +func Reflect(i interface {}) (value uint64, typestring string, indir bool) + +// Unreflect inverts Reflect: Given a value word, a type string, and the indirect bit, +// it returns an empty interface value with those contents. +func Unreflect(value uint64, typestring string, indir bool) (ret interface {}) diff --git a/src/pkg/utf8/Makefile b/src/pkg/utf8/Makefile new file mode 100644 index 000000000..b5ad083b2 --- /dev/null +++ b/src/pkg/utf8/Makefile @@ -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. + +# DO NOT EDIT. Automatically generated by gobuild. +# gobuild -m >Makefile + +D= + +include $(GOROOT)/src/Make.$(GOARCH) +AR=gopack + +default: packages + +clean: + rm -rf *.[$(OS)] *.a [$(OS)].out _obj + +test: packages + gotest + +coverage: packages + gotest + 6cov -g `pwd` | grep -v '_test\.go:' + +%.$O: %.go + $(GC) -I_obj $*.go + +%.$O: %.c + $(CC) $*.c + +%.$O: %.s + $(AS) $*.s + +O1=\ + utf8.$O\ + + +phases: a1 +_obj$D/utf8.a: phases + +a1: $(O1) + $(AR) grc _obj$D/utf8.a utf8.$O + rm -f $(O1) + + +newpkg: clean + mkdir -p _obj$D + $(AR) grc _obj$D/utf8.a + +$(O1): newpkg +$(O2): a1 + +nuke: clean + rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/utf8.a + +packages: _obj$D/utf8.a + +install: packages + test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D + cp _obj$D/utf8.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/utf8.a diff --git a/src/pkg/utf8/utf8.go b/src/pkg/utf8/utf8.go new file mode 100644 index 000000000..9c2ac790d --- /dev/null +++ b/src/pkg/utf8/utf8.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. + +// Functions and constants to support text encoded in UTF-8. +// This package calls a Unicode character a rune for brevity. +package utf8 + +// Numbers fundamental to the encoding. +const ( + RuneError = 0xFFFD; // the "error" Rune or "replacement character". + RuneSelf = 0x80; // characters below Runeself are represented as themselves in a single byte. + RuneMax = 0x10FFFF; // maximum Unicode code point. + 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 { + rune, size, short := decodeRuneInternal(p); + return !short +} + +// FullRuneInString is like FullRune but its input is a string. +func FullRuneInString(s string) bool { + rune, size, 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) { + var short bool; + rune, size, short = decodeRuneInternal(p); + return; +} + +// DecodeRuneInString is like DecodeRune but its input is a string. +func DecodeRuneInString(s string) (rune, size int) { + var short bool; + rune, size, short = decodeRuneInStringInternal(s); + return; +} + +// 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(rune int, p []byte) int { + if rune <= _Rune1Max { + p[0] = byte(rune); + return 1; + } + + if rune <= _Rune2Max { + p[0] = _T2 | byte(rune>>6); + p[1] = _Tx | byte(rune)&_Maskx; + return 2; + } + + if rune > RuneMax { + rune = RuneError + } + + if rune <= _Rune3Max { + p[0] = _T3 | byte(rune>>12); + p[1] = _Tx | byte(rune>>6)&_Maskx; + p[2] = _Tx | byte(rune)&_Maskx; + return 3; + } + + p[0] = _T4 | byte(rune>>18); + p[1] = _Tx | byte(rune>>12)&_Maskx; + p[2] = _Tx | byte(rune>>6)&_Maskx; + p[3] = _Tx | byte(rune)&_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 { + rune, size := DecodeRune(p[i:len(p)]); + i += size; + } + } + return n; +} + +// RuneCountInString is like RuneCount but its input is a string. +func RuneCountInString(s string) int { + ei := len(s); + i := 0; + n := 0; + for n = 0; i < ei; n++ { + if s[i] < RuneSelf { + i++; + } else { + rune, size, short := decodeRuneInStringInternal(s[i:ei]); + i += size; + } + } + return n; +} + diff --git a/src/pkg/utf8/utf8_test.go b/src/pkg/utf8/utf8_test.go new file mode 100644 index 000000000..f60b0b17e --- /dev/null +++ b/src/pkg/utf8/utf8_test.go @@ -0,0 +1,168 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package utf8 + +import ( + "bytes"; + "fmt"; + "io"; + "testing"; + "utf8"; +) + +type Utf8Map struct { + rune int; + str string; +} + +var utf8map = []Utf8Map { + Utf8Map{ 0x0000, "\x00" }, + Utf8Map{ 0x0001, "\x01" }, + Utf8Map{ 0x007e, "\x7e" }, + Utf8Map{ 0x007f, "\x7f" }, + Utf8Map{ 0x0080, "\xc2\x80" }, + Utf8Map{ 0x0081, "\xc2\x81" }, + Utf8Map{ 0x00bf, "\xc2\xbf" }, + Utf8Map{ 0x00c0, "\xc3\x80" }, + Utf8Map{ 0x00c1, "\xc3\x81" }, + Utf8Map{ 0x00c8, "\xc3\x88" }, + Utf8Map{ 0x00d0, "\xc3\x90" }, + Utf8Map{ 0x00e0, "\xc3\xa0" }, + Utf8Map{ 0x00f0, "\xc3\xb0" }, + Utf8Map{ 0x00f8, "\xc3\xb8" }, + Utf8Map{ 0x00ff, "\xc3\xbf" }, + Utf8Map{ 0x0100, "\xc4\x80" }, + Utf8Map{ 0x07ff, "\xdf\xbf" }, + Utf8Map{ 0x0800, "\xe0\xa0\x80" }, + Utf8Map{ 0x0801, "\xe0\xa0\x81" }, + Utf8Map{ 0xfffe, "\xef\xbf\xbe" }, + Utf8Map{ 0xffff, "\xef\xbf\xbf" }, + Utf8Map{ 0x10000, "\xf0\x90\x80\x80" }, + Utf8Map{ 0x10001, "\xf0\x90\x80\x81" }, + Utf8Map{ 0x10fffe, "\xf4\x8f\xbf\xbe" }, + Utf8Map{ 0x10ffff, "\xf4\x8f\xbf\xbf" }, +} + +// io.StringBytes with one extra byte at end +func makeBytes(s string) []byte { + s += "\x00"; + b := io.StringBytes(s); + return b[0:len(s)-1]; +} + +func TestFullRune(t *testing.T) { + for i := 0; i < len(utf8map); i++ { + m := utf8map[i]; + b := makeBytes(m.str); + if !utf8.FullRune(b) { + t.Errorf("FullRune(%q) (rune %04x) = false, want true", b, m.rune); + } + s := m.str; + if !utf8.FullRuneInString(s) { + t.Errorf("FullRuneInString(%q) (rune %04x) = false, want true", s, m.rune); + } + b1 := b[0:len(b)-1]; + if utf8.FullRune(b1) { + t.Errorf("FullRune(%q) = true, want false", b1); + } + s1 := string(b1); + if utf8.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 := makeBytes(m.str); + var buf [10]byte; + n := utf8.EncodeRune(m.rune, &buf); + b1 := buf[0:n]; + if !bytes.Equal(b, b1) { + t.Errorf("EncodeRune(0x%04x) = %q want %q", m.rune, b1, b); + } + } +} + +func TestDecodeRune(t *testing.T) { + for i := 0; i < len(utf8map); i++ { + m := utf8map[i]; + b := makeBytes(m.str); + rune, size := utf8.DecodeRune(b); + if rune != m.rune || size != len(b) { + t.Errorf("DecodeRune(%q) = 0x%04x, %d want 0x%04x, %d", b, rune, size, m.rune, len(b)); + } + s := m.str; + rune, size = utf8.DecodeRuneInString(s); + if rune != m.rune || size != len(b) { + t.Errorf("DecodeRune(%q) = 0x%04x, %d want 0x%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 = utf8.DecodeRune(b[0:cap(b)]); + if rune != m.rune || size != len(b) { + t.Errorf("DecodeRune(%q) = 0x%04x, %d want 0x%04x, %d", b, rune, size, m.rune, len(b)); + } + s = m.str+"\x00"; + rune, size = utf8.DecodeRuneInString(s); + if rune != m.rune || size != len(b) { + t.Errorf("DecodeRuneInString(%q) = 0x%04x, %d want 0x%04x, %d", s, rune, size, m.rune, len(b)); + } + + // make sure missing bytes fail + wantsize := 1; + if wantsize >= len(b) { + wantsize = 0; + } + rune, size = utf8.DecodeRune(b[0:len(b)-1]); + if rune != RuneError || size != wantsize { + t.Errorf("DecodeRune(%q) = 0x%04x, %d want 0x%04x, %d", b[0:len(b)-1], rune, size, RuneError, wantsize); + } + s = m.str[0:len(m.str)-1]; + rune, size = utf8.DecodeRuneInString(s); + if rune != RuneError || size != wantsize { + t.Errorf("DecodeRuneInString(%q) = 0x%04x, %d want 0x%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 = utf8.DecodeRune(b); + if rune != RuneError || size != 1 { + t.Errorf("DecodeRune(%q) = 0x%04x, %d want 0x%04x, %d", b, rune, size, RuneError, 1); + } + s = string(b); + rune, size = utf8.DecodeRune(b); + if rune != RuneError || size != 1 { + t.Errorf("DecodeRuneInString(%q) = 0x%04x, %d want 0x%04x, %d", s, rune, size, RuneError, 1); + } + } +} + +type RuneCountTest struct { + in string; + out int; +} +var runecounttests = []RuneCountTest { + RuneCountTest{ "abcd", 4 }, + RuneCountTest{ "☺☻☹", 3 }, + RuneCountTest{ "1,2,3,4", 7 }, + RuneCountTest{ "\xe2\x00", 2 }, +} +func TestRuneCount(t *testing.T) { + for i := 0; i < len(runecounttests); i++ { + tt := runecounttests[i]; + if out := utf8.RuneCountInString(tt.in); out != tt.out { + t.Errorf("RuneCountInString(%q) = %d, want %d", tt.in, out, tt.out); + } + if out := utf8.RuneCount(makeBytes(tt.in)); out != tt.out { + t.Errorf("RuneCount(%q) = %d, want %d", tt.in, out, tt.out); + } + } +} diff --git a/src/pkg/xml/xml.go b/src/pkg/xml/xml.go new file mode 100644 index 000000000..bd944337e --- /dev/null +++ b/src/pkg/xml/xml.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. + +// NOTE(rsc): Actually, this package is just a description +// of an implementation that hasn't been written yet. + +// This package implements an XML parser but relies on +// clients to implement the parsing actions. + +// An XML document is a single XML element. +// +// An XML element is either a start tag and an end tag, +// like ..., or a combined start/end tag . +// The latter is identical in semantics to , +// and this parser does not distinguish them. +// +// The start (or combined start/end) tag can have +// name="value" attributes inside the angle brackets after +// the tag name, as in Google. +// Names are drawn from a fixed set of alphabetic letters; +// Values are strings quoted with single or double quotes. +// +// An element made up of distinct start and end tags can +// contain free-form text and other elements inside it, +// as in Google +// or Google. +// The former is an element with the text "Google" inside it. +// The latter is a element with that element inside it. +// In general, an element can contain a sequence of elements +// and text inside it. In XML, white space inside an element is +// always counted as text--it is never discarded by the parser. +// XML parsers do translate \r and \r\n into \n in text. +// +// This parser reads an XML document and calls methods on a +// Builder interface object in response to the text. +// It calls the builder's StartElement, Text, and EndElement +// methods, mimicking the structure of the text. +// For example, the simple XML document: +// +// +// Google +//
+// +// results in the following sequence of builder calls: +// +// StartElement("a", []Attr(Attr("href", "http://www.google.com"))); +// Text("\n\t"); +// StartElement("img", []Attr(Attr("src", "http://www.google.com/icon.png"), +// Attr("alt", "Google"))); +// EndElement("img"); +// Text("\n"); +// StartElement("br", []Attr()); +// EndElement("br"); +// EndElement("a"); +// +// There are, of course, a few more details, but the story so far +// should be enough for the majority of uses. The details are: +// +// * XML documents typically begin with an XML declaration line like +// . +// This line is strongly recommended, but not strictly required. +// It introduces the XML version and text encoding for the rest +// of the file. XML parsers are required to recognize UTF-8 and +// UTF-16. This parser only recognizes UTF-8 (for now?). +// +// * After the XML declaration comes an optional doctype declaration like +// +// The parser should pass this information on to the client in some +// form, but does not. It discards such lines. +// +// * The XML declaration line is an instance of a more general tag +// called a processing instruction, XML's #pragma. The general form is +// , where target is a name (like "xml") specifying +// the intended recipient of the instruction, and text is the +// instruction itself. This XML parser keeps the declaration +// to itself but passes along other processing instructions using +// the ProcInst method. Processing instructions can appear anywhere +// in an XML document. Most clients will simply ignore them. +// +// * An XML comment can appear anywhere in an XML document. +// Comments have the form . The XML parser passes +// them along by calling the Comment method. Again, most clients +// will simply ignore them. +// +// * Text inside an XML element must be escaped to avoid looking like +// a start/end tag. Specifically, the characters < and & must be +// written as < and &. An alternate quoting mechanism is to +// use the construct . The quoted text ... can contain +// < characters, but not the sequence ]]>. Ampersands must still be +// escaped. For some reason, the existence of the CDATA quoting mechanism +// infects the processing of ordinary unquoted text, which is not allowed +// to contain the literal sequence ]]>. Instead, it would be written +// escaped, as in ]]>. The parser hides all these considerations +// from the library client -- it reports all text, regardless of original +// form and already unescaped, using the Text method. +// +// * A revision to XML 1.0 introduced the concept of name spaces +// for attribute and tag names. A start tag with an attribute +// xmlns:prefix="URL" introduces `prefix' as a shorthand +// for the name space whose identifier is URL. Inside the element +// with that start tag, an element name or attribute prefix:foo +// (as in ) is understood to refer +// to name `foo' in the name space denoted by `URL'. Although +// this is a shorthand, there is no canonical expansion. Thus: +// +// +// text1 +// text2 +// +// +// and +// +// +// text1 +// text2 +// +// +// are equivalent XML documents, and there is no canonical form. +// +// The special attribute xmlns="URL" sets the default name space +// for unprefixed tags (but not attribute names) to URL. +// Thus: +// +// +// text1 +// text2 +// +// +// is another XML document equivalent to the first two, and +// +// +// text1 +// text2 +// +// +// would be equivalent, except that `attr' in attr="value" has no +// associated name space, in contrast to the previous three where it +// is in the http://google.com/bar name space. +// +// The XML parser hides these details from the client by passing +// a Name struct (ns + name pair) for tag and attribute names. +// Tags and attributes without a name space have ns == "". +// +// References: +// Annotated XML spec: http://www.xml.com/axml/testaxml.htm +// XML name spaces: http://www.w3.org/TR/REC-xml-names/ + +package xml + +import ( + "io"; + "os"; +) + +// XML name, annotated with name space URL +type Name struct { + ns, name string; +} + +// XML attribute (name=value). +type Attr struct { + name Name; + value string; +} + +// XML Builder - methods client provides to Parser. +// Parser calls methods on builder as it reads and parses XML. +// If a builder method returns an error, the parse stops. +type Builder interface { + // Called when an element starts. + // Attr is list of attributes given in the tag. + // + // + // xmlns and xmlns:foo attributes are handled internally + // and not passed through to StartElement. + StartElement(name Name, attr []Attr) os.Error; + + // Called when an element ends. + // + // + EndElement(name Name) os.Error; + + // Called for non-empty character data string inside element. + // Can be called multiple times between elements. + // text + // + Text(text []byte) os.Error; + + // Called when a comment is found in the XML. + // + Comment(text []byte) os.Error; + + // Called for a processing instruction + // + ProcInst(target string, text []byte) os.Error; +} + +// Default builder. Implements no-op Builder methods. +// Embed this in your own Builders to handle the calls +// you don't care about (e.g., Comment, ProcInst). +type BaseBuilder struct { +} + +func (b *BaseBuilder) StartElement(name Name, attr []Attr) os.Error { + return nil; +} + +func (b *BaseBuilder) EndElement(name Name) os.Error { + return nil; +} + +func (b *BaseBuilder) Text(text []byte) os.Error { + return nil; +} + +func (b *BaseBuilder) Comment(text []byte) os.Error { + return nil; +} + +func (b *BaseBuilder) ProcInst(target string, text []byte) os.Error { + return nil; +} + +// XML Parser. Calls Builder methods as it parses. +func Parse(r io.Read, b Builder) os.Error { + return os.NewError("unimplemented"); +} + +// Channel interface to XML parser: create a new channel, +// go ParseTokens(r, c), and then read from the channel +// until TokenEnd. This variant has the benefit that +// the process reading the channel can be a recursive +// function instead of a set of callbacks, but it has the +// drawback that the channel interface cannot signal an +// error to cause the parser to stop early. + +// An XML parsing token. +const ( + TokenStartElement = 1 + iota; + TokenEndElement; + TokenText; + TokenComment; + TokenProcInst; + TokenEnd; +) + +type Token struct { + Kind int; // TokenStartElement, TokenEndElement, etc. + Name Name; // name (TokenStartElement, TokenEndElement) + Attr []Attr; // attributes (TokenStartElement) + Target string; // target (TokenProcessingInstruction) + Text []byte; // text (TokenCharData, TokenComment, etc.) + Err os.Error; // error (TokenEnd) +} + +type ChanBuilder chan Token; + +func (c ChanBuilder) StartElement(name Name, attr []Attr) os.Error { + var t Token; + t.Kind = TokenStartElement; + t.Name = name; + t.Attr = attr; + c <- t; + return nil; +} + +func (c ChanBuilder) EndElement(name Name) os.Error { + var t Token; + t.Kind = TokenEndElement; + t.Name = name; + c <- t; + return nil; +} + +func (c ChanBuilder) Text(text []byte) os.Error { + var t Token; + t.Kind = TokenText; + t.Text = text; + c <- t; + return nil; +} + +func (c ChanBuilder) Comment(text []byte) os.Error { + var t Token; + t.Kind = TokenComment; + t.Text = text; + c <- t; + return nil; +} + +func (c ChanBuilder) ProcInst(target string, text []byte) os.Error { + var t Token; + t.Kind = TokenProcInst; + t.Target = target; + t.Text = text; + c <- t; + return nil; +} + +func ParseToChan(r io.Read, c chan Token) { + var t Token; + t.Kind = TokenEnd; + t.Err = Parse(r, ChanBuilder(c)); + c <- t; +} + + +// scribbled notes based on XML spec. + +// document is +// xml decl? +// doctype decl? +// element +// +// if xml decl is present, must be first. after that, +// can have comments and procinsts scattered throughout, +// even after the element is done. +// +// xml decl is: +// +// <\?xml version='[a-zA-Z0-9_.:\-]+'( encoding='[A-Za-z][A-Za-z0-9._\-]*')? +// ( standalone='(yes|no)')? ?\?> +// +// spaces denote [ \r\t\n]+. +// written with '' above but can use "" too. +// +// doctype decl might as well be ]*> +// +// procinst is <\?name( .*?)\?>. name cannot be [Xx][Mm][Ll]. +// +// comment is . +// +// tags are: +// start tag +// combined start/end tag +// end tag +// (the " ?" is an optional space, not a literal question mark.) +// +// plain text is [^<&]* except cannot contain "]]>". +// can also have escaped characters: +// &#[0-9]+; +// &#x[0-9A-Fa-f]+; +// &name; +// +// can use to avoid escaping < characters. +// +// must rewrite \r and \r\n into \n in text. +// +// names are Unicode. valid chars listed below. +// +// attrib is name="value" or name='value'. +// can have spaces around =. +// attribute value text is [^<&"]* for appropriate ". +// can also use the &...; escape sequences above. +// cannot use . +// +// xmlns attributes are name=value where name has form xmlns:name +// (i.e., xmlns:123 is not okay, because 123 is not a name; xmlns:a123 is ok). +// sub-name must not start with : either. +// +// name is first(second)*. +// +// first is +// +// 003A 04D0-04EB 0A59-0A5C 0C35-0C39 0F49-0F69 1E00-1E9B +// 0041-005A 04EE-04F5 0A5E 0C60-0C61 10A0-10C5 1EA0-1EF9 +// 005F 04F8-04F9 0A72-0A74 0C85-0C8C 10D0-10F6 1F00-1F15 +// 0061-007A 0531-0556 0A85-0A8B 0C8E-0C90 1100 1F18-1F1D +// 00C0-00D6 0559 0A8D 0C92-0CA8 1102-1103 1F20-1F45 +// 00D8-00F6 0561-0586 0A8F-0A91 0CAA-0CB3 1105-1107 1F48-1F4D +// 00F8-00FF 05D0-05EA 0A93-0AA8 0CB5-0CB9 1109 1F50-1F57 +// 0100-0131 05F0-05F2 0AAA-0AB0 0CDE 110B-110C 1F59 +// 0134-013E 0621-063A 0AB2-0AB3 0CE0-0CE1 110E-1112 1F5B +// 0141-0148 0641-064A 0AB5-0AB9 0D05-0D0C 113C 1F5D +// 014A-017E 0671-06B7 0ABD 0D0E-0D10 113E 1F5F-1F7D +// 0180-01C3 06BA-06BE 0AE0 0D12-0D28 1140 1F80-1FB4 +// 01CD-01F0 06C0-06CE 0B05-0B0C 0D2A-0D39 114C 1FB6-1FBC +// 01F4-01F5 06D0-06D3 0B0F-0B10 0D60-0D61 114E 1FBE +// 01FA-0217 06D5 0B13-0B28 0E01-0E2E 1150 1FC2-1FC4 +// 0250-02A8 06E5-06E6 0B2A-0B30 0E30 1154-1155 1FC6-1FCC +// 02BB-02C1 0905-0939 0B32-0B33 0E32-0E33 1159 1FD0-1FD3 +// 0386 093D 0B36-0B39 0E40-0E45 115F-1161 1FD6-1FDB +// 0388-038A 0958-0961 0B3D 0E81-0E82 1163 1FE0-1FEC +// 038C 0985-098C 0B5C-0B5D 0E84 1165 1FF2-1FF4 +// 038E-03A1 098F-0990 0B5F-0B61 0E87-0E88 1167 1FF6-1FFC +// 03A3-03CE 0993-09A8 0B85-0B8A 0E8A 1169 2126 +// 03D0-03D6 09AA-09B0 0B8E-0B90 0E8D 116D-116E 212A-212B +// 03DA 09B2 0B92-0B95 0E94-0E97 1172-1173 212E +// 03DC 09B6-09B9 0B99-0B9A 0E99-0E9F 1175 2180-2182 +// 03DE 09DC-09DD 0B9C 0EA1-0EA3 119E 3007 +// 03E0 09DF-09E1 0B9E-0B9F 0EA5 11A8 3021-3029 +// 03E2-03F3 09F0-09F1 0BA3-0BA4 0EA7 11AB 3041-3094 +// 0401-040C 0A05-0A0A 0BA8-0BAA 0EAA-0EAB 11AE-11AF 30A1-30FA +// 040E-044F 0A0F-0A10 0BAE-0BB5 0EAD-0EAE 11B7-11B8 3105-312C +// 0451-045C 0A13-0A28 0BB7-0BB9 0EB0 11BA 4E00-9FA5 +// 045E-0481 0A2A-0A30 0C05-0C0C 0EB2-0EB3 11BC-11C2 AC00-D7A3 +// 0490-04C4 0A32-0A33 0C0E-0C10 0EBD 11EB +// 04C7-04C8 0A35-0A36 0C12-0C28 0EC0-0EC4 11F0 +// 04CB-04CC 0A38-0A39 0C2A-0C33 0F40-0F47 11F9 +// +// second is first plus +// +// 002D 06DD-06DF 09E6-09EF 0B56-0B57 0D3E-0D43 0F3E +// 002E 06E0-06E4 0A02 0B66-0B6F 0D46-0D48 0F3F +// 0030-0039 06E7-06E8 0A3C 0B82-0B83 0D4A-0D4D 0F71-0F84 +// 00B7 06EA-06ED 0A3E 0BBE-0BC2 0D57 0F86-0F8B +// 02D0 06F0-06F9 0A3F 0BC6-0BC8 0D66-0D6F 0F90-0F95 +// 02D1 0901-0903 0A40-0A42 0BCA-0BCD 0E31 0F97 +// 0300-0345 093C 0A47-0A48 0BD7 0E34-0E3A 0F99-0FAD +// 0360-0361 093E-094C 0A4B-0A4D 0BE7-0BEF 0E46 0FB1-0FB7 +// 0387 094D 0A66-0A6F 0C01-0C03 0E47-0E4E 0FB9 +// 0483-0486 0951-0954 0A70-0A71 0C3E-0C44 0E50-0E59 20D0-20DC +// 0591-05A1 0962-0963 0A81-0A83 0C46-0C48 0EB1 20E1 +// 05A3-05B9 0966-096F 0ABC 0C4A-0C4D 0EB4-0EB9 3005 +// 05BB-05BD 0981-0983 0ABE-0AC5 0C55-0C56 0EBB-0EBC 302A-302F +// 05BF 09BC 0AC7-0AC9 0C66-0C6F 0EC6 3031-3035 +// 05C1-05C2 09BE 0ACB-0ACD 0C82-0C83 0EC8-0ECD 3099 +// 05C4 09BF 0AE6-0AEF 0CBE-0CC4 0ED0-0ED9 309A +// 0640 09C0-09C4 0B01-0B03 0CC6-0CC8 0F18-0F19 309D-309E +// 064B-0652 09C7-09C8 0B3C 0CCA-0CCD 0F20-0F29 30FC-30FE +// 0660-0669 09CB-09CD 0B3E-0B43 0CD5-0CD6 0F35 +// 0670 09D7 0B47-0B48 0CE6-0CEF 0F37 +// 06D6-06DC 09E2-09E3 0B4B-0B4D 0D02-0D03 0F39 + diff --git a/src/run.bash b/src/run.bash index 85bd28655..1de6aafc2 100755 --- a/src/run.bash +++ b/src/run.bash @@ -24,13 +24,13 @@ maketest() { } maketest \ - lib \ + pkg \ # all of these are subtly different # from what maketest does. -(xcd lib/sync; +(xcd pkg/sync; make clean; time make GOMAXPROCS=10 make test diff --git a/usr/gri/pretty/astprinter.go b/usr/gri/pretty/astprinter.go index 9c1fe7439..867a84034 100644 --- a/usr/gri/pretty/astprinter.go +++ b/usr/gri/pretty/astprinter.go @@ -475,7 +475,7 @@ func (P *Printer) HtmlPackageName(pos token.Position, name string) { if P.html { sname := name[1 : len(name)-1]; // strip quotes TODO do this elsewhere eventually // TODO CAPITAL HACK BELOW FIX THIS - P.TaggedString(pos, `"`, sname, `"`); + P.TaggedString(pos, `"`, sname, `"`); } else { P.String(pos, name); } diff --git a/usr/gri/pretty/godoc.go b/usr/gri/pretty/godoc.go index 97e18952f..f2d66079a 100644 --- a/usr/gri/pretty/godoc.go +++ b/usr/gri/pretty/godoc.go @@ -80,7 +80,7 @@ var ( // file system roots goroot string; - pkgroot = flag.String("pkgroot", "src/lib", "root package source directory (if unrooted, relative to goroot)"); + pkgroot = flag.String("pkgroot", "src/pkg", "root package source directory (if unrooted, relative to goroot)"); tmplroot = flag.String("tmplroot", "usr/gri/pretty", "root template directory (if unrooted, relative to goroot)"); // periodic sync -- cgit v1.2.3