summaryrefslogtreecommitdiff
path: root/src/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg')
-rw-r--r--src/pkg/Make.deps52
-rw-r--r--src/pkg/Makefile139
-rw-r--r--src/pkg/archive/tar/Makefile60
-rw-r--r--src/pkg/archive/tar/testdata/small.txt1
-rw-r--r--src/pkg/archive/tar/testdata/small2.txt1
-rw-r--r--src/pkg/archive/tar/testdata/test.tarbin0 -> 3072 bytes
-rw-r--r--src/pkg/archive/tar/untar.go242
-rw-r--r--src/pkg/archive/tar/untar_test.go69
-rw-r--r--src/pkg/bignum/Makefile60
-rwxr-xr-xsrc/pkg/bignum/bignum.go1464
-rw-r--r--src/pkg/bignum/bignum_test.go482
-rw-r--r--src/pkg/bufio/Makefile60
-rw-r--r--src/pkg/bufio/bufio.go515
-rw-r--r--src/pkg/bufio/bufio_test.go298
-rw-r--r--src/pkg/bytes/Makefile60
-rw-r--r--src/pkg/bytes/bytes.go164
-rw-r--r--src/pkg/bytes/bytes_test.go157
-rw-r--r--src/pkg/compress/flate/Makefile60
-rw-r--r--src/pkg/compress/flate/flate_test.go131
-rw-r--r--src/pkg/compress/flate/inflate.go673
-rw-r--r--src/pkg/compress/gzip/Makefile60
-rw-r--r--src/pkg/compress/gzip/gunzip.go236
-rw-r--r--src/pkg/compress/gzip/gunzip_test.go268
-rw-r--r--src/pkg/container/list/Makefile60
-rwxr-xr-xsrc/pkg/container/list/list.go130
-rwxr-xr-xsrc/pkg/container/list/list_test.go91
-rw-r--r--src/pkg/container/vector/Makefile69
-rw-r--r--src/pkg/container/vector/intvector.go118
-rw-r--r--src/pkg/container/vector/stringvector.go118
-rw-r--r--src/pkg/container/vector/vector.go244
-rw-r--r--src/pkg/container/vector/vector_test.go209
-rw-r--r--src/pkg/crypto/aes/Makefile76
-rw-r--r--src/pkg/crypto/aes/aes_test.go353
-rw-r--r--src/pkg/crypto/aes/block.go182
-rw-r--r--src/pkg/crypto/aes/cipher.go71
-rw-r--r--src/pkg/crypto/aes/const.go363
-rw-r--r--src/pkg/crypto/block/Makefile82
-rw-r--r--src/pkg/crypto/block/cbc.go75
-rw-r--r--src/pkg/crypto/block/cbc_aes_test.go107
-rw-r--r--src/pkg/crypto/block/cfb.go100
-rw-r--r--src/pkg/crypto/block/cfb_aes_test.go316
-rw-r--r--src/pkg/crypto/block/cipher.go74
-rw-r--r--src/pkg/crypto/block/cmac.go105
-rw-r--r--src/pkg/crypto/block/cmac_aes_test.go165
-rw-r--r--src/pkg/crypto/block/ctr.go69
-rw-r--r--src/pkg/crypto/block/ctr_aes_test.go115
-rw-r--r--src/pkg/crypto/block/eax.go254
-rw-r--r--src/pkg/crypto/block/eax_aes_test.go239
-rw-r--r--src/pkg/crypto/block/ecb.go271
-rw-r--r--src/pkg/crypto/block/ecb_aes_test.go136
-rw-r--r--src/pkg/crypto/block/ecb_test.go183
-rw-r--r--src/pkg/crypto/block/ofb.go61
-rw-r--r--src/pkg/crypto/block/ofb_aes_test.go113
-rw-r--r--src/pkg/crypto/block/xor.go126
-rw-r--r--src/pkg/crypto/block/xor_test.go169
-rw-r--r--src/pkg/crypto/hmac/Makefile60
-rw-r--r--src/pkg/crypto/hmac/hmac.go104
-rw-r--r--src/pkg/crypto/hmac/hmac_test.go100
-rw-r--r--src/pkg/crypto/md5/Makefile68
-rw-r--r--src/pkg/crypto/md5/md5.go117
-rw-r--r--src/pkg/crypto/md5/md5_test.go68
-rw-r--r--src/pkg/crypto/md5/md5block.go178
-rw-r--r--src/pkg/crypto/sha1/Makefile68
-rw-r--r--src/pkg/crypto/sha1/sha1.go119
-rw-r--r--src/pkg/crypto/sha1/sha1_test.go70
-rw-r--r--src/pkg/crypto/sha1/sha1block.go86
-rw-r--r--src/pkg/datafmt/Makefile68
-rw-r--r--src/pkg/datafmt/datafmt.go789
-rw-r--r--src/pkg/datafmt/datafmt_test.go375
-rw-r--r--src/pkg/datafmt/parser.go447
-rw-r--r--src/pkg/exec/Makefile60
-rw-r--r--src/pkg/exec/exec.go228
-rw-r--r--src/pkg/exec/exec_test.go51
-rw-r--r--src/pkg/exvar/Makefile60
-rw-r--r--src/pkg/exvar/exvar.go214
-rw-r--r--src/pkg/exvar/exvar_test.go93
-rw-r--r--src/pkg/flag/Makefile60
-rw-r--r--src/pkg/flag/flag.go486
-rw-r--r--src/pkg/flag/flag_test.go77
-rw-r--r--src/pkg/fmt/Makefile68
-rw-r--r--src/pkg/fmt/fmt_test.go247
-rw-r--r--src/pkg/fmt/format.go533
-rw-r--r--src/pkg/fmt/print.go705
-rw-r--r--src/pkg/go/ast/Makefile68
-rw-r--r--src/pkg/go/ast/ast.go772
-rw-r--r--src/pkg/go/ast/format.go123
-rw-r--r--src/pkg/go/doc/Makefile68
-rw-r--r--src/pkg/go/doc/comment.go310
-rw-r--r--src/pkg/go/doc/doc.go486
-rw-r--r--src/pkg/go/parser/Makefile60
-rw-r--r--src/pkg/go/parser/parser.go1975
-rw-r--r--src/pkg/go/parser/parser_test.go68
-rw-r--r--src/pkg/go/scanner/Makefile60
-rw-r--r--src/pkg/go/scanner/scanner.go501
-rw-r--r--src/pkg/go/scanner/scanner_test.go276
-rw-r--r--src/pkg/go/token/Makefile60
-rw-r--r--src/pkg/go/token/token.go347
-rw-r--r--src/pkg/hash/Makefile60
-rw-r--r--src/pkg/hash/adler32/Makefile60
-rw-r--r--src/pkg/hash/adler32/adler32.go96
-rw-r--r--src/pkg/hash/adler32/adler32_test.go65
-rw-r--r--src/pkg/hash/crc32/Makefile60
-rw-r--r--src/pkg/hash/crc32/crc32.go120
-rw-r--r--src/pkg/hash/crc32/crc32_test.go64
-rw-r--r--src/pkg/hash/hash.go24
-rw-r--r--src/pkg/hash/test_cases.txt31
-rw-r--r--src/pkg/hash/test_gen.awk14
-rw-r--r--src/pkg/http/Makefile85
-rw-r--r--src/pkg/http/fs.go184
-rw-r--r--src/pkg/http/request.go413
-rw-r--r--src/pkg/http/server.go575
-rw-r--r--src/pkg/http/status.go101
-rw-r--r--src/pkg/http/triv.go159
-rw-r--r--src/pkg/http/url.go303
-rw-r--r--src/pkg/http/url_test.go348
-rw-r--r--src/pkg/io/Makefile70
-rw-r--r--src/pkg/io/bytebuffer.go109
-rw-r--r--src/pkg/io/bytebuffer_test.go158
-rw-r--r--src/pkg/io/io.go223
-rw-r--r--src/pkg/io/pipe.go226
-rw-r--r--src/pkg/io/pipe_test.go225
-rw-r--r--src/pkg/io/utils.go29
-rw-r--r--src/pkg/io/utils_test.go37
-rw-r--r--src/pkg/json/Makefile69
-rw-r--r--src/pkg/json/generic.go331
-rw-r--r--src/pkg/json/generic_test.go76
-rw-r--r--src/pkg/json/parse.go419
-rw-r--r--src/pkg/json/struct.go269
-rw-r--r--src/pkg/json/struct_test.go82
-rw-r--r--src/pkg/log/Makefile60
-rw-r--r--src/pkg/log/log.go195
-rw-r--r--src/pkg/log/log_test.go82
-rw-r--r--src/pkg/malloc/Makefile60
-rw-r--r--src/pkg/malloc/malloc.go24
-rw-r--r--src/pkg/math/Makefile98
-rw-r--r--src/pkg/math/all_test.go278
-rw-r--r--src/pkg/math/asin.go46
-rw-r--r--src/pkg/math/atan.go67
-rw-r--r--src/pkg/math/atan2.go28
-rw-r--r--src/pkg/math/const.go26
-rw-r--r--src/pkg/math/exp.go141
-rw-r--r--src/pkg/math/fabs.go14
-rw-r--r--src/pkg/math/floor.go25
-rw-r--r--src/pkg/math/fmod.go41
-rw-r--r--src/pkg/math/hypot.go49
-rw-r--r--src/pkg/math/log.go131
-rw-r--r--src/pkg/math/pow.go80
-rw-r--r--src/pkg/math/pow10.go37
-rw-r--r--src/pkg/math/runtime.go52
-rw-r--r--src/pkg/math/sin.go65
-rw-r--r--src/pkg/math/sinh.go70
-rw-r--r--src/pkg/math/sqrt.go66
-rw-r--r--src/pkg/math/tan.go67
-rw-r--r--src/pkg/math/tanh.go30
-rw-r--r--src/pkg/net/Makefile96
-rw-r--r--src/pkg/net/dialgoogle_test.go100
-rw-r--r--src/pkg/net/dnsclient.go227
-rw-r--r--src/pkg/net/dnsconfig.go113
-rw-r--r--src/pkg/net/dnsmsg.go679
-rw-r--r--src/pkg/net/fd.go429
-rw-r--r--src/pkg/net/fd_darwin.go115
-rw-r--r--src/pkg/net/fd_linux.go150
-rw-r--r--src/pkg/net/ip.go421
-rw-r--r--src/pkg/net/ip_test.go50
-rw-r--r--src/pkg/net/net.go862
-rw-r--r--src/pkg/net/parse.go160
-rw-r--r--src/pkg/net/parse_test.go44
-rw-r--r--src/pkg/net/port.go77
-rw-r--r--src/pkg/net/port_test.go59
-rw-r--r--src/pkg/net/server_test.go93
-rw-r--r--src/pkg/net/timeout_test.go42
-rw-r--r--src/pkg/once/Makefile60
-rw-r--r--src/pkg/once/once.go46
-rw-r--r--src/pkg/once/once_test.go31
-rw-r--r--src/pkg/os/Makefile91
-rw-r--r--src/pkg/os/dir_darwin_386.go76
-rw-r--r--src/pkg/os/dir_darwin_amd64.go76
-rw-r--r--src/pkg/os/dir_linux_386.go83
-rw-r--r--src/pkg/os/dir_linux_amd64.go79
-rw-r--r--src/pkg/os/env.go80
-rw-r--r--src/pkg/os/error.go83
-rw-r--r--src/pkg/os/exec.go101
-rw-r--r--src/pkg/os/file.go383
-rw-r--r--src/pkg/os/getwd.go94
-rw-r--r--src/pkg/os/os_test.go549
-rw-r--r--src/pkg/os/path.go121
-rw-r--r--src/pkg/os/path_test.go152
-rw-r--r--src/pkg/os/proc.go50
-rw-r--r--src/pkg/os/proc_linux.go20
-rw-r--r--src/pkg/os/stat_darwin_386.go41
-rw-r--r--src/pkg/os/stat_darwin_amd64.go41
-rw-r--r--src/pkg/os/stat_linux_386.go47
-rw-r--r--src/pkg/os/stat_linux_amd64.go41
-rw-r--r--src/pkg/os/time.go24
-rw-r--r--src/pkg/os/types.go75
-rw-r--r--src/pkg/path/Makefile60
-rw-r--r--src/pkg/path/path.go136
-rw-r--r--src/pkg/path/path_test.go136
-rw-r--r--src/pkg/rand/Makefile60
-rw-r--r--src/pkg/rand/rand.go318
-rw-r--r--src/pkg/reflect/Makefile78
-rw-r--r--src/pkg/reflect/all_test.go613
-rw-r--r--src/pkg/reflect/deepequal.go83
-rw-r--r--src/pkg/reflect/tostring.go234
-rw-r--r--src/pkg/reflect/type.go1047
-rw-r--r--src/pkg/reflect/typestring.c37
-rw-r--r--src/pkg/reflect/value.go996
-rw-r--r--src/pkg/regexp/Makefile60
-rw-r--r--src/pkg/regexp/all_test.go235
-rw-r--r--src/pkg/regexp/regexp.go764
-rw-r--r--src/pkg/runtime/386/asm.s217
-rw-r--r--src/pkg/runtime/386/closure.c104
-rw-r--r--src/pkg/runtime/386/traceback.c148
-rwxr-xr-xsrc/pkg/runtime/386/vlop.s48
-rwxr-xr-xsrc/pkg/runtime/386/vlrt.c815
-rw-r--r--src/pkg/runtime/Makefile125
-rw-r--r--src/pkg/runtime/amd64/asm.s207
-rw-r--r--src/pkg/runtime/amd64/closure.c121
-rw-r--r--src/pkg/runtime/amd64/traceback.c146
-rw-r--r--src/pkg/runtime/arm/asm.s83
-rw-r--r--src/pkg/runtime/arm/closure.c3
-rw-r--r--src/pkg/runtime/arm/traceback.s0
-rw-r--r--src/pkg/runtime/array.c175
-rw-r--r--src/pkg/runtime/cgo2c.c602
-rw-r--r--src/pkg/runtime/chan.c1024
-rw-r--r--src/pkg/runtime/darwin/386/defs.h229
-rwxr-xr-xsrc/pkg/runtime/darwin/386/rt0.s8
-rw-r--r--src/pkg/runtime/darwin/386/signal.c103
-rw-r--r--src/pkg/runtime/darwin/386/sys.s278
-rw-r--r--src/pkg/runtime/darwin/amd64/defs.h244
-rw-r--r--src/pkg/runtime/darwin/amd64/rt0.s9
-rw-r--r--src/pkg/runtime/darwin/amd64/signal.c111
-rw-r--r--src/pkg/runtime/darwin/amd64/sys.s263
-rw-r--r--src/pkg/runtime/darwin/defs.c104
-rw-r--r--src/pkg/runtime/darwin/os.h24
-rw-r--r--src/pkg/runtime/darwin/signals.h47
-rw-r--r--src/pkg/runtime/darwin/thread.c441
-rw-r--r--src/pkg/runtime/extern.go28
-rw-r--r--src/pkg/runtime/float.c173
-rw-r--r--src/pkg/runtime/float_go.cgo52
-rw-r--r--src/pkg/runtime/hashmap.c954
-rw-r--r--src/pkg/runtime/hashmap.h160
-rw-r--r--src/pkg/runtime/iface.c906
-rwxr-xr-xsrc/pkg/runtime/linux/386/defs.h136
-rwxr-xr-xsrc/pkg/runtime/linux/386/rt0.s8
-rw-r--r--src/pkg/runtime/linux/386/signal.c102
-rwxr-xr-xsrc/pkg/runtime/linux/386/sys.s222
-rw-r--r--src/pkg/runtime/linux/amd64/defs.h175
-rw-r--r--src/pkg/runtime/linux/amd64/rt0.s9
-rw-r--r--src/pkg/runtime/linux/amd64/signal.c112
-rw-r--r--src/pkg/runtime/linux/amd64/sys.s193
-rw-r--r--src/pkg/runtime/linux/arm/defs.h27
-rw-r--r--src/pkg/runtime/linux/arm/rt0.s6
-rw-r--r--src/pkg/runtime/linux/arm/signal.c4
-rw-r--r--src/pkg/runtime/linux/arm/sys.s15
-rw-r--r--src/pkg/runtime/linux/defs.c40
-rw-r--r--src/pkg/runtime/linux/defs1.c25
-rw-r--r--src/pkg/runtime/linux/defs2.c51
-rw-r--r--src/pkg/runtime/linux/defs_arm.c54
-rw-r--r--src/pkg/runtime/linux/os.h10
-rw-r--r--src/pkg/runtime/linux/signals.h47
-rw-r--r--src/pkg/runtime/linux/thread.c282
-rw-r--r--src/pkg/runtime/malloc.c308
-rw-r--r--src/pkg/runtime/malloc.h308
-rw-r--r--src/pkg/runtime/malloc_go.cgo28
-rw-r--r--src/pkg/runtime/mcache.c105
-rw-r--r--src/pkg/runtime/mcentral.c192
-rw-r--r--src/pkg/runtime/mem.c75
-rw-r--r--src/pkg/runtime/mfixalloc.c56
-rw-r--r--src/pkg/runtime/mgc0.c231
-rw-r--r--src/pkg/runtime/mheap.c333
-rw-r--r--src/pkg/runtime/mheapmap32.c96
-rw-r--r--src/pkg/runtime/mheapmap32.h76
-rw-r--r--src/pkg/runtime/mheapmap64.c117
-rw-r--r--src/pkg/runtime/mheapmap64.h96
-rw-r--r--src/pkg/runtime/msize.c165
-rw-r--r--src/pkg/runtime/print.c268
-rw-r--r--src/pkg/runtime/proc.c858
-rw-r--r--src/pkg/runtime/rune.c224
-rw-r--r--src/pkg/runtime/runtime.c462
-rw-r--r--src/pkg/runtime/runtime.h464
-rw-r--r--src/pkg/runtime/sema.c176
-rw-r--r--src/pkg/runtime/sema_go.cgo15
-rw-r--r--src/pkg/runtime/string.c263
-rw-r--r--src/pkg/runtime/symtab.c377
-rw-r--r--src/pkg/sort/Makefile60
-rw-r--r--src/pkg/sort/sort.go187
-rw-r--r--src/pkg/sort/sort_test.go229
-rw-r--r--src/pkg/strconv/Makefile79
-rw-r--r--src/pkg/strconv/atof.go372
-rw-r--r--src/pkg/strconv/atof_test.go133
-rw-r--r--src/pkg/strconv/atoi.go166
-rw-r--r--src/pkg/strconv/atoi_test.go188
-rw-r--r--src/pkg/strconv/decimal.go392
-rw-r--r--src/pkg/strconv/decimal_test.go119
-rw-r--r--src/pkg/strconv/fp_test.go149
-rw-r--r--src/pkg/strconv/ftoa.go418
-rw-r--r--src/pkg/strconv/ftoa_test.go119
-rw-r--r--src/pkg/strconv/itoa.go49
-rw-r--r--src/pkg/strconv/itoa_test.go111
-rw-r--r--src/pkg/strconv/quote.go229
-rw-r--r--src/pkg/strconv/quote_test.go170
-rw-r--r--src/pkg/strconv/testfp.txt181
-rw-r--r--src/pkg/strings/Makefile60
-rw-r--r--src/pkg/strings/strings.go178
-rw-r--r--src/pkg/strings/strings_test.go133
-rw-r--r--src/pkg/sync/Makefile61
-rw-r--r--src/pkg/sync/asm_386.s23
-rw-r--r--src/pkg/sync/asm_amd64.s23
-rw-r--r--src/pkg/sync/mutex.go114
-rw-r--r--src/pkg/sync/mutex_test.go53
-rw-r--r--src/pkg/syscall/Makefile97
-rwxr-xr-xsrc/pkg/syscall/PORT124
-rw-r--r--src/pkg/syscall/asm_darwin_386.s83
-rw-r--r--src/pkg/syscall/asm_darwin_amd64.s74
-rw-r--r--src/pkg/syscall/asm_linux_386.s108
-rw-r--r--src/pkg/syscall/asm_linux_amd64.s78
-rw-r--r--src/pkg/syscall/errstr.go30
-rw-r--r--src/pkg/syscall/exec.go305
-rwxr-xr-xsrc/pkg/syscall/mkerrors94
-rwxr-xr-xsrc/pkg/syscall/mksyscall170
-rwxr-xr-xsrc/pkg/syscall/mksysnum_darwin38
-rwxr-xr-xsrc/pkg/syscall/mksysnum_linux31
-rw-r--r--src/pkg/syscall/syscall.go37
-rw-r--r--src/pkg/syscall/syscall_darwin.go663
-rw-r--r--src/pkg/syscall/syscall_darwin_386.go49
-rw-r--r--src/pkg/syscall/syscall_darwin_amd64.go49
-rw-r--r--src/pkg/syscall/syscall_linux.go636
-rw-r--r--src/pkg/syscall/syscall_linux_386.go100
-rw-r--r--src/pkg/syscall/syscall_linux_amd64.go41
-rw-r--r--src/pkg/syscall/types_darwin.c226
-rw-r--r--src/pkg/syscall/types_darwin_386.c1
-rw-r--r--src/pkg/syscall/types_darwin_amd64.c1
-rw-r--r--src/pkg/syscall/types_linux.c217
-rw-r--r--src/pkg/syscall/types_linux_386.c1
-rw-r--r--src/pkg/syscall/types_linux_amd64.c1
-rw-r--r--src/pkg/syscall/zerrors_darwin_386.go260
-rw-r--r--src/pkg/syscall/zerrors_darwin_amd64.go260
-rw-r--r--src/pkg/syscall/zerrors_linux_386.go316
-rw-r--r--src/pkg/syscall/zerrors_linux_amd64.go316
-rw-r--r--src/pkg/syscall/zsyscall_darwin_386.go624
-rw-r--r--src/pkg/syscall/zsyscall_darwin_amd64.go624
-rw-r--r--src/pkg/syscall/zsyscall_linux_386.go720
-rw-r--r--src/pkg/syscall/zsyscall_linux_amd64.go764
-rw-r--r--src/pkg/syscall/zsysnum_darwin_386.go485
-rw-r--r--src/pkg/syscall/zsysnum_darwin_amd64.go485
-rw-r--r--src/pkg/syscall/zsysnum_linux_386.go319
-rw-r--r--src/pkg/syscall/zsysnum_linux_amd64.go296
-rw-r--r--src/pkg/syscall/ztypes_darwin_386.go246
-rw-r--r--src/pkg/syscall/ztypes_darwin_amd64.go248
-rw-r--r--src/pkg/syscall/ztypes_linux_386.go297
-rw-r--r--src/pkg/syscall/ztypes_linux_amd64.go300
-rw-r--r--src/pkg/tabwriter/Makefile60
-rw-r--r--src/pkg/tabwriter/tabwriter.go437
-rw-r--r--src/pkg/tabwriter/tabwriter_test.go380
-rw-r--r--src/pkg/template/Makefile68
-rw-r--r--src/pkg/template/format.go54
-rw-r--r--src/pkg/template/template.go808
-rw-r--r--src/pkg/template/template_test.go331
-rw-r--r--src/pkg/testing/Makefile60
-rw-r--r--src/pkg/testing/iotest/Makefile61
-rw-r--r--src/pkg/testing/iotest/logger.go55
-rw-r--r--src/pkg/testing/iotest/reader.go44
-rw-r--r--src/pkg/testing/testing.go155
-rw-r--r--src/pkg/time/Makefile77
-rw-r--r--src/pkg/time/sleep.go17
-rw-r--r--src/pkg/time/tick.go62
-rw-r--r--src/pkg/time/tick_test.go29
-rw-r--r--src/pkg/time/time.go372
-rw-r--r--src/pkg/time/time_test.go85
-rw-r--r--src/pkg/time/zoneinfo.go285
-rw-r--r--src/pkg/unicode/Makefile68
-rw-r--r--src/pkg/unicode/decimaldigit.go52
-rw-r--r--src/pkg/unicode/decimaldigit_test.go375
-rw-r--r--src/pkg/unicode/letter.go578
-rw-r--r--src/pkg/unicode/letter_test.go129
-rw-r--r--src/pkg/unsafe/unsafe.go44
-rw-r--r--src/pkg/utf8/Makefile60
-rw-r--r--src/pkg/utf8/utf8.go291
-rw-r--r--src/pkg/utf8/utf8_test.go168
-rw-r--r--src/pkg/xml/xml.go426
381 files changed, 73008 insertions, 0 deletions
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
--- /dev/null
+++ b/src/pkg/archive/tar/testdata/test.tar
Binary files 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;
+ const M2 = _B2 - 1;
+
+ // split x and y into sub-digits
+ // x = (x1*B2 + x0)
+ // y = (y1*B2 + y0)
+ x1, x0 := x>>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 + t0)&_M;
+ z1 := t2<<DW + (t1 + t0>>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<<m);
+ for i := uint(0); i < 100; i++ {
+ nat_eq(i, b.Shl(i*m), p);
+ p = mul(p, f);
+ }
+ }
+
+ test_msg = "NatShift3R";
+ { p := c;
+ for i := uint(0); !p.IsZero(); i++ {
+ nat_eq(i, c.Shr(i), p);
+ p = p.Shr(1);
+ }
+ }
+}
+
+
+func TestIntShift(t *testing.T) {
+ tester = t;
+ test_msg = "IntShift1L";
+ test(0, ip.Shl(0).Cmp(ip) == 0);
+ test(1, ip.Shl(1).Cmp(ip) > 0);
+
+ test_msg = "IntShift1R";
+ test(0, ip.Shr(0).Cmp(ip) == 0);
+ test(1, ip.Shr(1).Cmp(ip) < 0);
+
+ test_msg = "IntShift2";
+ for i := uint(0); i < 100; i++ {
+ test(i, ip.Shl(i).Shr(i).Cmp(ip) == 0);
+ }
+
+ test_msg = "IntShift3L";
+ { const m = 3;
+ p := ip;
+ f := bignum.Int(1<<m);
+ for i := uint(0); i < 100; i++ {
+ int_eq(i, ip.Shl(i*m), p);
+ p = p.Mul(f);
+ }
+ }
+
+ test_msg = "IntShift3R";
+ { p := ip;
+ for i := uint(0); p.IsPos(); i++ {
+ int_eq(i, ip.Shr(i), p);
+ p = p.Shr(1);
+ }
+ }
+
+ test_msg = "IntShift4R";
+ //int_eq(0, bignum.Int(-43).Shr(1), bignum.Int(-43 >> 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 - 1));
+ f.b >>= 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 - 1));
+ f.b >>= 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 - 1));
+ f.b >>= nb;
+ f.nb -= nb;
+ dist = 1<<(nb+1) + 1 + extra;
+ }
+
+ // Copy history[-dist:-dist+length] into output.
+ if dist > len(f.hist) {
+ 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<<n - 1));
+ v <<= 16 - n;
+ v = int(reverseByte[v>>8]) | int(reverseByte[v&0xFF])<<8; // reverse bits
+ if v <= lim {
+ f.b >>= n;
+ f.nb -= n;
+ return h.codes[v - h.base[n]], nil;
+ }
+ }
+ return 0, CorruptInputError(f.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<<n, i == b * xⁿ
+
+ if j & k != 0 {
+ // s += i in GF(2); xor in binary
+ s ^= i;
+ j ^= k; // turn off bit to end loop early
+ }
+
+ // i *= x in GF(2) modulo the polynomial
+ i <<= 1;
+ if i & 0x100 != 0 {
+ i ^= poly;
+ }
+ }
+ return s;
+}
+
+// Test all mul inputs against bit-by-bit n² algorithm.
+func TestMul(t *testing.T) {
+ for i := uint32(0); i < 256; i++ {
+ for j := uint32(0); j < 256; j++ {
+ // Multiply i, j bit by bit.
+ s := uint8(0);
+ for k := uint(0); k < 8; k++ {
+ for l := uint(0); l < 8; l++ {
+ if i & (1<<k) != 0 && j & (1<<l) != 0 {
+ s ^= powx[k+l];
+ }
+ }
+ }
+ if x := mul(i, j); x != uint32(s) {
+ t.Fatalf("mul(%#x, %#x) = %#x, want %#x", i, j, x, s);
+ }
+ }
+ }
+}
+
+// Check that S-boxes are inverses of each other.
+// They have more structure that we could test,
+// but if this sanity check passes, we'll assume
+// the cut and paste from the FIPS PDF worked.
+func TestSboxes(t *testing.T) {
+ for i := 0; i < 256; i++ {
+ if j := sbox0[sbox1[i]]; j != byte(i) {
+ t.Errorf("sbox0[sbox1[%#x]] = %#x", i, j);
+ }
+ if j := sbox1[sbox0[i]]; j != byte(i) {
+ t.Errorf("sbox1[sbox0[%#x]] = %#x", i, j);
+ }
+ }
+}
+
+// Test that encryption tables are correct.
+// (Can adapt this code to generate them too.)
+func TestTe(t *testing.T) {
+ for i := 0; i < 256; i++ {
+ s := uint32(sbox0[i]);
+ s2 := mul(s, 2);
+ s3 := mul(s, 3);
+ w := s2<<24 | s<<16 | s<<8 | s3;
+ for j := 0; j < 4; j++ {
+ if x := te[j][i]; x != w {
+ t.Fatalf("te[%d][%d] = %#x, want %#x", j, i, x, w);
+ }
+ w = w<<24 | w>>8;
+ }
+ }
+}
+
+// Test that decryption tables are correct.
+// (Can adapt this code to generate them too.)
+func TestTd(t *testing.T) {
+ for i := 0; i < 256; i++ {
+ s := uint32(sbox1[i]);
+ s9 := mul(s, 0x9);
+ sb := mul(s, 0xb);
+ sd := mul(s, 0xd);
+ se := mul(s, 0xe);
+ w := se<<24 | s9<<16 | sd<<8 | sb;
+ for j := 0; j < 4; j++ {
+ if x := td[j][i]; x != w {
+ t.Fatalf("td[%d][%d] = %#x, want %#x", j, i, x, w);
+ }
+ w = w<<24 | w>>8;
+ }
+ }
+}
+
+// Test vectors are from FIPS 197:
+// http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf
+
+// Appendix A of FIPS 197: Key expansion examples
+type KeyTest struct {
+ key []byte;
+ enc []uint32;
+ dec []uint32; // decryption expansion; not in FIPS 197, computed from C implementation.
+}
+
+var keyTests = []KeyTest {
+ 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 <vincent.rijmen@esat.kuleuven.ac.be>
+// @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
+// @author Paulo Barreto <paulo.barreto@terra.com.br>
+//
+// This code is hereby placed in the public domain.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
+// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// See FIPS 197 for specification, and see Daemen and Rijmen's Rijndael submission
+// for implementation details.
+// http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf
+// http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf
+
+package aes
+
+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<<s | 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<<s | 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<<s | 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<<s | 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 <nil>]" },
+ fmtTest{ "%v", &array, "&[1 2 3 4 5]" },
+ fmtTest{ "%v", &iarray, "&[1 hello 2.5 <nil>]" },
+
+ // 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 = "<nil>"
+ } 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 = "<nil>"
+ } 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 = "<nil>"
+ } 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 &copy;
+}
+
+
+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("&ldquo;");
+ rdquo = io.StringBytes("&rdquo;");
+)
+
+// Escape comment text for HTML.
+// Also, turn `` into &ldquo; and '' into &rdquo;.
+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("<p>\n");
+ html_endp = io.StringBytes("</p>\n");
+ html_pre = io.StringBytes("<pre>");
+ html_endpre = io.StringBytes("</pre>\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 </p><p>
+// Turn each run of indented lines into <pre> 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 = "<EOF>";
+ 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, "<pre>\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, "<a href=\"%s\">%s</a>\n", name, name);
+ }
+ }
+ fmt.Fprintf(c, "</pre>\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 := "<a href=\"%v\">" + statusText[code] + "</a>.\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; i<len(pow10tab); i++ {
+ m := i/2;
+ pow10tab[i] = pow10tab[m] * pow10tab[i-m];
+ }
+}
diff --git a/src/pkg/math/runtime.go b/src/pkg/math/runtime.go
new file mode 100644
index 000000000..69d333825
--- /dev/null
+++ b/src/pkg/math/runtime.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 math
+
+// implemented in C, in ../../runtime
+// perhaps one day the implementations will move here.
+
+// Float32bits returns the IEEE 754 binary representation of f.
+func Float32bits(f float32) (b uint32)
+
+// Float32frombits returns the floating point number corresponding
+// to the IEEE 754 binary representation b.
+func Float32frombits(b uint32) (f float32)
+
+// Float64bits returns the IEEE 754 binary representation of f.
+func Float64bits(f float64) (b uint64)
+
+// Float64frombits returns the floating point number corresponding
+// the IEEE 754 binary representation b.
+func Float64frombits(b uint64) (f float64)
+
+// Frexp breaks f into a normalized fraction
+// and an integral power of two.
+// It returns frac and exp satisfying f == frac × 2<sup>exp</sup>,
+// 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 × 2<sup>exp</sup>.
+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; i<n; i++ {
+ m[i] = i;
+ }
+ for i:=0; i<n; i++ {
+ j := Intn(n);
+ m[i],m[j] = m[j],m[i];
+ }
+ return m;
+}
+
+func init() {
+ Seed(1);
+}
diff --git a/src/pkg/reflect/Makefile b/src/pkg/reflect/Makefile
new file mode 100644
index 000000000..d622ffd51
--- /dev/null
+++ b/src/pkg/reflect/Makefile
@@ -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.
+
+# 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=\
+ 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{<can't iterate on maps>}");
+ 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 += "<can't iterate on maps>";
+ 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<no match>");
+ } 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<no match>");
+ } 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<siz; i+=4) {
+ // MOVSL
+ *p++ = 0xa5;
+ }
+ } else {
+ // MOVL $(siz/4), CX [32-bit immediate siz/4]
+ *p++ = 0xc7;
+ *p++ = 0xc1;
+ *(uint32*)p = siz/4;
+ p += 4;
+
+ // REP; MOVSL
+ *p++ = 0xf3;
+ *p++ = 0xa5;
+ }
+
+ // call fn
+ pcrel = fn - (p+5);
+ // direct call with pc-relative offset
+ // CALL fn
+ *p++ = 0xe8;
+ *(int32*)p = pcrel;
+ p += 4;
+
+ // ADDL $siz, SP
+ *p++ = 0x81;
+ *p++ = 0xc4;
+ *(uint32*)p = siz;
+ p += 4;
+
+ // RET
+ *p++ = 0xc3;
+
+ if(p > q)
+ 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<siz; i+=8) {
+ // MOVSQ
+ *p++ = 0x48;
+ *p++ = 0xa5;
+ }
+ } else {
+ // MOVQ $(siz/8), CX [32-bit immediate siz/8]
+ *p++ = 0x48;
+ *p++ = 0xc7;
+ *p++ = 0xc1;
+ *(uint32*)p = siz/8;
+ p += 4;
+
+ // REP; MOVSQ
+ *p++ = 0xf3;
+ *p++ = 0x48;
+ *p++ = 0xa5;
+ }
+
+
+ // call fn
+ pcrel = fn - (p+5);
+ if((int32)pcrel == pcrel) {
+ // can use direct call with pc-relative offset
+ // CALL fn
+ *p++ = 0xe8;
+ *(int32*)p = pcrel;
+ p += 4;
+ } else {
+ // MOVQ $fn, CX [64-bit immediate fn]
+ *p++ = 0x48;
+ *p++ = 0xb9;
+ *(byte**)p = fn;
+ p += 8;
+
+ // CALL *CX
+ *p++ = 0xff;
+ *p++ = 0xd1;
+ }
+
+ // ADDQ $siz, SP
+ *p++ = 0x48;
+ *p++ = 0x81;
+ *p++ = 0xc4;
+ *(uint32*)p = siz;
+ p += 4;
+
+ // RET
+ *p++ = 0xc3;
+
+ if(p > q)
+ 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
--- /dev/null
+++ b/src/pkg/runtime/arm/traceback.s
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 <assert.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+/* 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, &params, &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 = "<stdin>";
+ 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; i<hint; i++) {
+ d = mal(sizeof(*d) + c->elemsize - 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; i<sel->ncase; 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; i<sel->ncase; 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; i<NSIG; i++) {
+ if(sigtab[i].flags) {
+ if(sigtab[i].flags & SigCatch) {
+ sa.__sigaction_u.__sa_sigaction = sighandler;
+ } else {
+ sa.__sigaction_u.__sa_sigaction = sigignore;
+ }
+ if(sigtab[i].flags & SigRestart)
+ sa.sa_flags |= SA_RESTART;
+ else
+ sa.sa_flags &= ~SA_RESTART;
+ sigaction(i, &sa, nil);
+ }
+ }
+}
+
diff --git a/src/pkg/runtime/darwin/386/sys.s b/src/pkg/runtime/darwin/386/sys.s
new file mode 100644
index 000000000..bbcb622d5
--- /dev/null
+++ b/src/pkg/runtime/darwin/386/sys.s
@@ -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.
+
+// System calls and other sys.stuff for 386, Darwin
+// See http://fxr.watson.org/fxr/source/bsd/kern/syscalls.c?v=xnu-1228
+// or /usr/include/sys/syscall.h (on a Mac) for system call numbers.
+
+TEXT notok(SB),7,$0
+ MOVL $0xf1, 0xf1
+ RET
+
+// Exit the entire program (like C exit)
+TEXT exit(SB),7,$0
+ MOVL $1, AX
+ INT $0x80
+ CALL notok(SB)
+ RET
+
+// Exit this OS thread (like pthread_exit, which eventually
+// calls __bsdthread_terminate).
+TEXT exit1(SB),7,$0
+ MOVL $361, AX
+ INT $0x80
+ JAE 2(PC)
+ CALL notok(SB)
+ RET
+
+TEXT sys·write(SB),7,$0
+ MOVL $4, AX
+ INT $0x80
+ JAE 2(PC)
+ CALL notok(SB)
+ RET
+
+TEXT sys·mmap(SB),7,$0
+ MOVL $197, AX
+ INT $0x80
+ JAE 2(PC)
+ CALL notok(SB)
+ RET
+
+TEXT sigaction(SB),7,$0
+ MOVL $46, AX
+ INT $0x80
+ JAE 2(PC)
+ CALL notok(SB)
+ RET
+
+// Sigtramp's job is to call the actual signal handler.
+// It is called with the following arguments on the stack:
+// 0(FP) "return address" - ignored
+// 4(FP) actual handler
+// 8(FP) siginfo style - ignored
+// 12(FP) signal number
+// 16(FP) siginfo
+// 20(FP) context
+TEXT sigtramp(SB),7,$40
+ MOVL 4(FS), BP // m
+ MOVL 28(BP), BP // m->gsignal
+ 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; i<NSIG; i++) {
+ if(sigtab[i].flags) {
+ if(sigtab[i].flags & SigCatch) {
+ sa.__sigaction_u.__sa_sigaction = sighandler;
+ } else {
+ sa.__sigaction_u.__sa_sigaction = sigignore;
+ }
+ if(sigtab[i].flags & SigRestart)
+ sa.sa_flags |= SA_RESTART;
+ else
+ sa.sa_flags &= ~SA_RESTART;
+ sigaction(i, &sa, nil);
+ }
+ }
+}
+
diff --git a/src/pkg/runtime/darwin/amd64/sys.s b/src/pkg/runtime/darwin/amd64/sys.s
new file mode 100644
index 000000000..b46c823ae
--- /dev/null
+++ b/src/pkg/runtime/darwin/amd64/sys.s
@@ -0,0 +1,263 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//
+// System calls and other sys.stuff for AMD64, Darwin
+// See http://fxr.watson.org/fxr/source/bsd/kern/syscalls.c?v=xnu-1228
+// or /usr/include/sys/syscall.h (on a Mac) for system call numbers.
+//
+
+// Exit the entire program (like C exit)
+TEXT exit(SB),7,$-8
+ MOVL 8(SP), DI // arg 1 exit status
+ MOVL $(0x2000000+1), AX // syscall entry
+ SYSCALL
+ CALL notok(SB)
+ RET
+
+// Exit this OS thread (like pthread_exit, which eventually
+// calls __bsdthread_terminate).
+TEXT exit1(SB),7,$-8
+ MOVL 8(SP), DI // arg 1 exit status
+ MOVL $(0x2000000+361), AX // syscall entry
+ SYSCALL
+ CALL notok(SB)
+ RET
+
+TEXT sys·write(SB),7,$-8
+ MOVL 8(SP), DI // arg 1 fid
+ MOVQ 16(SP), SI // arg 2 buf
+ MOVL 24(SP), DX // arg 3 count
+ MOVL $(0x2000000+4), AX // syscall entry
+ SYSCALL
+ JCC 2(PC)
+ CALL notok(SB)
+ RET
+
+TEXT open(SB),7,$-8
+ MOVQ 8(SP), DI
+ MOVL 16(SP), SI
+ MOVL 20(SP), DX
+ MOVQ $0, R10
+ MOVL $(0x2000000+5), AX // syscall entry
+ SYSCALL
+ RET
+
+TEXT close(SB),7,$-8
+ MOVL 8(SP), DI
+ MOVL $(0x2000000+6), AX // syscall entry
+ SYSCALL
+ RET
+
+TEXT fstat(SB),7,$-8
+ MOVL 8(SP), DI
+ MOVQ 16(SP), SI
+ MOVL $(0x2000000+339), AX // syscall entry; really fstat64
+ SYSCALL
+ RET
+
+TEXT read(SB),7,$-8
+ MOVL 8(SP), DI
+ MOVQ 16(SP), SI
+ MOVL 24(SP), DX
+ MOVL $(0x2000000+3), AX // syscall entry
+ SYSCALL
+ RET
+
+TEXT write(SB),7,$-8
+ MOVL 8(SP), DI
+ MOVQ 16(SP), SI
+ MOVL 24(SP), DX
+ MOVL $(0x2000000+4), AX // syscall entry
+ SYSCALL
+ RET
+
+TEXT sigaction(SB),7,$-8
+ MOVL 8(SP), DI // arg 1 sig
+ MOVQ 16(SP), SI // arg 2 act
+ MOVQ 24(SP), DX // arg 3 oact
+ MOVQ 24(SP), CX // arg 3 oact
+ MOVQ 24(SP), R10 // arg 3 oact
+ MOVL $(0x2000000+46), AX // syscall entry
+ SYSCALL
+ JCC 2(PC)
+ CALL notok(SB)
+ RET
+
+TEXT sigtramp(SB),7,$40
+ MOVQ 32(R14), R15 // g = m->gsignal
+ 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 <mach/mach.h>
+#include <mach/message.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <sys/mman.h>
+
+enum {
+ $PROT_NONE = PROT_NONE,
+ $PROT_READ = PROT_READ,
+ $PROT_WRITE = PROT_WRITE,
+ $PROT_EXEC = PROT_EXEC,
+
+ $MAP_ANON = MAP_ANON,
+ $MAP_PRIVATE = MAP_PRIVATE,
+
+ $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; i<h->msgh_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; i<h->msgh_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; i<type.len; i++)
+ h = h*37 + type.str[i];
+ h += indir;
+ h %= nelem(fake);
+
+ for(locked=0; locked<2; locked++) {
+ if(locked)
+ lock(&ifacelock);
+ for(sigt = fake[h]; sigt != nil; sigt = sigt->link) {
+ // 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; i<nelem(cmp); i++) {
+ if(mcmp((byte*)sigt->name, (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; i<NSIG; i++) {
+ if(sigtab[i].flags) {
+ if(sigtab[i].flags & SigCatch)
+ *(void**)sa._u = (void*)sigtramp; // handler
+ else
+ *(void**)sa._u = (void*)sigignore; // handler
+ if(sigtab[i].flags & SigRestart)
+ sa.sa_flags |= SA_RESTART;
+ else
+ sa.sa_flags &= ~SA_RESTART;
+ rt_sigaction(i, &sa, nil, 8);
+ }
+ }
+}
+
diff --git a/src/pkg/runtime/linux/386/sys.s b/src/pkg/runtime/linux/386/sys.s
new file mode 100755
index 000000000..419973a5c
--- /dev/null
+++ b/src/pkg/runtime/linux/386/sys.s
@@ -0,0 +1,222 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//
+// System calls and other sys.stuff for 386, Linux
+//
+
+TEXT syscall(SB),7,$0
+ MOVL 4(SP), AX // syscall number
+ MOVL 8(SP), BX // arg1
+ MOVL 12(SP), CX // arg2
+ MOVL 16(SP), DX // arg3
+ MOVL 20(SP), SI // arg4
+ MOVL 24(SP), DI // arg5
+ MOVL 28(SP), BP // arg6
+ INT $0x80
+ CMPL AX, $0xfffff001
+ JLS 2(PC)
+ INT $3 // not reached
+ RET
+
+TEXT exit(SB),7,$0
+ MOVL $252, AX // syscall number
+ MOVL 4(SP), BX
+ INT $0x80
+ INT $3 // not reached
+ RET
+
+TEXT exit1(SB),7,$0
+ MOVL $1, AX // exit - exit the current os thread
+ MOVL 4(SP), BX
+ INT $0x80
+ INT $3 // not reached
+ RET
+
+TEXT write(SB),7,$0
+ MOVL $4, AX // syscall - write
+ MOVL 4(SP), BX
+ MOVL 8(SP), CX
+ MOVL 12(SP), DX
+ INT $0x80
+ RET
+
+TEXT getpid(SB),7,$0
+ MOVL $20, AX
+ INT $0x80
+ RET
+
+TEXT kill(SB),7,$0
+ MOVL $37, AX
+ MOVL 4(SP), BX
+ MOVL 8(SP), CX
+ INT $0x80
+ RET
+
+TEXT sys·write(SB),7,$0
+ MOVL $4, AX // syscall - write
+ MOVL 4(SP), BX
+ MOVL 8(SP), CX
+ MOVL 12(SP), DX
+ INT $0x80
+ RET
+
+TEXT rt_sigaction(SB),7,$0
+ MOVL $174, AX // syscall - rt_sigaction
+ MOVL 4(SP), BX
+ MOVL 8(SP), CX
+ MOVL 12(SP), DX
+ MOVL 16(SP), SI
+ INT $0x80
+ RET
+
+TEXT sigtramp(SB),7,$0
+ MOVL 4(FS), BP // m
+ MOVL 20(BP), AX // m->gsignal
+ 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
+// <asm-i386/ldt.h>
+// struct user_desc {
+// unsigned int entry_number;
+// unsigned long base_addr;
+// unsigned int limit;
+// unsigned int seg_32bit:1;
+// unsigned int contents:2;
+// unsigned int read_exec_only:1;
+// unsigned int limit_in_pages:1;
+// unsigned int seg_not_present:1;
+// unsigned int useable:1;
+// };
+#define SEG_32BIT 0x01
+// contents are the 2 bits 0x02 and 0x04.
+#define CONTENTS_DATA 0x00
+#define CONTENTS_STACK 0x02
+#define CONTENTS_CODE 0x04
+#define READ_EXEC_ONLY 0x08
+#define LIMIT_IN_PAGES 0x10
+#define SEG_NOT_PRESENT 0x20
+#define USEABLE 0x40
+
+// setldt(int entry, int address, int limit)
+TEXT 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; i<NSIG; i++) {
+ if(sigtab[i].flags) {
+ if(sigtab[i].flags & SigCatch)
+ sa.sa_handler = (void*)sigtramp;
+ else
+ sa.sa_handler = (void*)sigignore;
+ if(sigtab[i].flags & SigRestart)
+ sa.sa_flags |= SA_RESTART;
+ else
+ sa.sa_flags &= ~SA_RESTART;
+ rt_sigaction(i, &sa, nil, 8);
+ }
+ }
+}
+
diff --git a/src/pkg/runtime/linux/amd64/sys.s b/src/pkg/runtime/linux/amd64/sys.s
new file mode 100644
index 000000000..f90c704fa
--- /dev/null
+++ b/src/pkg/runtime/linux/amd64/sys.s
@@ -0,0 +1,193 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//
+// System calls and other sys.stuff for AMD64, Linux
+//
+
+TEXT exit(SB),7,$0-8
+ MOVL 8(SP), DI
+ MOVL $231, AX // exitgroup - force all os threads to exi
+ SYSCALL
+ RET
+
+TEXT exit1(SB),7,$0-8
+ MOVL 8(SP), DI
+ MOVL $60, AX // exit - exit the current os thread
+ SYSCALL
+ RET
+
+TEXT open(SB),7,$0-16
+ MOVQ 8(SP), DI
+ MOVL 16(SP), SI
+ MOVL 20(SP), DX
+ MOVL $2, AX // syscall entry
+ SYSCALL
+ RET
+
+TEXT close(SB),7,$0-8
+ MOVL 8(SP), DI
+ MOVL $3, AX // syscall entry
+ SYSCALL
+ RET
+
+TEXT fstat(SB),7,$0-16
+ MOVL 8(SP), DI
+ MOVQ 16(SP), SI
+ MOVL $5, AX // syscall entry
+ SYSCALL
+ RET
+
+TEXT read(SB),7,$0-24
+ MOVL 8(SP), DI
+ MOVQ 16(SP), SI
+ MOVL 24(SP), DX
+ MOVL $0, AX // syscall entry
+ SYSCALL
+ RET
+
+TEXT write(SB),7,$0-24
+ MOVL 8(SP), DI
+ MOVQ 16(SP), SI
+ MOVL 24(SP), DX
+ MOVL $1, AX // syscall entry
+ SYSCALL
+ RET
+
+TEXT sys·write(SB),7,$0-24
+ MOVL 8(SP), DI
+ MOVQ 16(SP), SI
+ MOVL 24(SP), DX
+ MOVL $1, AX // syscall entry
+ SYSCALL
+ RET
+
+TEXT rt_sigaction(SB),7,$0-32
+ MOVL 8(SP), DI
+ MOVQ 16(SP), SI
+ MOVQ 24(SP), DX
+ MOVQ 32(SP), R10
+ MOVL $13, AX // syscall entry
+ SYSCALL
+ RET
+
+TEXT sigtramp(SB),7,$24-16
+ MOVQ 32(R14), R15 // g = m->gsignal
+ 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 <asm/signal.h>
+#include <asm/siginfo.h>
+#include <asm/mman.h>
+
+enum {
+ $PROT_NONE = PROT_NONE,
+ $PROT_READ = PROT_READ,
+ $PROT_WRITE = PROT_WRITE,
+ $PROT_EXEC = PROT_EXEC,
+
+ $MAP_ANON = MAP_ANONYMOUS,
+ $MAP_PRIVATE = MAP_PRIVATE,
+
+ $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 <ucontext.h>
+
+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 <asm/signal.h>
+#include <asm/mman.h>
+#include <asm/sigframe.h>
+#include <asm/ucontext.h>
+
+/*
+#include <sys/signal.h>
+#include <sys/mman.h>
+#include <ucontext.h>
+*/
+
+enum {
+ $PROT_NONE = PROT_NONE,
+ $PROT_READ = PROT_READ,
+ $PROT_WRITE = PROT_WRITE,
+ $PROT_EXEC = PROT_EXEC,
+
+ $MAP_ANON = MAP_ANONYMOUS,
+ $MAP_PRIVATE = MAP_PRIVATE,
+
+ $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 <asm/signal.h>
+#include <asm/mman.h>
+#include <asm/sigcontext.h>
+#include <asm/ucontext.h>
+
+/*
+#include <sys/signal.h>
+#include <sys/mman.h>
+#include <ucontext.h>
+*/
+
+#include <time.h>
+
+enum {
+ $PROT_NONE = PROT_NONE,
+ $PROT_READ = PROT_READ,
+ $PROT_WRITE = PROT_WRITE,
+ $PROT_EXEC = PROT_EXEC,
+
+ $MAP_ANON = MAP_ANONYMOUS,
+ $MAP_PRIVATE = MAP_PRIVATE,
+
+ $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<<PageShift;
+ v = (void*)(s->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<<PageShift;
+ sys_memclr(v, s->npages<<PageShift);
+ MHeap_Free(&mheap, s);
+ goto out;
+ }
+ MHeapMapCache_SET(&mheap.mapcache, page, sizeclass);
+ }
+
+ // Small object.
+ c = m->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<<PageShift);
+ if(s->sizeclass == 0) {
+ // Large object.
+ if(base)
+ *base = p;
+ if(size)
+ *size = s->npages<<PageShift;
+ if(ref)
+ *ref = &s->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<<PageShift)) {
+ printf("odd span state=%d span=%p base=%p sizeclass=%d n=%D size=%D npages=%D\n",
+ s->state, s, p, s->sizeclass, (uint64)nobj, (uint64)n, (uint64)s->npages);
+ printf("s->base sizeclass %d v=%p base=%p gcref=%p blocksize=%D nobj=%D size=%D end=%p end=%p\n",
+ s->sizeclass, v, p, s->gcref, (uint64)s->npages<<PageShift,
+ (uint64)nobj, (uint64)n, s->gcref + nobj, p+(s->npages<<PageShift));
+ throw("bad gcref");
+ }
+ if(ref)
+ *ref = &s->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<n; i++) {
+ if(p[i] != 0) {
+ printf("mal %d => %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,
+ PageMask = PageSize - 1,
+};
+typedef uintptr PageID; // address >> 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; i<n; i++)
+ lp = &(*lp)->next;
+ l->list = *lp;
+ *lp = nil;
+ l->nlist -= n;
+ if(l->nlist < l->nlistmin)
+ l->nlistmin = l->nlist;
+ c->size -= n*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; i<NumSizeClasses; i++) {
+ l = &c->list[i];
+ n = l->nlistmin;
+
+ // n is the minimum number of elements we've seen on
+ // the list since the last scavenge. If n > 0, it means that
+ // we could have gotten by with n fewer elements
+ // without needing to consult the central free list.
+ // Move toward that situation by releasing n/2 of them.
+ if(n > 0) {
+ if(n > 1)
+ n /= 2;
+ ReleaseN(c, l, n, i);
+ }
+ l->nlistmin = l->nlist;
+ }
+ }
+}
+
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; i<n && (v = MCentral_Alloc(c)) != nil; i++) {
+ last->next = 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; i<n; i++) {
+ v = (MLink*)p;
+ *tailp = v;
+ tailp = &v->next;
+ 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; i<n; i++) {
+ if(mlookup(vp[i], &obj, &size, &ref)) {
+ if(*ref == RefFree || *ref == RefStack)
+ continue;
+ if(*ref == RefNone) {
+ if(Debug)
+ printf("%d found at %p: ", depth, &vp[i]);
+ *ref = RefSome;
+ scanblock(depth+1, obj, size);
+ }
+ }
+ }
+}
+
+static void
+scanstack(G *g)
+{
+ Stktop *stk;
+ byte *sp;
+
+ sp = g->sched.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<<PageShift, p);
+ free(p);
+ break;
+ case RefSome:
+ s->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; i<n; i++) {
+ switch(s->gcref[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; i<nelem(h->free); i++)
+ MSpanList_Init(&h->free[i]);
+ MSpanList_Init(&h->large);
+ for(i=0; i<nelem(h->central); 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; n<npage; n++)
+ MHeapMap_Set(&h->map, 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; n<npage; n++)
+ if(MHeapMapCache_GET(&h->mapcache, 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; n<npage; n++)
+ MHeapMapCache_SET(&h->mapcache, 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<<PageShift;
+ if(ask < HeapAllocChunk)
+ ask = HeapAllocChunk;
+
+ v = SysAlloc(ask);
+ if(v == nil) {
+ if(ask > (npage<<PageShift)) {
+ ask = npage<<PageShift;
+ v = SysAlloc(ask);
+ }
+ if(v == nil)
+ return false;
+ }
+
+ // NOTE(rsc): In tcmalloc, if we've accumulated enough
+ // system allocations, the heap map gets entirely allocated
+ // in 32-bit mode. (In 64-bit mode that's not practical.)
+
+ if(!MHeapMap_Preallocate(&h->map, ((uintptr)v>>PageShift) - 1, (ask>>PageShift) + 2)) {
+ SysFree(v, ask);
+ 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<<PageShift, s->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<<MHeapMap_Level1Bits) - 1,
+ MHeapMap_Level2Mask = (1<<MHeapMap_Level2Bits) - 1,
+};
+
+struct MHeapMap
+{
+ void *(*allocator)(uintptr);
+ MHeapMapNode2 *p[1<<MHeapMap_Level1Bits];
+};
+
+struct MHeapMapNode2
+{
+ MSpan *s[1<<MHeapMap_Level2Bits];
+};
+
+void MHeapMap_Init(MHeapMap *m, void *(*allocator)(uintptr));
+bool MHeapMap_Preallocate(MHeapMap *m, PageID k, uintptr npages);
+MSpan* MHeapMap_Get(MHeapMap *m, PageID k);
+MSpan* MHeapMap_GetMaybe(MHeapMap *m, PageID k);
+void MHeapMap_Set(MHeapMap *m, PageID k, MSpan *v);
+
+
+// Much of the time, free(v) needs to know only the size class for v,
+// not which span it came from. The MHeapMap finds the size class
+// by looking up the span.
+//
+// An MHeapMapCache is a simple direct-mapped cache translating
+// page numbers to size classes. It avoids the expensive MHeapMap
+// lookup for hot pages.
+//
+// The cache entries are 32 bits, with the page number in the low part
+// and the value at the top.
+//
+// NOTE(rsc): On a machine with 32-bit addresses (= 20-bit page numbers),
+// we can use a 16-bit cache entry by not storing the redundant 12 bits
+// of the key that are used as the entry index. For now, keep it simple.
+enum
+{
+ MHeapMapCache_HashBits = 12
+};
+
+struct MHeapMapCache
+{
+ uint32 array[1<<MHeapMapCache_HashBits];
+};
+
+// All macros for speed (sorry).
+#define HMASK ((1<<MHeapMapCache_HashBits)-1)
+#define KBITS MHeapMap_TotalBits
+#define KMASK ((1LL<<KBITS)-1)
+
+#define MHeapMapCache_SET(cache, key, value) \
+ ((cache)->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<<MHeapMap_Level1Bits) - 1,
+ MHeapMap_Level2Mask = (1<<MHeapMap_Level2Bits) - 1,
+ MHeapMap_Level3Mask = (1<<MHeapMap_Level3Bits) - 1,
+};
+
+struct MHeapMap
+{
+ void *(*allocator)(uintptr);
+ MHeapMapNode2 *p[1<<MHeapMap_Level1Bits];
+};
+
+struct MHeapMapNode2
+{
+ MHeapMapNode3 *p[1<<MHeapMap_Level2Bits];
+};
+
+struct MHeapMapNode3
+{
+ MSpan *s[1<<MHeapMap_Level3Bits];
+};
+
+void MHeapMap_Init(MHeapMap *m, void *(*allocator)(uintptr));
+bool MHeapMap_Preallocate(MHeapMap *m, PageID k, uintptr npages);
+MSpan* MHeapMap_Get(MHeapMap *m, PageID k);
+MSpan* MHeapMap_GetMaybe(MHeapMap *m, PageID k);
+void MHeapMap_Set(MHeapMap *m, PageID k, MSpan *v);
+
+
+// Much of the time, free(v) needs to know only the size class for v,
+// not which span it came from. The MHeapMap finds the size class
+// by looking up the span.
+//
+// An MHeapMapCache is a simple direct-mapped cache translating
+// page numbers to size classes. It avoids the expensive MHeapMap
+// lookup for hot pages.
+//
+// The cache entries are 64 bits, with the page number in the low part
+// and the value at the top.
+//
+// NOTE(rsc): On a machine with 32-bit addresses (= 20-bit page numbers),
+// we can use a 16-bit cache entry by not storing the redundant 12 bits
+// of the key that are used as the entry index. Here in 64-bit land,
+// that trick won't work unless the hash table has 2^28 entries.
+enum
+{
+ MHeapMapCache_HashBits = 12
+};
+
+struct MHeapMapCache
+{
+ uintptr array[1<<MHeapMapCache_HashBits];
+};
+
+// All macros for speed (sorry).
+#define HMASK ((1<<MHeapMapCache_HashBits)-1)
+#define KBITS MHeapMap_TotalBits
+#define KMASK ((1LL<<KBITS)-1)
+
+#define MHeapMapCache_SET(cache, key, value) \
+ ((cache)->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<NumSizeClasses; sizeclass++)
+ printf(" %d", class_to_size[sizeclass]);
+ printf("\n\n");
+ printf("size_to_class8:");
+ for(i=0; i<nelem(size_to_class8); i++)
+ printf(" %d=>%d(%d)\n", i*8, size_to_class8[i], class_to_size[size_to_class8[i]]);
+ printf("\n");
+ printf("size_to_class128:");
+ for(i=0; i<nelem(size_to_class128); i++)
+ printf(" %d=>%d(%d)\n", i*128, size_to_class128[i], class_to_size[size_to_class128[i]]);
+ printf("\n");
+ }
+ 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<n; i++) {
+ sys·printpointer((byte*)(p[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<n; i++)
+ h /= 10;
+ v += h;
+ if(v >= 10) {
+ e++;
+ v /= 10;
+ }
+ }
+
+ // format +d.dddd+edd
+ buf[0] = '+';
+ if(s)
+ buf[0] = '-';
+ for(i=0; i<n; i++) {
+ s = v;
+ buf[i+2] = s+'0';
+ v -= s;
+ v *= 10.;
+ }
+ buf[1] = buf[2];
+ buf[2] = '.';
+
+ buf[n+2] = 'e';
+ buf[n+3] = '+';
+ if(e < 0) {
+ e = -e;
+ buf[n+3] = '-';
+ }
+
+ buf[n+4] = (e/100) + '0';
+ buf[n+5] = (e/10)%10 + '0';
+ buf[n+6] = (e%10) + '0';
+ sys·write(1, buf, n+7);
+}
+
+void
+sys·printuint(uint64 v)
+{
+ byte buf[100];
+ int32 i;
+
+ for(i=nelem(buf)-1; i>0; i--) {
+ buf[i] = v%10 + '0';
+ if(v < 10)
+ break;
+ v = v/10;
+ }
+ 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<<Bitx)-1, /* 0011 1111 */
+ Testx = Maskx ^ 0xFF, /* 1100 0000 */
+
+ Runeerror = 0xFFFD,
+ Runeself = 0x80,
+
+ Bad = Runeerror,
+
+ Runemax = 0x10FFFF, /* maximum rune value */
+};
+
+/*
+ * Modified by Wei-Hwa Huang, Google Inc., on 2004-09-24
+ * This is a slower but "safe" version of the old chartorune
+ * that works on strings that are not necessarily null-terminated.
+ *
+ * If you know for sure that your string is null-terminated,
+ * chartorune will be a bit faster.
+ *
+ * It is guaranteed not to attempt to access "length"
+ * past the incoming pointer. This is to avoid
+ * possible access violations. If the string appears to be
+ * well-formed but incomplete (i.e., to get the whole Rune
+ * we'd need to read past str+length) then we'll set the Rune
+ * to Bad and return 0.
+ *
+ * Note that if we have decoding problems for other
+ * reasons, we return 1 instead of 0.
+ */
+int32
+charntorune(int32 *rune, uint8 *str, int32 length)
+{
+ int32 c, c1, c2, c3, l;
+
+ /* When we're not allowed to read anything */
+ if(length <= 0) {
+ goto badlen;
+ }
+
+ /*
+ * one character sequence (7-bit value)
+ * 00000-0007F => T1
+ */
+ c = *(uint8*)str;
+ if(c < Tx) {
+ *rune = c;
+ return 1;
+ }
+
+ // If we can't read more than one character we must stop
+ if(length <= 1) {
+ goto badlen;
+ }
+
+ /*
+ * two character sequence (11-bit value)
+ * 0080-07FF => T2 Tx
+ */
+ c1 = *(uint8*)(str+1) ^ Tx;
+ if(c1 & Testx)
+ goto bad;
+ if(c < T3) {
+ if(c < T2)
+ goto bad;
+ l = ((c << Bitx) | c1) & Rune2;
+ if(l <= Rune1)
+ goto bad;
+ *rune = l;
+ return 2;
+ }
+
+ // If we can't read more than two characters we must stop
+ if(length <= 2) {
+ goto badlen;
+ }
+
+ /*
+ * three character sequence (16-bit value)
+ * 0800-FFFF => T3 Tx Tx
+ */
+ c2 = *(uint8*)(str+2) ^ Tx;
+ if(c2 & Testx)
+ goto bad;
+ if(c < T4) {
+ l = ((((c << Bitx) | c1) << Bitx) | c2) & Rune3;
+ if(l <= Rune2)
+ goto bad;
+ *rune = l;
+ return 3;
+ }
+
+ if (length <= 3)
+ goto badlen;
+
+ /*
+ * four character sequence (21-bit value)
+ * 10000-1FFFFF => T4 Tx Tx Tx
+ */
+ c3 = *(uint8*)(str+3) ^ Tx;
+ if (c3 & Testx)
+ goto bad;
+ if (c < T5) {
+ l = ((((((c << Bitx) | c1) << Bitx) | c2) << Bitx) | c3) & Rune4;
+ if (l <= Rune3 || l > Runemax)
+ goto bad;
+ *rune = l;
+ return 4;
+ }
+
+ // Support for 5-byte or longer UTF-8 would go here, but
+ // since we don't have that, we'll just fall through to bad.
+
+ /*
+ * bad decoding
+ */
+bad:
+ *rune = Bad;
+ return 1;
+badlen:
+ *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<n; i++) {
+ c1 = s1[i];
+ c2 = s2[i];
+ if(c1 < c2)
+ return -1;
+ if(c1 > 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<argc; i++)
+ gargv[i] = gostring(argv[i]);
+ os·Args.array = (byte*)gargv;
+ os·Args.nel = argc;
+ os·Args.cap = argc;
+
+ for(i=0; i<envc; i++)
+ genvv[i] = gostring(argv[argc+1+i]);
+ os·Envs.array = (byte*)genvv;
+ os·Envs.nel = envc;
+ os·Envs.cap = envc;
+}
+
+byte*
+getenv(int8 *s)
+{
+ int32 i, j, len;
+ byte *v, *bs;
+ String* envv;
+ int32 envc;
+
+ bs = (byte*)s;
+ len = findnull(bs);
+ envv = (String*)os·Envs.array;
+ envc = os·Envs.nel;
+ for(i=0; i<envc; i++){
+ if(envv[i].len <= len)
+ continue;
+ v = envv[i].str;
+ for(j=0; j<len; j++)
+ if(bs[j] != v[j])
+ goto nomatch;
+ if(v[len] != '=')
+ goto nomatch;
+ return v+len+1;
+ nomatch:;
+ }
+ return nil;
+}
+
+
+int32
+atoi(byte *p)
+{
+ int32 n;
+
+ n = 0;
+ while('0' <= *p && *p <= '9')
+ n = n*10 + *p++ - '0';
+ return n;
+}
+
+void
+check(void)
+{
+ int8 a;
+ uint8 b;
+ int16 c;
+ uint16 d;
+ int32 e;
+ uint32 f;
+ int64 g;
+ uint64 h;
+ float32 i;
+ float64 j;
+ void* k;
+ uint16* l;
+
+ if(sizeof(a) != 1) throw("bad a");
+ if(sizeof(b) != 1) throw("bad b");
+ if(sizeof(c) != 2) throw("bad c");
+ if(sizeof(d) != 2) throw("bad d");
+ if(sizeof(e) != 4) throw("bad e");
+ if(sizeof(f) != 4) throw("bad f");
+ if(sizeof(g) != 8) throw("bad g");
+ if(sizeof(h) != 8) throw("bad h");
+ if(sizeof(i) != 4) throw("bad i");
+ if(sizeof(j) != 8) throw("bad j");
+ if(sizeof(k) != sizeof(uintptr)) throw("bad k");
+ if(sizeof(l) != sizeof(uintptr)) throw("bad l");
+// prints(1"check ok\n");
+
+ uint32 z;
+ z = 1;
+ if(!cas(&z, 1, 2))
+ throw("cas1");
+ if(z != 2)
+ throw("cas2");
+
+ z = 4;
+ if(cas(&z, 5, 6))
+ throw("cas3");
+ if(z != 4)
+ throw("cas4");
+
+ initsig();
+}
+
+/*
+ * map and chan helpers for
+ * dealing with unknown types
+ */
+static uintptr
+memhash(uint32 s, void *a)
+{
+ byte *b;
+ uintptr hash;
+
+ b = a;
+ if(sizeof(hash) == 4)
+ hash = 2860486313U;
+ else
+ hash = 33054211828000289ULL;
+ while(s > 0) {
+ if(sizeof(hash) == 4)
+ hash = (hash ^ *b) * 3267000013UL;
+ else
+ hash = (hash ^ *b) * 23344194077549503ULL;
+ b++;
+ s--;
+ }
+ return hash;
+}
+
+static uint32
+memequal(uint32 s, void *a, void *b)
+{
+ byte *ba, *bb;
+ uint32 i;
+
+ ba = a;
+ bb = b;
+ for(i=0; i<s; i++)
+ if(ba[i] != bb[i])
+ return 0;
+ return 1;
+}
+
+static void
+memprint(uint32 s, void *a)
+{
+ uint64 v;
+
+ v = 0xbadb00b;
+ switch(s) {
+ case 1:
+ v = *(uint8*)a;
+ break;
+ case 2:
+ v = *(uint16*)a;
+ break;
+ case 4:
+ v = *(uint32*)a;
+ break;
+ case 8:
+ v = *(uint64*)a;
+ break;
+ }
+ sys·printint(v);
+}
+
+static void
+memcopy(uint32 s, void *a, void *b)
+{
+ byte *ba, *bb;
+ uint32 i;
+
+ ba = a;
+ bb = b;
+ if(bb == nil) {
+ for(i=0; i<s; i++)
+ ba[i] = 0;
+ return;
+ }
+ for(i=0; i<s; i++)
+ ba[i] = bb[i];
+}
+
+static uintptr
+strhash(uint32 s, String *a)
+{
+ USED(s);
+ return memhash((*a).len, (*a).str);
+}
+
+static uint32
+strequal(uint32 s, String *a, String *b)
+{
+ USED(s);
+ return cmpstring(*a, *b) == 0;
+}
+
+static void
+strprint(uint32 s, String *a)
+{
+ USED(s);
+ sys·printstring(*a);
+}
+
+static uintptr
+interhash(uint32 s, Iface *a)
+{
+ USED(s);
+ return ifacehash(*a);
+}
+
+static void
+interprint(uint32 s, Iface *a)
+{
+ USED(s);
+ sys·printiface(*a);
+}
+
+static uint32
+interequal(uint32 s, Iface *a, Iface *b)
+{
+ USED(s);
+ return ifaceeq(*a, *b);
+}
+
+static uintptr
+nilinterhash(uint32 s, Eface *a)
+{
+ USED(s);
+ return efacehash(*a);
+}
+
+static void
+nilinterprint(uint32 s, Eface *a)
+{
+ USED(s);
+ sys·printeface(*a);
+}
+
+static uint32
+nilinterequal(uint32 s, Eface *a, Eface *b)
+{
+ USED(s);
+ return efaceeq(*a, *b);
+}
+
+uintptr
+nohash(uint32 s, void *a)
+{
+ USED(s);
+ USED(a);
+ throw("hash of unhashable type");
+ return 0;
+}
+
+uint32
+noequal(uint32 s, void *a, void *b)
+{
+ USED(s);
+ USED(a);
+ USED(b);
+ throw("comparing uncomparable types");
+ return 0;
+}
+
+static void
+noprint(uint32 s, void *a)
+{
+ USED(s);
+ USED(a);
+ throw("print of unprintable type");
+}
+
+static void
+nocopy(uint32 s, void *a, void *b)
+{
+ USED(s);
+ USED(a);
+ USED(b);
+ throw("copy of uncopyable type");
+}
+
+Alg
+algarray[] =
+{
+[AMEM] { memhash, memequal, memprint, memcopy },
+[ANOEQ] { nohash, noequal, memprint, memcopy },
+[ASTRING] { strhash, strequal, strprint, memcopy },
+[AINTER] { interhash, interequal, interprint, memcopy },
+[ANILINTER] { nilinterhash, nilinterequal, nilinterprint, memcopy },
+[AFAKE] { nohash, noequal, noprint, nocopy },
+};
+
+#pragma textflag 7
+void
+FLUSH(void *v)
+{
+ USED(v);
+}
+
diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h
new file mode 100644
index 000000000..749364f95
--- /dev/null
+++ b/src/pkg/runtime/runtime.h
@@ -0,0 +1,464 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ * basic types
+ */
+typedef signed char int8;
+typedef unsigned char uint8;
+typedef signed short int16;
+typedef unsigned short uint16;
+typedef signed int int32;
+typedef unsigned int uint32;
+typedef signed long long int int64;
+typedef unsigned long long int uint64;
+typedef float float32;
+typedef double float64;
+
+#ifdef _64BIT
+typedef uint64 uintptr;
+#else
+typedef uint32 uintptr;
+#endif
+
+/*
+ * get rid of C types
+ * the / / / forces a syntax error immediately,
+ * which will show "last name: XXunsigned".
+ */
+#define unsigned XXunsigned / / /
+#define signed XXsigned / / /
+#define char XXchar / / /
+#define short XXshort / / /
+#define int XXint / / /
+#define long XXlong / / /
+#define float XXfloat / / /
+#define double XXdouble / / /
+
+/*
+ * defined types
+ */
+typedef uint8 bool;
+typedef uint8 byte;
+typedef struct Alg Alg;
+typedef struct Array Array;
+typedef struct Func Func;
+typedef struct G G;
+typedef struct Gobuf Gobuf;
+typedef struct Lock Lock;
+typedef struct M M;
+typedef struct Mem Mem;
+typedef union Note Note;
+typedef struct Stktop Stktop;
+typedef struct String String;
+typedef struct Usema Usema;
+typedef struct SigTab SigTab;
+typedef struct MCache MCache;
+typedef struct Iface Iface;
+typedef struct Itype Itype;
+typedef struct Eface Eface;
+typedef struct Sigt Sigt;
+typedef struct Defer Defer;
+
+/*
+ * per cpu declaration
+ */
+extern register G* g; // R15
+extern register M* m; // R14
+
+/*
+ * defined constants
+ */
+enum
+{
+ // G status
+ Gidle,
+ Grunnable,
+ Grunning,
+ Gsyscall,
+ Gwaiting,
+ Gmoribund,
+ Gdead,
+};
+enum
+{
+ true = 1,
+ false = 0,
+};
+
+/*
+ * structures
+ */
+struct Lock
+{
+ uint32 key;
+ uint32 sema; // for OS X
+};
+struct Usema
+{
+ uint32 u;
+ uint32 k;
+};
+union Note
+{
+ struct { // Linux
+ Lock lock;
+ };
+ struct { // OS X
+ int32 wakeup;
+ Usema sema;
+ };
+};
+struct String
+{
+ byte* str;
+ int32 len;
+};
+struct Iface
+{
+ Itype* type;
+ void* data;
+};
+struct Eface
+{
+ Sigt* type;
+ void* data;
+};
+
+struct Array
+{ // must not move anything
+ byte* array; // actual data
+ uint32 nel; // number of elements
+ uint32 cap; // allocated number of elements
+};
+struct Gobuf
+{
+ byte* SP;
+ byte* PC;
+};
+struct G
+{
+ byte* stackguard; // must not move
+ byte* stackbase; // must not move
+ Defer* defer; // must not move
+ byte* stack0; // first stack segment
+ Gobuf sched;
+ G* alllink; // on allg
+ void* param; // passed parameter on wakeup
+ int16 status;
+ int32 goid;
+ int32 selgen; // valid sudog pointer
+ G* schedlink;
+ bool readyonstop;
+ M* m; // for debuggers
+};
+struct Mem
+{
+ uint8* hunk;
+ uint32 nhunk;
+ uint64 nmmap;
+ uint64 nmal;
+};
+struct M
+{
+ G* g0; // g0 w interrupt stack - must not move
+ uint64 morearg; // arg to morestack - must not move
+ uint64 cret; // return value from C - must not move
+ uint64 procid; // for debuggers - must not move
+ G* gsignal; // signal-handling G - must not move
+ G* curg; // current running goroutine - must not move
+ G* lastg; // last running goroutine - to emulate fifo - must not move
+ uint32 tls[8]; // thread-local storage (for 386 extern register) - must not move
+ Gobuf sched;
+ Gobuf morestack;
+ byte* moresp;
+ int32 siz1;
+ int32 siz2;
+ int32 id;
+ int32 mallocing;
+ int32 locks;
+ Note havenextg;
+ G* nextg;
+ M* schedlink;
+ Mem mem;
+ uint32 machport; // Return address for Mach IPC (OS X)
+ MCache *mcache;
+};
+struct Stktop
+{
+ uint8* oldbase;
+ uint8* oldsp;
+ uint64 magic;
+ uint8* oldguard;
+};
+struct Alg
+{
+ uintptr (*hash)(uint32, void*);
+ uint32 (*equal)(uint32, void*, void*);
+ void (*print)(uint32, void*);
+ void (*copy)(uint32, void*, void*);
+};
+struct SigTab
+{
+ int32 flags;
+ int8 *name;
+};
+enum
+{
+ SigCatch = 1<<0,
+ SigIgnore = 1<<1,
+ SigRestart = 1<<2,
+};
+
+// (will be) shared with go; edit ../cmd/6g/sys.go too.
+// should move out of sys.go eventually.
+// also eventually, the loaded symbol table should
+// be closer to this form.
+struct Func
+{
+ String name;
+ String type; // go type string
+ String src; // src file name
+ uint64 entry; // entry pc
+ int64 frame; // stack frame size
+ Array pcln; // pc/ln tab for this func
+ int64 pc0; // starting pc, ln for table
+ int32 ln0;
+ int32 args; // number of 32-bit in/out args
+ int32 locals; // number of 32-bit locals
+};
+
+/*
+ * defined macros
+ * you need super-goru privilege
+ * to add this list.
+ */
+#define nelem(x) (sizeof(x)/sizeof((x)[0]))
+#define nil ((void*)0)
+
+/*
+ * known to compiler
+ */
+enum
+{
+ AMEM,
+ ANOEQ,
+ ASTRING,
+ AINTER,
+ ANILINTER,
+ AFAKE,
+ Amax
+};
+
+/*
+ * deferred subroutine calls
+ */
+struct Defer
+{
+ int32 siz;
+ byte* sp;
+ byte* fn;
+ Defer* link;
+ byte args[8]; // padded to actual size
+};
+
+/*
+ * external data
+ */
+extern Alg algarray[Amax];
+extern String emptystring;
+G* allg;
+int32 goidgen;
+extern int32 gomaxprocs;
+extern int32 panicking;
+extern int32 maxround;
+
+/*
+ * common functions and data
+ */
+int32 strcmp(byte*, byte*);
+int32 findnull(byte*);
+void dump(byte*, int32);
+int32 runetochar(byte*, int32);
+int32 charntorune(int32*, uint8*, int32);
+
+/*
+ * very low level c-called
+ */
+int32 gogo(Gobuf*);
+int32 gosave(Gobuf*);
+int32 gogoret(Gobuf*, uint64);
+void retfromnewstack(void);
+void goargs(void);
+void setspgoto(byte*, void(*)(void), void(*)(void));
+void FLUSH(void*);
+void* getu(void);
+void throw(int8*);
+uint32 rnd(uint32, uint32);
+void prints(int8*);
+void printf(int8*, ...);
+byte* mchr(byte*, byte, byte*);
+void mcpy(byte*, byte*, uint32);
+int32 mcmp(byte*, byte*, uint32);
+void mmov(byte*, byte*, uint32);
+void* mal(uint32);
+uint32 cmpstring(String, String);
+String gostring(byte*);
+void initsig(void);
+int32 gotraceback(void);
+void traceback(uint8 *pc, uint8 *sp, G* gp);
+void tracebackothers(G*);
+int32 open(byte*, int32, ...);
+int32 read(int32, void*, int32);
+int32 write(int32, void*, int32);
+void close(int32);
+int32 fstat(int32, void*);
+bool cas(uint32*, uint32, uint32);
+void jmpdefer(byte*, void*);
+void exit1(int32);
+void ready(G*);
+byte* getenv(int8*);
+int32 atoi(byte*);
+void newosproc(M *m, G *g, void *stk, void (*fn)(void));
+void sigaltstack(void*, void*);
+void signalstack(byte*, int32);
+G* malg(int32);
+void minit(void);
+Func* findfunc(uintptr);
+int32 funcline(Func*, uint64);
+void* stackalloc(uint32);
+void stackfree(void*);
+MCache* allocmcache(void);
+void mallocinit(void);
+bool ifaceeq(Iface, Iface);
+bool efaceeq(Eface, Eface);
+uintptr ifacehash(Iface);
+uintptr efacehash(Eface);
+uintptr nohash(uint32, void*);
+uint32 noequal(uint32, void*, void*);
+void* malloc(uintptr size);
+void* mallocgc(uintptr size);
+void free(void *v);
+void exit(int32);
+void breakpoint(void);
+void gosched(void);
+void goexit(void);
+
+#pragma varargck argpos printf 1
+
+#pragma varargck type "d" int32
+#pragma varargck type "d" uint32
+#pragma varargck type "D" int64
+#pragma varargck type "D" uint64
+#pragma varargck type "x" int32
+#pragma varargck type "x" uint32
+#pragma varargck type "X" int64
+#pragma varargck type "X" uint64
+#pragma varargck type "p" void*
+#pragma varargck type "p" uintptr
+#pragma varargck type "s" int8*
+#pragma varargck type "s" uint8*
+#pragma varargck type "S" String
+
+// TODO(rsc): Remove. These are only temporary,
+// for the mark and sweep collector.
+void stoptheworld(void);
+void starttheworld(void);
+
+/*
+ * mutual exclusion locks. in the uncontended case,
+ * as fast as spin locks (just a few user-level instructions),
+ * but on the contention path they sleep in the kernel.
+ * a zeroed Lock is unlocked (no need to initialize each lock).
+ */
+void lock(Lock*);
+void unlock(Lock*);
+
+/*
+ * sleep and wakeup on one-time events.
+ * before any calls to notesleep or notewakeup,
+ * must call noteclear to initialize the Note.
+ * then, any number of threads can call notesleep
+ * and exactly one thread can call notewakeup (once).
+ * once notewakeup has been called, all the notesleeps
+ * will return. future notesleeps will return immediately.
+ */
+void noteclear(Note*);
+void notesleep(Note*);
+void notewakeup(Note*);
+
+/*
+ * Redefine methods for the benefit of gcc, which does not support
+ * UTF-8 characters in identifiers.
+ */
+#ifndef __GNUC__
+#define sys_memclr sys·memclr
+#define sys_write sys·write
+#define sys_catstring sys·catstring
+#define sys_cmpstring sys·cmpstring
+#define sys_getcallerpc sys·getcallerpc
+#define sys_indexstring sys·indexstring
+#define sys_intstring sys·intstring
+#define sys_mal sys·mal
+#define sys_mmap sys·mmap
+#define sys_printarray sys·printarray
+#define sys_printbool sys·printbool
+#define sys_printfloat sys·printfloat
+#define sys_printhex sys·printhex
+#define sys_printint sys·printint
+#define sys_printiface sys·printiface
+#define sys_printeface sys·printeface
+#define sys_printpc sys·printpc
+#define sys_printpointer sys·printpointer
+#define sys_printstring sys·printstring
+#define sys_printuint sys·printuint
+#define sys_setcallerpc sys·setcallerpc
+#define sys_slicestring sys·slicestring
+#endif
+
+/*
+ * low level go-called
+ */
+void sys_write(int32, void*, int32);
+uint8* sys_mmap(byte*, uint32, int32, int32, int32, uint32);
+void sys_memclr(byte*, uint32);
+void sys_setcallerpc(void*, void*);
+void* sys_getcallerpc(void*);
+
+/*
+ * runtime go-called
+ */
+void sys_printbool(bool);
+void sys_printfloat(float64);
+void sys_printint(int64);
+void sys_printiface(Iface);
+void sys_printeface(Eface);
+void sys_printstring(String);
+void sys_printpc(void*);
+void sys_printpointer(void*);
+void sys_printuint(uint64);
+void sys_printhex(uint64);
+void sys_printarray(Array);
+void sys_catstring(String, String, String);
+void sys_cmpstring(String, String, int32);
+void sys_slicestring(String, int32, int32, String);
+void sys_indexstring(String, int32, byte);
+void sys_intstring(int64, String);
+
+/*
+ * wrapped for go users
+ */
+float64 Inf(int32 sign);
+float64 NaN(void);
+float32 float32frombits(uint32 i);
+uint32 float32tobits(float32 f);
+float64 float64frombits(uint64 i);
+uint64 float64tobits(float64 f);
+float64 frexp(float64 d, int32 *ep);
+bool isInf(float64 f, int32 sign);
+bool isNaN(float64 f);
+float64 ldexp(float64 d, int32 e);
+float64 modf(float64 d, float64 *ip);
+void semacquire(uint32*);
+void semrelease(uint32*);
diff --git a/src/pkg/runtime/sema.c b/src/pkg/runtime/sema.c
new file mode 100644
index 000000000..5e5b07aa6
--- /dev/null
+++ b/src/pkg/runtime/sema.c
@@ -0,0 +1,176 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Semaphore implementation exposed to Go.
+// Intended use is provide a sleep and wakeup
+// primitive that can be used in the contended case
+// of other synchronization primitives.
+// Thus it targets the same goal as Linux's futex,
+// but it has much simpler semantics.
+//
+// That is, don't think of these as semaphores.
+// Think of them as a way to implement sleep and wakeup
+// such that every sleep is paired with a single wakeup,
+// even if, due to races, the wakeup happens before the sleep.
+//
+// See Mullender and Cox, ``Semaphores in Plan 9,''
+// http://swtch.com/semaphore.pdf
+
+#include "runtime.h"
+
+typedef struct Sema Sema;
+struct Sema
+{
+ uint32 *addr;
+ G *g;
+ Sema *prev;
+ Sema *next;
+};
+
+// TODO: For now, a linked list; maybe a hash table of linked lists later.
+static Sema *semfirst, *semlast;
+static Lock semlock;
+
+static void
+semqueue(uint32 *addr, Sema *s)
+{
+ s->addr = 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<l; i++) {
+ c1 = s1.str[i];
+ c2 = s2.str[i];
+ if(c1 < c2)
+ return -1;
+ if(c1 > c2)
+ return +1;
+ }
+ if(s1.len < s2.len)
+ return -1;
+ if(s1.len > s2.len)
+ return +1;
+ return 0;
+}
+
+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<b.nel; i++) {
+ siz1 += runetochar(dum, a[i]);
+ }
+
+ s = gostringsize(siz1+4);
+ siz2 = 0;
+ for(i=0; i<b.nel; i++) {
+ // check for race
+ if(siz2 >= 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<<uint(i) < n {
+ i++;
+ }
+ return i;
+}
+
+func TestBentleyMcIlroy(t *testing.T) {
+ sizes := []int{100, 1023, 1024, 1025};
+ dists := []string{"sawtooth", "rand", "stagger", "plateau", "shuffle"};
+ modes := []string{"copy", "reverse", "reverse1", "reverse2", "sort", "dither"};
+ var tmp1, tmp2 [1025]int;
+ for ni := 0; ni < len(sizes); ni++ {
+ n := sizes[ni];
+ for m := 1; m < 2*n; m *= 2 {
+ for dist := 0; dist < _NDist; dist++ {
+ j := 0;
+ k := 1;
+ data := tmp1[0:n];
+ for i := 0; i < n; i++ {
+ switch dist {
+ case _Sawtooth:
+ data[i] = i % m;
+ case _Rand:
+ data[i] = rand.Intn(m);
+ case _Stagger:
+ data[i] = (i*m + i) % n;
+ case _Plateau:
+ data[i] = min(i, m);
+ case _Shuffle:
+ if rand.Intn(m) != 0 {
+ j += 2;
+ data[i] = j;
+ } else {
+ k += 2;
+ data[i] = k;
+ }
+ }
+ }
+
+ mdata := tmp2[0:n];
+ for mode := 0; mode < _NMode; mode++ {
+ switch mode {
+ case _Copy:
+ for i := 0; i < n; i++ {
+ mdata[i] = data[i];
+ }
+ case _Reverse:
+ for i := 0; i < n; i++ {
+ mdata[i] = data[n-i-1];
+ }
+ case _ReverseFirstHalf:
+ for i := 0; i < n/2; i++ {
+ mdata[i] = data[n/2-i-1];
+ }
+ for i := n/2; i < n; i++ {
+ mdata[i] = data[i];
+ }
+ case _ReverseSecondHalf:
+ for i := 0; i < n/2; i++ {
+ mdata[i] = data[i];
+ }
+ for i := n/2; i < n; i++ {
+ mdata[i] = data[n-(i-n/2)-1];
+ }
+ case _Sorted:
+ for i := 0; i < n; i++ {
+ mdata[i] = data[i];
+ }
+ // sort.SortInts is known to be correct
+ // because mode Sort runs after mode _Copy.
+ sort.SortInts(mdata);
+ case _Dither:
+ for i := 0; i < n; i++ {
+ mdata[i] = data[i] + i%5;
+ }
+ }
+
+ desc := fmt.Sprintf("n=%d m=%d dist=%s mode=%s", n, m, dists[dist], modes[mode]);
+ d := &testingData{desc, t, mdata[0:n], n*lg(n)*12/10, 0};
+ sort.Sort(d);
+
+ // If we were testing C qsort, we'd have to make a copy
+ // of the array and sort it ourselves and then compare
+ // x against it, to ensure that qsort was only permuting
+ // the data, not (for example) overwriting it with zeros.
+ //
+ // In go, we don't have to be so paranoid: since the only
+ // mutating method sort.Sort can call is TestingData.swap,
+ // it suffices here just to check that the final array is sorted.
+ if !sort.IntsAreSorted(mdata) {
+ t.Errorf("%s: ints not sorted", desc);
+ t.Errorf("\t%v", mdata);
+ t.FailNow();
+ }
+ }
+ }
+ }
+ }
+}
+
diff --git a/src/pkg/strconv/Makefile b/src/pkg/strconv/Makefile
new file mode 100644
index 000000000..499f8c1c1
--- /dev/null
+++ b/src/pkg/strconv/Makefile
@@ -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.
+
+# 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=\
+ 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<<flt.expbits - 1 {
+ goto overflow;
+ }
+
+ // Extract 1+flt.mantbits bits.
+ mant = d.Shift(int(1+flt.mantbits)).RoundedInteger();
+
+ // Rounding might have added a bit; shift down.
+ if mant == 2<<flt.mantbits {
+ mant >>= 1;
+ exp++;
+ if exp-flt.bias >= 1<<flt.expbits - 1 {
+ goto overflow;
+ }
+ }
+
+ // Denormalized?
+ if mant&(1<<flt.mantbits) == 0 {
+ exp = flt.bias;
+ }
+ goto out;
+
+overflow:
+ // ±Inf
+ mant = 0;
+ exp = 1<<flt.expbits - 1 + flt.bias;
+ overflow = true;
+
+out:
+ // Assemble bits.
+ bits := mant & (uint64(1)<<flt.mantbits - 1);
+ bits |= uint64((exp-flt.bias)&(1<<flt.expbits - 1)) << flt.mantbits;
+ if neg {
+ bits |= 1<<flt.mantbits<<flt.expbits;
+ }
+ return bits, overflow;
+}
+
+// Compute exact floating-point integer from d's digits.
+// Caller is responsible for avoiding overflow.
+func decimalAtof64Int(neg bool, d *decimal) float64 {
+ f := float64(0);
+ for i := 0; i < d.nd; i++ {
+ f = f*10 + float64(d.d[i] - '0');
+ }
+ if neg {
+ f *= -1; // BUG work around 6g f = -f.
+ }
+ return f;
+}
+
+func decimalAtof32Int(neg bool, d *decimal) float32 {
+ f := float32(0);
+ for i := 0; i < d.nd; i++ {
+ f = f*10 + float32(d.d[i] - '0');
+ }
+ if neg {
+ f *= -1; // BUG work around 6g f = -f.
+ }
+ return f;
+}
+
+// Exact powers of 10.
+var float64pow10 = []float64 {
+ 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
+ 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
+ 1e20, 1e21, 1e22
+}
+var float32pow10 = []float32 {
+ 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10
+}
+
+// If possible to convert decimal d to 64-bit float f exactly,
+// entirely in floating-point math, do so, avoiding the expense of decimalToFloatBits.
+// Three common cases:
+// value is exact integer
+// value is exact integer * exact power of ten
+// value is exact integer / exact power of ten
+// These all produce potentially inexact but correctly rounded answers.
+func decimalAtof64(neg bool, d *decimal, trunc bool) (f float64, ok bool) {
+ // Exact integers are <= 10^15.
+ // Exact powers of ten are <= 10^22.
+ if d.nd > 15 {
+ return;
+ }
+ switch {
+ case d.dp == d.nd: // int
+ f := decimalAtof64Int(neg, d);
+ return f, true;
+
+ case d.dp > d.nd && d.dp <= 15+22: // int * 10^k
+ f := decimalAtof64Int(neg, d);
+ k := d.dp - d.nd;
+ // If exponent is big but number of digits is not,
+ // can move a few zeros into the integer part.
+ if k > 22 {
+ f *= float64pow10[k-22];
+ k = 22;
+ }
+ return f*float64pow10[k], true;
+
+ case d.dp < d.nd && d.nd - d.dp <= 22: // int / 10^k
+ f := decimalAtof64Int(neg, d);
+ return f/float64pow10[d.nd - d.dp], true;
+ }
+ return;
+}
+
+// If possible to convert decimal d to 32-bit float f exactly,
+// entirely in floating-point math, do so, avoiding the machinery above.
+func decimalAtof32(neg bool, d *decimal, trunc bool) (f float32, ok bool) {
+ // Exact integers are <= 10^7.
+ // Exact powers of ten are <= 10^10.
+ if d.nd > 7 {
+ return;
+ }
+ switch {
+ case d.dp == d.nd: // int
+ f := decimalAtof32Int(neg, d);
+ return f, true;
+
+ case d.dp > d.nd && d.dp <= 7+10: // int * 10^k
+ f := decimalAtof32Int(neg, d);
+ k := d.dp - d.nd;
+ // If exponent is big but number of digits is not,
+ // can move a few zeros into the integer part.
+ if k > 10 {
+ f *= float32pow10[k-10];
+ k = 10;
+ }
+ return f*float32pow10[k], true;
+
+ case d.dp < d.nd && d.nd - d.dp <= 10: // int / 10^k
+ f := decimalAtof32Int(neg, d);
+ return f/float32pow10[d.nd - d.dp], true;
+ }
+ return;
+}
+
+// Atof32 converts the string s to a 32-bit floating-point number.
+//
+// If s is well-formed and near a valid floating point number,
+// Atof32 returns the nearest floating point number rounded
+// using IEEE754 unbiased rounding.
+//
+// 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<<siz != 0 {
+ siz *= 2
+ }
+ return siz
+}
+var intsize = computeIntsize();
+
+// Return the first number n such that n*base >= 1<<64.
+func cutoff64(base int) uint64 {
+ if base < 2 {
+ return 0;
+ }
+ return (1<<64 - 1) / uint64(base) + 1;
+}
+
+// Btoui64 interprets a string s in an arbitrary base b (2 to 36)
+// and returns the corresponding value n.
+//
+// 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.
+const maxShift = 27
+
+// Binary shift right (* 2) by k bits. k <= maxShift to avoid overflow.
+func rightShift(a *decimal, k uint) {
+ r := 0; // read pointer
+ w := 0; // write pointer
+
+ // Pick up enough leading digits to cover first shift.
+ n := 0;
+ for ; n>>k == 0; r++ {
+ if r >= a.nd {
+ if n == 0 {
+ // a == 0; shouldn't get here, but handle anyway.
+ a.nd = 0;
+ return;
+ }
+ for n>>k == 0 {
+ n = n*10;
+ r++;
+ }
+ break;
+ }
+ c := int(a.d[r]);
+ n = n*10 + c-'0';
+ }
+ a.dp -= r-1;
+
+ // Pick up a digit, put down a digit.
+ for ; r < a.nd; r++ {
+ c := int(a.d[r]);
+ dig := n>>k;
+ n -= dig<<k;
+ a.d[w] = byte(dig+'0');
+ w++;
+ n = n*10 + c-'0';
+ }
+
+ // Put down extra digits.
+ for n > 0 {
+ dig := n>>k;
+ n -= dig<<k;
+ a.d[w] = byte(dig+'0');
+ w++;
+ n = n*10;
+ }
+
+ a.nd = w;
+ trim(a);
+}
+
+// Cheat sheet for left shift: table indexed by shift count giving
+// number of new digits that will be introduced by that shift.
+//
+// For example, leftcheats[4] = {2, "625"}. That means that
+// if we are shifting by 4 (multiplying by 16), it will add 2 digits
+// when the string prefix is "625" through "999", and one fewer digit
+// if the string prefix is "000" through "624".
+//
+// Credit for this trick goes to Ken.
+
+type leftCheat struct {
+ delta int; // number of new digits
+ cutoff string; // minus one digit if original < a.
+}
+
+var leftcheats = []leftCheat {
+ // Leading digits of 1/2^i = 5^i.
+ // 5^23 is not an exact 64-bit floating point number,
+ // so have to use bc for the math.
+ /*
+ seq 27 | sed 's/^/5^/' | bc |
+ awk 'BEGIN{ print "\tleftCheat{ 0, \"\" }," }
+ {
+ log2 = log(2)/log(10)
+ printf("\tleftCheat{ %d, \"%s\" },\t// * %d\n",
+ int(log2*NR+1), $0, 2**NR)
+ }'
+ */
+ leftCheat{ 0, "" },
+ leftCheat{ 1, "5" }, // * 2
+ leftCheat{ 1, "25" }, // * 4
+ leftCheat{ 1, "125" }, // * 8
+ leftCheat{ 2, "625" }, // * 16
+ leftCheat{ 2, "3125" }, // * 32
+ leftCheat{ 2, "15625" }, // * 64
+ leftCheat{ 3, "78125" }, // * 128
+ leftCheat{ 3, "390625" }, // * 256
+ leftCheat{ 3, "1953125" }, // * 512
+ leftCheat{ 4, "9765625" }, // * 1024
+ leftCheat{ 4, "48828125" }, // * 2048
+ leftCheat{ 4, "244140625" }, // * 4096
+ leftCheat{ 4, "1220703125" }, // * 8192
+ leftCheat{ 5, "6103515625" }, // * 16384
+ leftCheat{ 5, "30517578125" }, // * 32768
+ leftCheat{ 5, "152587890625" }, // * 65536
+ leftCheat{ 6, "762939453125" }, // * 131072
+ leftCheat{ 6, "3814697265625" }, // * 262144
+ leftCheat{ 6, "19073486328125" }, // * 524288
+ leftCheat{ 7, "95367431640625" }, // * 1048576
+ leftCheat{ 7, "476837158203125" }, // * 2097152
+ leftCheat{ 7, "2384185791015625" }, // * 4194304
+ leftCheat{ 7, "11920928955078125" }, // * 8388608
+ leftCheat{ 8, "59604644775390625" }, // * 16777216
+ leftCheat{ 8, "298023223876953125" }, // * 33554432
+ leftCheat{ 8, "1490116119384765625" }, // * 67108864
+ leftCheat{ 9, "7450580596923828125" }, // * 134217728
+}
+
+// Is the leading prefix of b lexicographically less than s?
+func prefixIsLessThan(b []byte, s string) bool {
+ for i := 0; i < len(s); i++ {
+ if i >= len(b) {
+ return true;
+ }
+ if b[i] != s[i] {
+ return b[i] < s[i];
+ }
+ }
+ return false;
+}
+
+// Binary shift left (/ 2) by k bits. k <= maxShift to avoid overflow.
+func leftShift(a *decimal, k uint) {
+ delta := leftcheats[k].delta;
+ if prefixIsLessThan(a.d[0:a.nd], leftcheats[k].cutoff) {
+ delta--;
+ }
+
+ r := a.nd; // read index
+ w := a.nd + delta; // write index
+ n := 0;
+
+ // Pick up a digit, put down a digit.
+ for r--; r >= 0; r-- {
+ n += (int(a.d[r])-'0') << k;
+ quo := n/10;
+ rem := n - 10*quo;
+ w--;
+ a.d[w] = byte(rem+'0');
+ n = quo;
+ }
+
+ // Put down extra digits.
+ for n > 0 {
+ quo := n/10;
+ rem := n - 10*quo;
+ w--;
+ a.d[w] = byte(rem+'0');
+ n = quo;
+ }
+
+ 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<<flt.expbits - 1);
+ mant := bits & (uint64(1)<<flt.mantbits - 1);
+
+ switch exp {
+ case 1<<flt.expbits - 1:
+ // Inf, NaN
+ if mant != 0 {
+ return "NaN";
+ }
+ if neg {
+ return "-Inf";
+ }
+ return "+Inf";
+
+ case 0:
+ // denormalized
+ exp++;
+
+ default:
+ // add implicit top bit
+ mant |= uint64(1)<<flt.mantbits;
+ }
+ exp += flt.bias;
+
+ // Pick off easy binary format.
+ if fmt == 'b' {
+ return fmtB(neg, mant, exp, flt);
+ }
+
+ // Create exact decimal representation.
+ // The shift is exp - flt.mantbits because mant is a 1-bit integer
+ // followed by a flt.mantbits fraction, and we are treating it as
+ // a 1+flt.mantbits-bit integer.
+ d := newDecimal(mant).Shift(exp - int(flt.mantbits));
+
+ // Round appropriately.
+ // Negative precision means "only as much as needed to be exact."
+ shortest := false;
+ if prec < 0 {
+ shortest = true;
+ roundShortest(d, mant, exp, flt);
+ switch fmt {
+ case 'e':
+ prec = d.nd - 1;
+ case 'f':
+ prec = max(d.nd - d.dp, 0);
+ case 'g':
+ prec = d.nd;
+ }
+ } else {
+ switch fmt {
+ case 'e':
+ d.Round(prec+1);
+ case 'f':
+ d.Round(d.dp+prec);
+ case 'g':
+ if prec == 0 {
+ prec = 1;
+ }
+ d.Round(prec);
+ }
+ }
+
+ switch fmt {
+ case 'e':
+ return fmtE(neg, d, prec);
+ case 'f':
+ return fmtF(neg, d, prec);
+ case 'g':
+ // trailing zeros are removed.
+ if prec > 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<<flt.mantbits || exp == minexp {
+ mantlo = mant - 1;
+ explo = exp;
+ } else {
+ mantlo = mant*2-1;
+ explo = exp-1;
+ }
+ lower := newDecimal(mantlo*2+1).Shift(explo-int(flt.mantbits)-1);
+
+ // The upper and lower bounds are possible outputs only if
+ // the original mantissa is even, so that IEEE round-to-even
+ // would round to the original mantissa and not the neighbors.
+ inclusive := mant%2 == 0;
+
+ // Now we can figure out the minimum number of digits required.
+ // Walk along until d has distinguished itself from upper and lower.
+ for i := 0; i < d.nd; i++ {
+ var l, m, u byte; // lower, middle, upper digits
+ if i < lower.nd {
+ l = lower.d[i];
+ } else {
+ l = '0';
+ }
+ m = d.d[i];
+ if i < upper.nd {
+ u = upper.d[i];
+ } else {
+ u = '0';
+ }
+
+ // Okay to round down (truncate) if lower has a different digit
+ // or if lower is inclusive and is exactly the result of rounding down.
+ okdown := l != m || (inclusive && l == m && i+1 == lower.nd);
+
+ // Okay to round up if upper has a different digit and
+ // either upper is inclusive or upper is bigger than the result of rounding up.
+ okup := m != u && (inclusive || i+1 < upper.nd);
+
+ // If it's okay to do either, then round to the nearest one.
+ // If it's okay to do only one, do it.
+ switch {
+ case okdown && okup:
+ d.Round(i+1);
+ return;
+ case okdown:
+ d.RoundDown(i+1);
+ return;
+ case okup:
+ d.RoundUp(i+1);
+ return;
+ }
+ }
+}
+
+// %e: -d.ddddde±dd
+func fmtE(neg bool, d *decimal, prec int) string {
+ buf := make([]byte, 3+max(prec, 0)+30); // "-0." + prec digits + exp
+ w := 0; // write index
+
+ // sign
+ if neg {
+ buf[w] = '-';
+ w++;
+ }
+
+ // first digit
+ if d.nd == 0 {
+ buf[w] = '0';
+ } else {
+ buf[w] = d.d[0];
+ }
+ w++;
+
+ // .moredigits
+ if prec > 0 {
+ buf[w] = '.';
+ w++;
+ for i := 0; i < prec; i++ {
+ if 1+i < d.nd {
+ buf[w] = d.d[1+i];
+ } else {
+ buf[w] = '0';
+ }
+ w++;
+ }
+ }
+
+ // e±
+ buf[w] = '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 <errno.h>' |
+ # 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 <sys/signal.h>' |
+ 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 <errno.h>'
+ echo '#include <signal.h>'
+ 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 <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <string.h>
+
+#define nelem(x) (sizeof(x)/sizeof((x)[0]))
+
+enum { A = 'A', Z = 'Z', a = 'a', z = 'z' }; // avoid need for single quotes below
+
+int errors[] = {
+"
+ for i in $errors
+ do
+ 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<nelem(errors); i++) {
+ e = errors[i];
+ for(j=0; j<i; j++)
+ if(errors[j] == e) // duplicate value
+ goto next;
+ strcpy(buf, strerror(e));
+ // lowercase first letter: Bad -> bad, but STREAM -> STREAM.
+ if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z)
+ buf[0] += a - A;
+ printf("\t%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 <<EOF;
+// $cmdline
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import (
+ "syscall";
+ "unsafe";
+)
+
+$text
+
+EOF
+exit 0;
diff --git a/src/pkg/syscall/mksysnum_darwin b/src/pkg/syscall/mksysnum_darwin
new file mode 100755
index 000000000..74e2dfde9
--- /dev/null
+++ b/src/pkg/syscall/mksysnum_darwin
@@ -0,0 +1,38 @@
+#!/usr/bin/perl
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+#
+# Generate system call table for Darwin from master list
+# (for example, xnu-1228/bsd/kern/syscalls.master).
+
+my $command = "mksysnum_darwin " . join(' ', @ARGV);
+
+print <<EOF;
+// $command
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+
+package syscall
+
+const (
+EOF
+
+while(<>){
+ 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 <<EOF;
+)
+EOF
diff --git a/src/pkg/syscall/mksysnum_linux b/src/pkg/syscall/mksysnum_linux
new file mode 100755
index 000000000..2252bfd7c
--- /dev/null
+++ b/src/pkg/syscall/mksysnum_linux
@@ -0,0 +1,31 @@
+#!/usr/bin/perl
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+my $command = "mklinux ". join(' ', @ARGV);
+
+print <<EOF;
+// Generated by mklinux; DO NOT EDIT.
+// $command
+
+package syscall
+
+const(
+EOF
+
+while(<>){
+ if(/^#define __NR_(\w+)\s+([0-9]+)/){
+ my $name = "SYS_$1";
+ my $num = $2;
+ $name =~ y/a-z/A-Z/;
+ print " $name = $num;\n";
+ }
+}
+
+print <<EOF;
+)
+
+func _darwin_system_call_conflict() {
+}
+EOF
diff --git a/src/pkg/syscall/syscall.go b/src/pkg/syscall/syscall.go
new file mode 100644
index 000000000..5ee44e3e8
--- /dev/null
+++ b/src/pkg/syscall/syscall.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.
+
+// This package contains an interface to the low-level operating system
+// primitives. The details vary depending on the underlying system.
+// Its primary use is inside other packages that provide a more portable
+// interface to the system, such as "os", "time" and "net". Use those
+// packages rather than this one if you can.
+// For details of the functions and data types in this package consult
+// the manuals for the appropriate operating system.
+package syscall
+
+import (
+ "syscall";
+ "unsafe";
+)
+
+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)
+
+// StringByteSlice returns a NUL-terminated slice of bytes
+// containing the text of s.
+func StringByteSlice(s string) []byte {
+ a := make([]byte, len(s)+1);
+ for i := 0; i < len(s); i++ {
+ a[i] = s[i];
+ }
+ return a;
+}
+
+// StringBytePtr returns a pointer to a NUL-terminated array of bytes
+// containing the text of s.
+func StringBytePtr(s string) *byte {
+ return &StringByteSlice(s)[0];
+}
diff --git a/src/pkg/syscall/syscall_darwin.go b/src/pkg/syscall/syscall_darwin.go
new file mode 100644
index 000000000..011fc7a0f
--- /dev/null
+++ b/src/pkg/syscall/syscall_darwin.go
@@ -0,0 +1,663 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Darwin system calls.
+// This file is compiled as ordinary Go code,
+// but it is also input to mksyscall,
+// which parses the //sys lines and generates system call stubs.
+// Note that sometimes we use a lowercase //sys name and
+// wrap it in our own nicer implementation.
+
+package syscall
+
+import (
+ "syscall";
+ "unsafe";
+)
+
+const OS = "darwin"
+
+/*
+ * Pseudo-system calls
+ */
+// The const provides a compile-time constant so clients
+// can adjust to whether there is a working Getwd and avoid
+// even linking this function into the binary. See ../os/getwd.go.
+const ImplementsGetwd = false
+
+func Getwd() (string, int) {
+ return "", ENOTSUP;
+}
+
+
+/*
+ * Wrapped
+ */
+
+//sys getgroups(ngid int, gid *_Gid_t) (n int, errno int)
+//sys setgroups(ngid int, gid *_Gid_t) (errno int)
+
+func Getgroups() (gids []int, errno int) {
+ n, err := getgroups(0, nil);
+ if err != 0 {
+ return nil, errno;
+ }
+ if n == 0 {
+ return nil, 0;
+ }
+
+ // Sanity check group count. Max is 16 on BSD.
+ if n < 0 || n > 1000 {
+ return nil, EINVAL;
+ }
+
+ a := make([]_Gid_t, n);
+ n, err = getgroups(n, &a[0]);
+ if err != 0 {
+ return nil, errno;
+ }
+ gids = make([]int, n);
+ for i, v := range a[0:n] {
+ gids[i] = int(v);
+ }
+ return;
+}
+
+func Setgroups(gids []int) (errno int) {
+ if len(gids) == 0 {
+ return setgroups(0, nil);
+ }
+
+ a := make([]_Gid_t, len(gids));
+ for i, v := range gids {
+ a[i] = _Gid_t(v);
+ }
+ return setgroups(len(a), &a[0]);
+}
+
+// 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 <dirent.h>
+#include <fcntl.h>
+#include <mach/mach.h>
+#include <mach/message.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <sys/event.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+#include <sys/param.h>
+#include <sys/ptrace.h>
+#include <sys/resource.h>
+#include <sys/select.h>
+#include <sys/signal.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+// 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 <dirent.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <sys/epoll.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+#include <sys/param.h>
+#include <sys/ptrace.h>
+#include <sys/resource.h>
+#include <sys/select.h>
+#include <sys/signal.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <sys/sysinfo.h>
+#include <sys/time.h>
+#include <sys/times.h>
+#include <sys/timex.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <sys/utsname.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+#include <ustat.h>
+#include <utime.h>
+
+// Machine characteristics; for internal use.
+
+enum
+{
+ $sizeofPtr = sizeof(void*),
+ $sizeofShort = sizeof(short),
+ $sizeofInt = sizeof(int),
+ $sizeofLong = sizeof(long),
+ $sizeofLongLong = sizeof(long long),
+ $PathMax = PATH_MAX,
+};
+
+
+// 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------------<tag>...</tag>...]
+// ^ ^ ^
+// | | |
+// 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&lt;o\t<b>bar</b>\t\n",
+ "f) f&lt;o..<b>bar</b>.....\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<!---\f--->\t3\t4\n" // \f inside HTML is ignored
+ "11\t222\t3333\t44444\n",
+
+ "1.2<!---\f--->..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\t<font color=red attr=日本語>999999999</font>\t0000000000\n",
+
+ "4444\t\t333\t22\t1\t333\n"
+ "999999999\t22\n"
+ "7\t\t22\n"
+ "\t\t\t\t88888888\n"
+ "\n"
+ "666666\t666666\t666666\t\t4444\n"
+ "1\t1\t<font color=red attr=日本語>999999999</font>\t0000000000\n"
+ },
+
+ 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("&amp;")
+var esc_lt = io.StringBytes("&lt;")
+var esc_gt = io.StringBytes("&gt;")
+
+// 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"
+ "&amp;&lt;&gt;!@ #$%^\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;<wide> 0030;0;0;0;N;;;;;
+ 0xFF11, // FF11;FULLWIDTH DIGIT ONE;Nd;0;EN;<wide> 0031;1;1;1;N;;;;;
+ 0xFF12, // FF12;FULLWIDTH DIGIT TWO;Nd;0;EN;<wide> 0032;2;2;2;N;;;;;
+ 0xFF13, // FF13;FULLWIDTH DIGIT THREE;Nd;0;EN;<wide> 0033;3;3;3;N;;;;;
+ 0xFF14, // FF14;FULLWIDTH DIGIT FOUR;Nd;0;EN;<wide> 0034;4;4;4;N;;;;;
+ 0xFF15, // FF15;FULLWIDTH DIGIT FIVE;Nd;0;EN;<wide> 0035;5;5;5;N;;;;;
+ 0xFF16, // FF16;FULLWIDTH DIGIT SIX;Nd;0;EN;<wide> 0036;6;6;6;N;;;;;
+ 0xFF17, // FF17;FULLWIDTH DIGIT SEVEN;Nd;0;EN;<wide> 0037;7;7;7;N;;;;;
+ 0xFF18, // FF18;FULLWIDTH DIGIT EIGHT;Nd;0;EN;<wide> 0038;8;8;8;N;;;;;
+ 0xFF19, // FF19;FULLWIDTH DIGIT NINE;Nd;0;EN;<wide> 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 <tag>...</tag>, or a combined start/end tag <tag/>.
+// The latter is identical in semantics to <tag></tag>,
+// 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 <img src="http://google.com/icon.png" alt="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 <a href="http://www.google.com">Google</a>
+// or <b><a href="http://www.google.com">Google</a></b>.
+// The former is an <a> element with the text "Google" inside it.
+// The latter is a <b> element with that <a> 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:
+//
+// <a href="http://www.google.com">
+// <img src="http://www.google.com/icon.png" alt="Google" />
+// <br/></a>
+//
+// 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
+// <?xml version="1.0" encoding="UTF-8"?>.
+// 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
+// <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+// "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+// 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
+// <?target text?>, 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 <?xml ...?> 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 <!--text-->. 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 &lt; and &amp;. An alternate quoting mechanism is to
+// use the construct <![CDATA[...]]>. 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 ]]&gt;. 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 <prefix:foo prefix:bar="baz">) 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:
+//
+// <tag xmlns:foo="http://google.com/foo" xmlns:bar="http://google.com/bar">
+// <foo:red bar:attr="value">text1</foo:red>
+// <bar:red>text2</bar:red>
+// </tag>
+//
+// and
+//
+// <tag xmlns:bar="http://google.com/foo" xmlns:foo="http://google.com/bar">
+// <bar:red foo:attr="value">text1</bar:red>
+// <foo:red>text2</foo:red>
+// </tag>
+//
+// 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:
+//
+// <tag xmlns="http://google.com/foo" xmlns:bar="http://google.com/bar">
+// <red bar:attr="value">text1</red>
+// <bar:red>text2</bar:red>
+// </tag>
+//
+// is another XML document equivalent to the first two, and
+//
+// <tag xmlns:bar="http://google.com/foo" xmlns="http://google.com/bar">
+// <bar:red attr="value">text1</bar:red>
+// <red>text2</red>
+// </tag>
+//
+// 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.
+ // <name attr.name=attr.value attr1.name=attr1.value ...>
+ // <name attr.name=attr.value attr1.name=attr1.value ... />
+ // 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.
+ // </name>
+ // <name ... />
+ EndElement(name Name) os.Error;
+
+ // Called for non-empty character data string inside element.
+ // Can be called multiple times between elements.
+ // text
+ // <![CDATA[text]]>
+ Text(text []byte) os.Error;
+
+ // Called when a comment is found in the XML.
+ // <!-- text -->
+ Comment(text []byte) os.Error;
+
+ // Called for a processing instruction
+ // <?target text?>
+ 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 <!DOCTYPE[^>]*>
+//
+// procinst is <\?name( .*?)\?>. name cannot be [Xx][Mm][Ll].
+//
+// comment is <!--(.*?)-->.
+//
+// tags are:
+// <name( attrib)* ?> start tag
+// <name( attrib)* ?/> combined start/end tag
+// </name ?> 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 <![CDATA[.*?]]> 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 <![CDATA[...]]>.
+//
+// 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
+