diff --git a/libgo/MERGE b/libgo/MERGE
index 5cf1a26a66f..5b7344c007d 100644
--- a/libgo/MERGE
+++ b/libgo/MERGE
@@ -1,4 +1,4 @@
-229081515358
+a7bd9a33067b
The first line of this file holds the Mercurial revision number of the
last merge done from the master library sources.
diff --git a/libgo/Makefile.am b/libgo/Makefile.am
index d54448c42a0..6a81d336819 100644
--- a/libgo/Makefile.am
+++ b/libgo/Makefile.am
@@ -211,40 +211,11 @@ toolexeclibgoencoding_DATA = \
encoding/pem.gox \
encoding/xml.gox
-if LIBGO_IS_LINUX
-# exp_inotify_gox = exp/inotify.gox
-exp_inotify_gox =
-else
-exp_inotify_gox =
-endif
-
toolexeclibgoexpdir = $(toolexeclibgodir)/exp
toolexeclibgoexp_DATA = \
- exp/cookiejar.gox \
- exp/ebnf.gox \
- exp/html.gox \
- $(exp_inotify_gox) \
- exp/norm.gox \
exp/proxy.gox \
- exp/ssa.gox \
- exp/terminal.gox \
- exp/utf8string.gox
-
-toolexeclibgoexphtmldir = $(toolexeclibgoexpdir)/html
-
-toolexeclibgoexphtml_DATA = \
- exp/html/atom.gox
-
-toolexeclibgoexplocaledir = $(toolexeclibgoexpdir)/locale
-
-toolexeclibgoexplocale_DATA = \
- exp/locale/collate.gox
-
-toolexeclibgoexplocalecollatedir = $(toolexeclibgoexplocaledir)/collate
-
-toolexeclibgoexplocalecollate_DATA = \
- exp/locale/collate/build.gox
+ exp/terminal.gox
toolexeclibgogodir = $(toolexeclibgodir)/go
@@ -256,8 +227,7 @@ toolexeclibgogo_DATA = \
go/parser.gox \
go/printer.gox \
go/scanner.gox \
- go/token.gox \
- go/types.gox
+ go/token.gox
toolexeclibgohashdir = $(toolexeclibgodir)/hash
@@ -322,6 +292,7 @@ toolexeclibgonethttpdir = $(toolexeclibgonetdir)/http
toolexeclibgonethttp_DATA = \
net/http/cgi.gox \
+ net/http/cookiejar.gox \
net/http/fcgi.gox \
net/http/httptest.gox \
net/http/httputil.gox \
@@ -335,7 +306,6 @@ toolexeclibgonetrpc_DATA = \
toolexeclibgoolddir = $(toolexeclibgodir)/old
toolexeclibgoold_DATA = \
- old/netchan.gox \
old/regexp.gox \
old/template.gox
@@ -435,6 +405,16 @@ endif
endif
endif
+if LIBGO_IS_LINUX
+runtime_netpoll_files = netpoll.c runtime/netpoll_epoll.c
+else
+if LIBGO_IS_DARWIN
+runtime_netpoll_files = netpoll.c runtime/netpoll_kqueue.c
+else
+runtime_netpoll_files = runtime/netpoll_stub.c
+endif
+endif
+
runtime_files = \
runtime/go-append.c \
runtime/go-assert.c \
@@ -513,6 +493,7 @@ runtime_files = \
runtime/mgc0.c \
runtime/mheap.c \
runtime/msize.c \
+ $(runtime_netpoll_files) \
runtime/panic.c \
runtime/parfor.c \
runtime/print.c \
@@ -548,6 +529,10 @@ mprof.c: $(srcdir)/runtime/mprof.goc goc2c
./goc2c $< > $@.tmp
mv -f $@.tmp $@
+netpoll.c: $(srcdir)/runtime/netpoll.goc goc2c
+ ./goc2c $< > $@.tmp
+ mv -f $@.tmp $@
+
reflect.c: $(srcdir)/runtime/reflect.goc goc2c
./goc2c $< > $@.tmp
mv -f $@.tmp $@
@@ -573,7 +558,8 @@ time.c: $(srcdir)/runtime/time.goc goc2c
mv -f $@.tmp $@
go_bufio_files = \
- go/bufio/bufio.go
+ go/bufio/bufio.go \
+ go/bufio/scan.go
go_bytes_files = \
go/bytes/buffer.go \
@@ -678,17 +664,17 @@ go_net_fd_os_file = go/net/fd_select.go
go_net_newpollserver_file = go/net/newpollserver_rtems.go
else # !LIBGO_IS_RTEMS
if LIBGO_IS_LINUX
-go_net_fd_os_file = go/net/fd_linux.go
-go_net_newpollserver_file = go/net/newpollserver_unix.go
+go_net_fd_os_file =
+go_net_newpollserver_file =
else # !LIBGO_IS_LINUX && !LIBGO_IS_RTEMS
if LIBGO_IS_NETBSD
go_net_fd_os_file = go/net/fd_bsd.go
-go_net_newpollserver_file = go/net/newpollserver_unix.go
+go_net_newpollserver_file =
else # !LIBGO_IS_NETBSD && !LIBGO_IS_LINUX && !LIBGO_IS_RTEMS
# By default use select with pipes. Most systems should have
# something better.
go_net_fd_os_file = go/net/fd_select.go
-go_net_newpollserver_file = go/net/newpollserver_unix.go
+go_net_newpollserver_file =
endif # !LIBGO_IS_NETBSD
endif # !LIBGO_IS_LINUX
endif # !LIBGO_IS_RTEMS
@@ -759,6 +745,16 @@ else
go_net_cloexec_file = go/net/sys_cloexec.go
endif
+if LIBGO_IS_LINUX
+go_net_poll_file = go/net/fd_poll_runtime.go
+else
+if LIBGO_IS_DARWIN
+go_net_poll_file = go/net/fd_poll_runtime.go
+else
+go_net_poll_file = go/net/fd_poll_unix.go
+endif
+endif
+
go_net_files = \
go/net/cgo_unix.go \
$(go_net_cgo_file) \
@@ -786,10 +782,12 @@ go_net_files = \
go/net/net.go \
go/net/parse.go \
go/net/pipe.go \
+ $(go_net_poll_file) \
go/net/port.go \
go/net/port_unix.go \
$(go_net_sendfile_file) \
go/net/sock_posix.go \
+ go/net/sock_unix.go \
$(go_net_sock_file) \
go/net/sockopt_posix.go \
$(go_net_sockopt_file) \
@@ -890,7 +888,8 @@ go_os_files = \
$(go_os_stat_file) \
go/os/str.go \
$(go_os_sys_file) \
- go/os/types.go
+ go/os/types.go \
+ go/os/types_notwin.go
go_path_files = \
go/path/match.go \
@@ -979,6 +978,7 @@ go_syslog_c_files = \
go/log/syslog/syslog_c.c
go_testing_files = \
+ go/testing/allocs.go \
go/testing/benchmark.go \
go/testing/example.go \
go/testing/testing.go
@@ -1101,7 +1101,8 @@ go_crypto_rand_files = \
go/crypto/rand/rand_unix.go \
go/crypto/rand/util.go
go_crypto_rc4_files = \
- go/crypto/rc4/rc4.go
+ go/crypto/rc4/rc4.go \
+ go/crypto/rc4/rc4_ref.go
go_crypto_rsa_files = \
go/crypto/rsa/pkcs1v15.go \
go/crypto/rsa/rsa.go
@@ -1212,73 +1213,14 @@ go_encoding_xml_files = \
go/encoding/xml/typeinfo.go \
go/encoding/xml/xml.go
-go_exp_cookiejar_files = \
- go/exp/cookiejar/jar.go \
- go/exp/cookiejar/storage.go
-go_exp_ebnf_files = \
- go/exp/ebnf/ebnf.go \
- go/exp/ebnf/parser.go
-go_exp_html_files = \
- go/exp/html/const.go \
- go/exp/html/doc.go \
- go/exp/html/doctype.go \
- go/exp/html/entity.go \
- go/exp/html/escape.go \
- go/exp/html/foreign.go \
- go/exp/html/node.go \
- go/exp/html/parse.go \
- go/exp/html/render.go \
- go/exp/html/token.go
-go_exp_html_atom_files = \
- go/exp/html/atom/atom.go \
- go/exp/html/atom/table.go
-go_exp_inotify_files = \
- go/exp/inotify/inotify_linux.go
-go_exp_locale_collate_files = \
- go/exp/locale/collate/colelem.go \
- go/exp/locale/collate/collate.go \
- go/exp/locale/collate/colltab.go \
- go/exp/locale/collate/contract.go \
- go/exp/locale/collate/export.go \
- go/exp/locale/collate/sort.go \
- go/exp/locale/collate/table.go \
- go/exp/locale/collate/tables.go \
- go/exp/locale/collate/trie.go
-go_exp_locale_collate_build_files = \
- go/exp/locale/collate/build/builder.go \
- go/exp/locale/collate/build/colelem.go \
- go/exp/locale/collate/build/contract.go \
- go/exp/locale/collate/build/order.go \
- go/exp/locale/collate/build/table.go \
- go/exp/locale/collate/build/trie.go
-go_exp_norm_files = \
- go/exp/norm/composition.go \
- go/exp/norm/forminfo.go \
- go/exp/norm/input.go \
- go/exp/norm/iter.go \
- go/exp/norm/normalize.go \
- go/exp/norm/readwriter.go \
- go/exp/norm/tables.go \
- go/exp/norm/trie.go
go_exp_proxy_files = \
go/exp/proxy/direct.go \
go/exp/proxy/per_host.go \
go/exp/proxy/proxy.go \
go/exp/proxy/socks5.go
-go_exp_ssa_files = \
- go/exp/ssa/blockopt.go \
- go/exp/ssa/doc.go \
- go/exp/ssa/func.go \
- go/exp/ssa/sanity.go \
- go/exp/ssa/ssa.go \
- go/exp/ssa/literal.go \
- go/exp/ssa/print.go \
- go/exp/ssa/util.go
go_exp_terminal_files = \
go/exp/terminal/terminal.go \
go/exp/terminal/util.go
-go_exp_utf8string_files = \
- go/exp/utf8string/string.go
go_go_ast_files = \
go/go/ast/ast.go \
@@ -1317,24 +1259,6 @@ go_go_token_files = \
go/go/token/position.go \
go/go/token/serialize.go \
go/go/token/token.go
-go_go_types_files = \
- go/go/types/api.go \
- go/go/types/builtins.go \
- go/go/types/check.go \
- go/go/types/const.go \
- go/go/types/conversions.go \
- go/go/types/errors.go \
- go/go/types/exportdata.go \
- go/go/types/expr.go \
- go/go/types/gcimporter.go \
- go/go/types/objects.go \
- go/go/types/operand.go \
- go/go/types/predicates.go \
- go/go/types/resolve.go \
- go/go/types/scope.go \
- go/go/types/stmt.go \
- go/go/types/types.go \
- go/go/types/universe.go
go_hash_adler32_files = \
go/hash/adler32/adler32.go
@@ -1458,6 +1382,9 @@ go_net_url_files = \
go_net_http_cgi_files = \
go/net/http/cgi/child.go \
go/net/http/cgi/host.go
+go_net_http_cookiejar_files = \
+ go/net/http/cookiejar/jar.go \
+ go/net/http/cookiejar/punycode.go
go_net_http_fcgi_files = \
go/net/http/fcgi/child.go \
go/net/http/fcgi/fcgi.go
@@ -1473,10 +1400,6 @@ go_net_http_httputil_files = \
go/net/http/httputil/reverseproxy.go
-go_old_netchan_files = \
- go/old/netchan/common.go \
- go/old/netchan/export.go \
- go/old/netchan/import.go
go_old_regexp_files = \
go/old/regexp/regexp.go
go_old_template_files = \
@@ -1518,6 +1441,7 @@ go_net_rpc_jsonrpc_files = \
go/net/rpc/jsonrpc/server.go
go_runtime_debug_files = \
+ go/runtime/debug/garbage.go \
go/runtime/debug/stack.go
go_runtime_pprof_files = \
go/runtime/pprof/pprof.go
@@ -1896,17 +1820,8 @@ libgo_go_objs = \
encoding/json.lo \
encoding/pem.lo \
encoding/xml.lo \
- exp/cookiejar.lo \
- exp/ebnf.lo \
- exp/html.lo \
- exp/html/atom.lo \
- exp/locale/collate.lo \
- exp/locale/collate/build.lo \
- exp/norm.lo \
exp/proxy.lo \
- exp/ssa.lo \
exp/terminal.lo \
- exp/utf8string.lo \
html/template.lo \
go/ast.lo \
go/build.lo \
@@ -1916,12 +1831,12 @@ libgo_go_objs = \
go/printer.lo \
go/scanner.lo \
go/token.lo \
- go/types.lo \
hash/adler32.lo \
hash/crc32.lo \
hash/crc64.lo \
hash/fnv.lo \
net/http/cgi.lo \
+ net/http/cookiejar.lo \
net/http/fcgi.lo \
net/http/httptest.lo \
net/http/httputil.lo \
@@ -1945,7 +1860,6 @@ libgo_go_objs = \
net/smtp.lo \
net/textproto.lo \
net/url.lo \
- old/netchan.lo \
old/regexp.lo \
old/template.lo \
os/exec.lo \
@@ -2730,69 +2644,6 @@ encoding/xml/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: encoding/xml/check
-@go_include@ exp/cookiejar.lo.dep
-exp/cookiejar.lo.dep: $(go_exp_cookiejar_files)
- $(BUILDDEPS)
-exp/cookiejar.lo: $(go_exp_cookiejar_files)
- $(BUILDPACKAGE)
-exp/cookiejar/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: exp/cookiejar/check
-
-@go_include@ exp/ebnf.lo.dep
-exp/ebnf.lo.dep: $(go_exp_ebnf_files)
- $(BUILDDEPS)
-exp/ebnf.lo: $(go_exp_ebnf_files)
- $(BUILDPACKAGE)
-exp/ebnf/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: exp/ebnf/check
-
-@go_include@ exp/html.lo.dep
-exp/html.lo.dep: $(go_exp_html_files)
- $(BUILDDEPS)
-exp/html.lo: $(go_exp_html_files)
- $(BUILDPACKAGE)
-exp/html/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: exp/html/check
-
-@go_include@ exp/html/atom.lo.dep
-exp/html/atom.lo.dep: $(go_exp_html_atom_files)
- $(BUILDDEPS)
-exp/html/atom.lo: $(go_exp_html_atom_files)
- $(BUILDPACKAGE)
-exp/html/atom/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: exp/html/atom/check
-
-@go_include@ exp/locale/collate.lo.dep
-exp/locale/collate.lo.dep: $(go_exp_locale_collate_files)
- $(BUILDDEPS)
-exp/locale/collate.lo: $(go_exp_locale_collate_files)
- $(BUILDPACKAGE)
-exp/locale/collate/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: exp/locale/collate/check
-
-@go_include@ exp/locale/collate/build.lo.dep
-exp/locale/collate/build.lo.dep: $(go_exp_locale_collate_build_files)
- $(BUILDDEPS)
-exp/locale/collate/build.lo: $(go_exp_locale_collate_build_files)
- $(BUILDPACKAGE)
-exp/locale/collate/build/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: exp/locale/collate/build/check
-
-@go_include@ exp/norm.lo.dep
-exp/norm.lo.dep: $(go_exp_norm_files)
- $(BUILDDEPS)
-exp/norm.lo: $(go_exp_norm_files)
- $(BUILDPACKAGE)
-exp/norm/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: exp/norm/check
-
@go_include@ exp/proxy.lo.dep
exp/proxy.lo.dep: $(go_exp_proxy_files)
$(BUILDDEPS)
@@ -2802,15 +2653,6 @@ exp/proxy/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: exp/proxy/check
-@go_include@ exp/ssa.lo.dep
-exp/ssa.lo.dep: $(go_exp_ssa_files)
- $(BUILDDEPS)
-exp/ssa.lo: $(go_exp_ssa_files)
- $(BUILDPACKAGE)
-exp/ssa/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: exp/ssa/check
-
@go_include@ exp/terminal.lo.dep
exp/terminal.lo.dep: $(go_exp_terminal_files)
$(BUILDDEPS)
@@ -2820,24 +2662,6 @@ exp/terminal/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: exp/terminal/check
-@go_include@ exp/utf8string.lo.dep
-exp/utf8string.lo.dep: $(go_exp_utf8string_files)
- $(BUILDDEPS)
-exp/utf8string.lo: $(go_exp_utf8string_files)
- $(BUILDPACKAGE)
-exp/utf8string/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: exp/utf8string/check
-
-@go_include@ exp/inotify.lo.dep
-exp/inotify.lo.dep: $(go_exp_inotify_files)
- $(BUILDDEPS)
-exp/inotify.lo: $(go_exp_inotify_files)
- $(BUILDPACKAGE)
-exp/inotify/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: exp/inotify/check
-
@go_include@ html/template.lo.dep
html/template.lo.dep: $(go_html_template_files)
$(BUILDDEPS)
@@ -2928,15 +2752,6 @@ go/token/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: go/token/check
-@go_include@ go/types.lo.dep
-go/types.lo.dep: $(go_go_types_files)
- $(BUILDDEPS)
-go/types.lo: $(go_go_types_files)
- $(BUILDPACKAGE)
-go/types/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/types/check
-
@go_include@ hash/adler32.lo.dep
hash/adler32.lo.dep: $(go_hash_adler32_files)
$(BUILDDEPS)
@@ -3147,6 +2962,15 @@ net/http/cgi/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: net/http/cgi/check
+@go_include@ net/http/cookiejar.lo.dep
+net/http/cookiejar.lo.dep: $(go_net_http_cookiejar_files)
+ $(BUILDDEPS)
+net/http/cookiejar.lo: $(go_net_http_cookiejar_files)
+ $(BUILDPACKAGE)
+net/http/cookiejar/check: $(CHECK_DEPS)
+ @$(CHECK)
+.PHONY: net/http/cookiejar/check
+
@go_include@ net/http/fcgi.lo.dep
net/http/fcgi.lo.dep: $(go_net_http_fcgi_files)
$(BUILDDEPS)
@@ -3192,15 +3016,6 @@ net/rpc/jsonrpc/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: net/rpc/jsonrpc/check
-@go_include@ old/netchan.lo.dep
-old/netchan.lo.dep: $(go_old_netchan_files)
- $(BUILDDEPS)
-old/netchan.lo: $(go_old_netchan_files)
- $(BUILDPACKAGE)
-old/netchan/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: old/netchan/check
-
@go_include@ old/regexp.lo.dep
old/regexp.lo.dep: $(go_old_regexp_files)
$(BUILDDEPS)
@@ -3549,30 +3364,10 @@ encoding/pem.gox: encoding/pem.lo
encoding/xml.gox: encoding/xml.lo
$(BUILDGOX)
-exp/cookiejar.gox: exp/cookiejar.lo
- $(BUILDGOX)
-exp/ebnf.gox: exp/ebnf.lo
- $(BUILDGOX)
-exp/html.gox: exp/html.lo
- $(BUILDGOX)
-exp/html/atom.gox: exp/html/atom.lo
- $(BUILDGOX)
-exp/inotify.gox: exp/inotify.lo
- $(BUILDGOX)
-exp/locale/collate.gox: exp/locale/collate.lo
- $(BUILDGOX)
-exp/locale/collate/build.gox: exp/locale/collate/build.lo
- $(BUILDGOX)
-exp/norm.gox: exp/norm.lo
- $(BUILDGOX)
exp/proxy.gox: exp/proxy.lo
$(BUILDGOX)
-exp/ssa.gox: exp/ssa.lo
- $(BUILDGOX)
exp/terminal.gox: exp/terminal.lo
$(BUILDGOX)
-exp/utf8string.gox: exp/utf8string.lo
- $(BUILDGOX)
html/template.gox: html/template.lo
$(BUILDGOX)
@@ -3593,8 +3388,6 @@ go/scanner.gox: go/scanner.lo
$(BUILDGOX)
go/token.gox: go/token.lo
$(BUILDGOX)
-go/types.gox: go/types.lo
- $(BUILDGOX)
hash/adler32.gox: hash/adler32.lo
$(BUILDGOX)
@@ -3650,6 +3443,8 @@ net/url.gox: net/url.lo
net/http/cgi.gox: net/http/cgi.lo
$(BUILDGOX)
+net/http/cookiejar.gox: net/http/cookiejar.lo
+ $(BUILDGOX)
net/http/fcgi.gox: net/http/fcgi.lo
$(BUILDGOX)
net/http/httptest.gox: net/http/httptest.lo
@@ -3662,8 +3457,6 @@ net/http/pprof.gox: net/http/pprof.lo
net/rpc/jsonrpc.gox: net/rpc/jsonrpc.lo
$(BUILDGOX)
-old/netchan.gox: old/netchan.lo
- $(BUILDGOX)
old/regexp.gox: old/regexp.lo
$(BUILDGOX)
old/template.gox: old/template.lo
@@ -3709,13 +3502,6 @@ unicode/utf16.gox: unicode/utf16.lo
unicode/utf8.gox: unicode/utf8.lo
$(BUILDGOX)
-if LIBGO_IS_LINUX
-# exp_inotify_check = exp/inotify/check
-exp_inotify_check =
-else
-exp_inotify_check =
-endif
-
TEST_PACKAGES = \
bufio/check \
bytes/check \
@@ -3786,17 +3572,8 @@ TEST_PACKAGES = \
encoding/json/check \
encoding/pem/check \
encoding/xml/check \
- exp/cookiejar/check \
- exp/ebnf/check \
- exp/html/check \
- exp/html/atom/check \
- $(exp_inotify_check) \
- exp/locale/collate/check \
- exp/locale/collate/build/check \
- exp/norm/check \
exp/proxy/check \
exp/terminal/check \
- exp/utf8string/check \
html/template/check \
go/ast/check \
$(go_build_check_omitted_since_it_calls_6g) \
@@ -3806,7 +3583,6 @@ TEST_PACKAGES = \
go/printer/check \
go/scanner/check \
go/token/check \
- go/types/check \
hash/adler32/check \
hash/crc32/check \
hash/crc64/check \
@@ -3824,6 +3600,7 @@ TEST_PACKAGES = \
mime/multipart/check \
net/http/check \
net/http/cgi/check \
+ net/http/cookiejar/check \
net/http/fcgi/check \
net/http/httptest/check \
net/http/httputil/check \
@@ -3833,7 +3610,6 @@ TEST_PACKAGES = \
net/textproto/check \
net/url/check \
net/rpc/jsonrpc/check \
- old/netchan/check \
old/regexp/check \
old/template/check \
os/exec/check \
diff --git a/libgo/Makefile.in b/libgo/Makefile.in
index 08eae578e51..eccc72d2e3c 100644
--- a/libgo/Makefile.in
+++ b/libgo/Makefile.in
@@ -101,9 +101,6 @@ am__installdirs = "$(DESTDIR)$(toolexeclibdir)" \
"$(DESTDIR)$(toolexeclibgodebugdir)" \
"$(DESTDIR)$(toolexeclibgoencodingdir)" \
"$(DESTDIR)$(toolexeclibgoexpdir)" \
- "$(DESTDIR)$(toolexeclibgoexphtmldir)" \
- "$(DESTDIR)$(toolexeclibgoexplocaledir)" \
- "$(DESTDIR)$(toolexeclibgoexplocalecollatedir)" \
"$(DESTDIR)$(toolexeclibgogodir)" \
"$(DESTDIR)$(toolexeclibgohashdir)" \
"$(DESTDIR)$(toolexeclibgohtmldir)" \
@@ -153,22 +150,20 @@ am__DEPENDENCIES_2 = bufio.lo bytes.lo bytes/index.lo crypto.lo \
debug/pe.lo encoding/ascii85.lo encoding/asn1.lo \
encoding/base32.lo encoding/base64.lo encoding/binary.lo \
encoding/csv.lo encoding/gob.lo encoding/hex.lo \
- encoding/json.lo encoding/pem.lo encoding/xml.lo \
- exp/cookiejar.lo exp/ebnf.lo exp/html.lo exp/html/atom.lo \
- exp/locale/collate.lo exp/locale/collate/build.lo exp/norm.lo \
- exp/proxy.lo exp/ssa.lo exp/terminal.lo exp/utf8string.lo \
- html/template.lo go/ast.lo go/build.lo go/doc.lo go/format.lo \
- go/parser.lo go/printer.lo go/scanner.lo go/token.lo \
- go/types.lo hash/adler32.lo hash/crc32.lo hash/crc64.lo \
- hash/fnv.lo net/http/cgi.lo net/http/fcgi.lo \
- net/http/httptest.lo net/http/httputil.lo net/http/pprof.lo \
- image/color.lo image/draw.lo image/gif.lo image/jpeg.lo \
- image/png.lo index/suffixarray.lo io/ioutil.lo log/syslog.lo \
+ encoding/json.lo encoding/pem.lo encoding/xml.lo exp/proxy.lo \
+ exp/terminal.lo html/template.lo go/ast.lo go/build.lo \
+ go/doc.lo go/format.lo go/parser.lo go/printer.lo \
+ go/scanner.lo go/token.lo hash/adler32.lo hash/crc32.lo \
+ hash/crc64.lo hash/fnv.lo net/http/cgi.lo \
+ net/http/cookiejar.lo net/http/fcgi.lo net/http/httptest.lo \
+ net/http/httputil.lo net/http/pprof.lo image/color.lo \
+ image/draw.lo image/gif.lo image/jpeg.lo image/png.lo \
+ index/suffixarray.lo io/ioutil.lo log/syslog.lo \
log/syslog/syslog_c.lo math/big.lo math/cmplx.lo math/rand.lo \
mime/multipart.lo net/http.lo net/mail.lo net/rpc.lo \
- net/smtp.lo net/textproto.lo net/url.lo old/netchan.lo \
- old/regexp.lo old/template.lo os/exec.lo $(am__DEPENDENCIES_1) \
- os/signal.lo os/user.lo path/filepath.lo regexp/syntax.lo \
+ net/smtp.lo net/textproto.lo net/url.lo old/regexp.lo \
+ old/template.lo os/exec.lo $(am__DEPENDENCIES_1) os/signal.lo \
+ os/user.lo path/filepath.lo regexp/syntax.lo \
net/rpc/jsonrpc.lo runtime/debug.lo runtime/pprof.lo \
sync/atomic.lo sync/atomic_c.lo text/scanner.lo \
text/tabwriter.lo text/template.lo text/template/parse.lo \
@@ -183,16 +178,22 @@ libgo_la_DEPENDENCIES = $(am__DEPENDENCIES_2) \
@LIBGO_IS_LINUX_TRUE@am__objects_1 = lock_futex.lo thread-linux.lo
@HAVE_SYS_MMAN_H_FALSE@am__objects_2 = mem_posix_memalign.lo
@HAVE_SYS_MMAN_H_TRUE@am__objects_2 = mem.lo
-@LIBGO_IS_RTEMS_TRUE@am__objects_3 = rtems-task-variable-add.lo
-@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@am__objects_4 = getncpu-none.lo
-@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_SOLARIS_FALSE@am__objects_4 = getncpu-bsd.lo
-@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@am__objects_4 = getncpu-bsd.lo
-@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@am__objects_4 = getncpu-solaris.lo
-@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_IRIX_TRUE@@LIBGO_IS_LINUX_FALSE@am__objects_4 = getncpu-irix.lo
-@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_LINUX_FALSE@am__objects_4 = \
+@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_LINUX_FALSE@am__objects_3 = \
+@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_LINUX_FALSE@ netpoll_stub.lo
+@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_LINUX_FALSE@am__objects_3 = \
+@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_LINUX_FALSE@ netpoll.lo \
+@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_LINUX_FALSE@ netpoll_kqueue.lo
+@LIBGO_IS_LINUX_TRUE@am__objects_3 = netpoll.lo netpoll_epoll.lo
+@LIBGO_IS_RTEMS_TRUE@am__objects_4 = rtems-task-variable-add.lo
+@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@am__objects_5 = getncpu-none.lo
+@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_SOLARIS_FALSE@am__objects_5 = getncpu-bsd.lo
+@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@am__objects_5 = getncpu-bsd.lo
+@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@am__objects_5 = getncpu-solaris.lo
+@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_IRIX_TRUE@@LIBGO_IS_LINUX_FALSE@am__objects_5 = getncpu-irix.lo
+@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_LINUX_FALSE@am__objects_5 = \
@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_LINUX_FALSE@ getncpu-bsd.lo
-@LIBGO_IS_LINUX_TRUE@am__objects_4 = getncpu-linux.lo
-am__objects_5 = go-append.lo go-assert.lo go-assert-interface.lo \
+@LIBGO_IS_LINUX_TRUE@am__objects_5 = getncpu-linux.lo
+am__objects_6 = go-append.lo go-assert.lo go-assert-interface.lo \
go-byte-array-to-string.lo go-breakpoint.lo go-caller.lo \
go-callers.lo go-can-convert-interface.lo go-cgo.lo \
go-check-interface.lo go-construct-map.lo \
@@ -215,12 +216,12 @@ am__objects_5 = go-append.lo go-assert.lo go-assert-interface.lo \
go-unsafe-new.lo go-unsafe-newarray.lo go-unsafe-pointer.lo \
go-unwind.lo chan.lo cpuprof.lo env_posix.lo lfstack.lo \
$(am__objects_1) mcache.lo mcentral.lo $(am__objects_2) \
- mfinal.lo mfixalloc.lo mgc0.lo mheap.lo msize.lo panic.lo \
- parfor.lo print.lo proc.lo runtime.lo signal_unix.lo thread.lo \
- yield.lo $(am__objects_3) iface.lo malloc.lo map.lo mprof.lo \
- reflect.lo runtime1.lo sema.lo sigqueue.lo string.lo time.lo \
- $(am__objects_4)
-am_libgo_la_OBJECTS = $(am__objects_5)
+ mfinal.lo mfixalloc.lo mgc0.lo mheap.lo msize.lo \
+ $(am__objects_3) panic.lo parfor.lo print.lo proc.lo \
+ runtime.lo signal_unix.lo thread.lo yield.lo $(am__objects_4) \
+ iface.lo malloc.lo map.lo mprof.lo reflect.lo runtime1.lo \
+ sema.lo sigqueue.lo string.lo time.lo $(am__objects_5)
+am_libgo_la_OBJECTS = $(am__objects_6)
libgo_la_OBJECTS = $(am_libgo_la_OBJECTS)
libgo_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(libgo_la_LDFLAGS) \
@@ -257,9 +258,7 @@ DATA = $(toolexeclibgo_DATA) $(toolexeclibgoarchive_DATA) \
$(toolexeclibgocrypto_DATA) $(toolexeclibgocryptox509_DATA) \
$(toolexeclibgodatabase_DATA) $(toolexeclibgodatabasesql_DATA) \
$(toolexeclibgodebug_DATA) $(toolexeclibgoencoding_DATA) \
- $(toolexeclibgoexp_DATA) $(toolexeclibgoexphtml_DATA) \
- $(toolexeclibgoexplocale_DATA) \
- $(toolexeclibgoexplocalecollate_DATA) $(toolexeclibgogo_DATA) \
+ $(toolexeclibgoexp_DATA) $(toolexeclibgogo_DATA) \
$(toolexeclibgohash_DATA) $(toolexeclibgohtml_DATA) \
$(toolexeclibgoimage_DATA) $(toolexeclibgoindex_DATA) \
$(toolexeclibgoio_DATA) $(toolexeclibgolog_DATA) \
@@ -606,33 +605,10 @@ toolexeclibgoencoding_DATA = \
encoding/pem.gox \
encoding/xml.gox
-@LIBGO_IS_LINUX_FALSE@exp_inotify_gox =
-
-# exp_inotify_gox = exp/inotify.gox
-@LIBGO_IS_LINUX_TRUE@exp_inotify_gox =
toolexeclibgoexpdir = $(toolexeclibgodir)/exp
toolexeclibgoexp_DATA = \
- exp/cookiejar.gox \
- exp/ebnf.gox \
- exp/html.gox \
- $(exp_inotify_gox) \
- exp/norm.gox \
exp/proxy.gox \
- exp/ssa.gox \
- exp/terminal.gox \
- exp/utf8string.gox
-
-toolexeclibgoexphtmldir = $(toolexeclibgoexpdir)/html
-toolexeclibgoexphtml_DATA = \
- exp/html/atom.gox
-
-toolexeclibgoexplocaledir = $(toolexeclibgoexpdir)/locale
-toolexeclibgoexplocale_DATA = \
- exp/locale/collate.gox
-
-toolexeclibgoexplocalecollatedir = $(toolexeclibgoexplocaledir)/collate
-toolexeclibgoexplocalecollate_DATA = \
- exp/locale/collate/build.gox
+ exp/terminal.gox
toolexeclibgogodir = $(toolexeclibgodir)/go
toolexeclibgogo_DATA = \
@@ -643,8 +619,7 @@ toolexeclibgogo_DATA = \
go/parser.gox \
go/printer.gox \
go/scanner.gox \
- go/token.gox \
- go/types.gox
+ go/token.gox
toolexeclibgohashdir = $(toolexeclibgodir)/hash
toolexeclibgohash_DATA = \
@@ -699,6 +674,7 @@ toolexeclibgonet_DATA = \
toolexeclibgonethttpdir = $(toolexeclibgonetdir)/http
toolexeclibgonethttp_DATA = \
net/http/cgi.gox \
+ net/http/cookiejar.gox \
net/http/fcgi.gox \
net/http/httptest.gox \
net/http/httputil.gox \
@@ -710,7 +686,6 @@ toolexeclibgonetrpc_DATA = \
toolexeclibgoolddir = $(toolexeclibgodir)/old
toolexeclibgoold_DATA = \
- old/netchan.gox \
old/regexp.gox \
old/template.gox
@@ -770,6 +745,9 @@ toolexeclibgounicode_DATA = \
@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_IRIX_TRUE@@LIBGO_IS_LINUX_FALSE@runtime_getncpu_file = runtime/getncpu-irix.c
@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_LINUX_FALSE@runtime_getncpu_file = runtime/getncpu-bsd.c
@LIBGO_IS_LINUX_TRUE@runtime_getncpu_file = runtime/getncpu-linux.c
+@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_LINUX_FALSE@runtime_netpoll_files = runtime/netpoll_stub.c
+@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_LINUX_FALSE@runtime_netpoll_files = netpoll.c runtime/netpoll_kqueue.c
+@LIBGO_IS_LINUX_TRUE@runtime_netpoll_files = netpoll.c runtime/netpoll_epoll.c
runtime_files = \
runtime/go-append.c \
runtime/go-assert.c \
@@ -848,6 +826,7 @@ runtime_files = \
runtime/mgc0.c \
runtime/mheap.c \
runtime/msize.c \
+ $(runtime_netpoll_files) \
runtime/panic.c \
runtime/parfor.c \
runtime/print.c \
@@ -870,7 +849,8 @@ runtime_files = \
$(runtime_getncpu_file)
go_bufio_files = \
- go/bufio/bufio.go
+ go/bufio/bufio.go \
+ go/bufio/scan.go
go_bytes_files = \
go/bytes/buffer.go \
@@ -975,11 +955,11 @@ go_mime_files = \
# something better.
@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_RTEMS_FALSE@go_net_fd_os_file = go/net/fd_select.go
@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_RTEMS_FALSE@go_net_fd_os_file = go/net/fd_bsd.go
-@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_RTEMS_FALSE@go_net_fd_os_file = go/net/fd_linux.go
+@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_RTEMS_FALSE@go_net_fd_os_file =
@LIBGO_IS_RTEMS_TRUE@go_net_fd_os_file = go/net/fd_select.go
-@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_RTEMS_FALSE@go_net_newpollserver_file = go/net/newpollserver_unix.go
-@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_RTEMS_FALSE@go_net_newpollserver_file = go/net/newpollserver_unix.go
-@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_RTEMS_FALSE@go_net_newpollserver_file = go/net/newpollserver_unix.go
+@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_RTEMS_FALSE@go_net_newpollserver_file =
+@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_RTEMS_FALSE@go_net_newpollserver_file =
+@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_RTEMS_FALSE@go_net_newpollserver_file =
@LIBGO_IS_RTEMS_TRUE@go_net_newpollserver_file = go/net/newpollserver_rtems.go
@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_cgo_file = go/net/cgo_bsd.go
@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_SOLARIS_FALSE@go_net_cgo_file = go/net/cgo_netbsd.go
@@ -1013,6 +993,9 @@ go_mime_files = \
@LIBGO_IS_LINUX_TRUE@go_net_interface_file = go/net/interface_linux.go
@LIBGO_IS_LINUX_FALSE@go_net_cloexec_file = go/net/sys_cloexec.go
@LIBGO_IS_LINUX_TRUE@go_net_cloexec_file = go/net/sock_cloexec.go
+@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_LINUX_FALSE@go_net_poll_file = go/net/fd_poll_unix.go
+@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_LINUX_FALSE@go_net_poll_file = go/net/fd_poll_runtime.go
+@LIBGO_IS_LINUX_TRUE@go_net_poll_file = go/net/fd_poll_runtime.go
go_net_files = \
go/net/cgo_unix.go \
$(go_net_cgo_file) \
@@ -1040,10 +1023,12 @@ go_net_files = \
go/net/net.go \
go/net/parse.go \
go/net/pipe.go \
+ $(go_net_poll_file) \
go/net/port.go \
go/net/port_unix.go \
$(go_net_sendfile_file) \
go/net/sock_posix.go \
+ go/net/sock_unix.go \
$(go_net_sock_file) \
go/net/sockopt_posix.go \
$(go_net_sockopt_file) \
@@ -1095,7 +1080,8 @@ go_os_files = \
$(go_os_stat_file) \
go/os/str.go \
$(go_os_sys_file) \
- go/os/types.go
+ go/os/types.go \
+ go/os/types_notwin.go
go_path_files = \
go/path/match.go \
@@ -1167,6 +1153,7 @@ go_syslog_c_files = \
go/log/syslog/syslog_c.c
go_testing_files = \
+ go/testing/allocs.go \
go/testing/benchmark.go \
go/testing/example.go \
go/testing/testing.go
@@ -1285,7 +1272,8 @@ go_crypto_rand_files = \
go/crypto/rand/util.go
go_crypto_rc4_files = \
- go/crypto/rc4/rc4.go
+ go/crypto/rc4/rc4.go \
+ go/crypto/rc4/rc4_ref.go
go_crypto_rsa_files = \
go/crypto/rsa/pkcs1v15.go \
@@ -1417,85 +1405,16 @@ go_encoding_xml_files = \
go/encoding/xml/typeinfo.go \
go/encoding/xml/xml.go
-go_exp_cookiejar_files = \
- go/exp/cookiejar/jar.go \
- go/exp/cookiejar/storage.go
-
-go_exp_ebnf_files = \
- go/exp/ebnf/ebnf.go \
- go/exp/ebnf/parser.go
-
-go_exp_html_files = \
- go/exp/html/const.go \
- go/exp/html/doc.go \
- go/exp/html/doctype.go \
- go/exp/html/entity.go \
- go/exp/html/escape.go \
- go/exp/html/foreign.go \
- go/exp/html/node.go \
- go/exp/html/parse.go \
- go/exp/html/render.go \
- go/exp/html/token.go
-
-go_exp_html_atom_files = \
- go/exp/html/atom/atom.go \
- go/exp/html/atom/table.go
-
-go_exp_inotify_files = \
- go/exp/inotify/inotify_linux.go
-
-go_exp_locale_collate_files = \
- go/exp/locale/collate/colelem.go \
- go/exp/locale/collate/collate.go \
- go/exp/locale/collate/colltab.go \
- go/exp/locale/collate/contract.go \
- go/exp/locale/collate/export.go \
- go/exp/locale/collate/sort.go \
- go/exp/locale/collate/table.go \
- go/exp/locale/collate/tables.go \
- go/exp/locale/collate/trie.go
-
-go_exp_locale_collate_build_files = \
- go/exp/locale/collate/build/builder.go \
- go/exp/locale/collate/build/colelem.go \
- go/exp/locale/collate/build/contract.go \
- go/exp/locale/collate/build/order.go \
- go/exp/locale/collate/build/table.go \
- go/exp/locale/collate/build/trie.go
-
-go_exp_norm_files = \
- go/exp/norm/composition.go \
- go/exp/norm/forminfo.go \
- go/exp/norm/input.go \
- go/exp/norm/iter.go \
- go/exp/norm/normalize.go \
- go/exp/norm/readwriter.go \
- go/exp/norm/tables.go \
- go/exp/norm/trie.go
-
go_exp_proxy_files = \
go/exp/proxy/direct.go \
go/exp/proxy/per_host.go \
go/exp/proxy/proxy.go \
go/exp/proxy/socks5.go
-go_exp_ssa_files = \
- go/exp/ssa/blockopt.go \
- go/exp/ssa/doc.go \
- go/exp/ssa/func.go \
- go/exp/ssa/sanity.go \
- go/exp/ssa/ssa.go \
- go/exp/ssa/literal.go \
- go/exp/ssa/print.go \
- go/exp/ssa/util.go
-
go_exp_terminal_files = \
go/exp/terminal/terminal.go \
go/exp/terminal/util.go
-go_exp_utf8string_files = \
- go/exp/utf8string/string.go
-
go_go_ast_files = \
go/go/ast/ast.go \
go/go/ast/commentmap.go \
@@ -1541,25 +1460,6 @@ go_go_token_files = \
go/go/token/serialize.go \
go/go/token/token.go
-go_go_types_files = \
- go/go/types/api.go \
- go/go/types/builtins.go \
- go/go/types/check.go \
- go/go/types/const.go \
- go/go/types/conversions.go \
- go/go/types/errors.go \
- go/go/types/exportdata.go \
- go/go/types/expr.go \
- go/go/types/gcimporter.go \
- go/go/types/objects.go \
- go/go/types/operand.go \
- go/go/types/predicates.go \
- go/go/types/resolve.go \
- go/go/types/scope.go \
- go/go/types/stmt.go \
- go/go/types/types.go \
- go/go/types/universe.go
-
go_hash_adler32_files = \
go/hash/adler32/adler32.go
@@ -1692,6 +1592,10 @@ go_net_http_cgi_files = \
go/net/http/cgi/child.go \
go/net/http/cgi/host.go
+go_net_http_cookiejar_files = \
+ go/net/http/cookiejar/jar.go \
+ go/net/http/cookiejar/punycode.go
+
go_net_http_fcgi_files = \
go/net/http/fcgi/child.go \
go/net/http/fcgi/fcgi.go
@@ -1709,11 +1613,6 @@ go_net_http_httputil_files = \
go/net/http/httputil/persist.go \
go/net/http/httputil/reverseproxy.go
-go_old_netchan_files = \
- go/old/netchan/common.go \
- go/old/netchan/export.go \
- go/old/netchan/import.go
-
go_old_regexp_files = \
go/old/regexp/regexp.go
@@ -1756,6 +1655,7 @@ go_net_rpc_jsonrpc_files = \
go/net/rpc/jsonrpc/server.go
go_runtime_debug_files = \
+ go/runtime/debug/garbage.go \
go/runtime/debug/stack.go
go_runtime_pprof_files = \
@@ -2005,17 +1905,8 @@ libgo_go_objs = \
encoding/json.lo \
encoding/pem.lo \
encoding/xml.lo \
- exp/cookiejar.lo \
- exp/ebnf.lo \
- exp/html.lo \
- exp/html/atom.lo \
- exp/locale/collate.lo \
- exp/locale/collate/build.lo \
- exp/norm.lo \
exp/proxy.lo \
- exp/ssa.lo \
exp/terminal.lo \
- exp/utf8string.lo \
html/template.lo \
go/ast.lo \
go/build.lo \
@@ -2025,12 +1916,12 @@ libgo_go_objs = \
go/printer.lo \
go/scanner.lo \
go/token.lo \
- go/types.lo \
hash/adler32.lo \
hash/crc32.lo \
hash/crc64.lo \
hash/fnv.lo \
net/http/cgi.lo \
+ net/http/cookiejar.lo \
net/http/fcgi.lo \
net/http/httptest.lo \
net/http/httputil.lo \
@@ -2054,7 +1945,6 @@ libgo_go_objs = \
net/smtp.lo \
net/textproto.lo \
net/url.lo \
- old/netchan.lo \
old/regexp.lo \
old/template.lo \
os/exec.lo \
@@ -2185,10 +2075,6 @@ BUILDGOX = \
f=`echo $< | sed -e 's/.lo$$/.o/'`; \
$(OBJCOPY) -j .go_export $$f $@.tmp && mv -f $@.tmp $@
-@LIBGO_IS_LINUX_FALSE@exp_inotify_check =
-
-# exp_inotify_check = exp/inotify/check
-@LIBGO_IS_LINUX_TRUE@exp_inotify_check =
TEST_PACKAGES = \
bufio/check \
bytes/check \
@@ -2259,17 +2145,8 @@ TEST_PACKAGES = \
encoding/json/check \
encoding/pem/check \
encoding/xml/check \
- exp/cookiejar/check \
- exp/ebnf/check \
- exp/html/check \
- exp/html/atom/check \
- $(exp_inotify_check) \
- exp/locale/collate/check \
- exp/locale/collate/build/check \
- exp/norm/check \
exp/proxy/check \
exp/terminal/check \
- exp/utf8string/check \
html/template/check \
go/ast/check \
$(go_build_check_omitted_since_it_calls_6g) \
@@ -2279,7 +2156,6 @@ TEST_PACKAGES = \
go/printer/check \
go/scanner/check \
go/token/check \
- go/types/check \
hash/adler32/check \
hash/crc32/check \
hash/crc64/check \
@@ -2297,6 +2173,7 @@ TEST_PACKAGES = \
mime/multipart/check \
net/http/check \
net/http/cgi/check \
+ net/http/cookiejar/check \
net/http/fcgi/check \
net/http/httptest/check \
net/http/httputil/check \
@@ -2306,7 +2183,6 @@ TEST_PACKAGES = \
net/textproto/check \
net/url/check \
net/rpc/jsonrpc/check \
- old/netchan/check \
old/regexp/check \
old/template/check \
os/exec/check \
@@ -2547,6 +2423,10 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mheap.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mprof.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/msize.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netpoll.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netpoll_epoll.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netpoll_kqueue.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netpoll_stub.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/panic.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parfor.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/print.Plo@am__quote@
@@ -3167,6 +3047,27 @@ msize.lo: runtime/msize.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o msize.lo `test -f 'runtime/msize.c' || echo '$(srcdir)/'`runtime/msize.c
+netpoll_stub.lo: runtime/netpoll_stub.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT netpoll_stub.lo -MD -MP -MF $(DEPDIR)/netpoll_stub.Tpo -c -o netpoll_stub.lo `test -f 'runtime/netpoll_stub.c' || echo '$(srcdir)/'`runtime/netpoll_stub.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/netpoll_stub.Tpo $(DEPDIR)/netpoll_stub.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/netpoll_stub.c' object='netpoll_stub.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o netpoll_stub.lo `test -f 'runtime/netpoll_stub.c' || echo '$(srcdir)/'`runtime/netpoll_stub.c
+
+netpoll_kqueue.lo: runtime/netpoll_kqueue.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT netpoll_kqueue.lo -MD -MP -MF $(DEPDIR)/netpoll_kqueue.Tpo -c -o netpoll_kqueue.lo `test -f 'runtime/netpoll_kqueue.c' || echo '$(srcdir)/'`runtime/netpoll_kqueue.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/netpoll_kqueue.Tpo $(DEPDIR)/netpoll_kqueue.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/netpoll_kqueue.c' object='netpoll_kqueue.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o netpoll_kqueue.lo `test -f 'runtime/netpoll_kqueue.c' || echo '$(srcdir)/'`runtime/netpoll_kqueue.c
+
+netpoll_epoll.lo: runtime/netpoll_epoll.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT netpoll_epoll.lo -MD -MP -MF $(DEPDIR)/netpoll_epoll.Tpo -c -o netpoll_epoll.lo `test -f 'runtime/netpoll_epoll.c' || echo '$(srcdir)/'`runtime/netpoll_epoll.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/netpoll_epoll.Tpo $(DEPDIR)/netpoll_epoll.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/netpoll_epoll.c' object='netpoll_epoll.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o netpoll_epoll.lo `test -f 'runtime/netpoll_epoll.c' || echo '$(srcdir)/'`runtime/netpoll_epoll.c
+
panic.lo: runtime/panic.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT panic.lo -MD -MP -MF $(DEPDIR)/panic.Tpo -c -o panic.lo `test -f 'runtime/panic.c' || echo '$(srcdir)/'`runtime/panic.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/panic.Tpo $(DEPDIR)/panic.Plo
@@ -3510,66 +3411,6 @@ uninstall-toolexeclibgoexpDATA:
test -n "$$files" || exit 0; \
echo " ( cd '$(DESTDIR)$(toolexeclibgoexpdir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(toolexeclibgoexpdir)" && rm -f $$files
-install-toolexeclibgoexphtmlDATA: $(toolexeclibgoexphtml_DATA)
- @$(NORMAL_INSTALL)
- test -z "$(toolexeclibgoexphtmldir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgoexphtmldir)"
- @list='$(toolexeclibgoexphtml_DATA)'; test -n "$(toolexeclibgoexphtmldir)" || list=; \
- for p in $$list; do \
- if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
- echo "$$d$$p"; \
- done | $(am__base_list) | \
- while read files; do \
- echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(toolexeclibgoexphtmldir)'"; \
- $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgoexphtmldir)" || exit $$?; \
- done
-
-uninstall-toolexeclibgoexphtmlDATA:
- @$(NORMAL_UNINSTALL)
- @list='$(toolexeclibgoexphtml_DATA)'; test -n "$(toolexeclibgoexphtmldir)" || list=; \
- files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
- test -n "$$files" || exit 0; \
- echo " ( cd '$(DESTDIR)$(toolexeclibgoexphtmldir)' && rm -f" $$files ")"; \
- cd "$(DESTDIR)$(toolexeclibgoexphtmldir)" && rm -f $$files
-install-toolexeclibgoexplocaleDATA: $(toolexeclibgoexplocale_DATA)
- @$(NORMAL_INSTALL)
- test -z "$(toolexeclibgoexplocaledir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgoexplocaledir)"
- @list='$(toolexeclibgoexplocale_DATA)'; test -n "$(toolexeclibgoexplocaledir)" || list=; \
- for p in $$list; do \
- if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
- echo "$$d$$p"; \
- done | $(am__base_list) | \
- while read files; do \
- echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(toolexeclibgoexplocaledir)'"; \
- $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgoexplocaledir)" || exit $$?; \
- done
-
-uninstall-toolexeclibgoexplocaleDATA:
- @$(NORMAL_UNINSTALL)
- @list='$(toolexeclibgoexplocale_DATA)'; test -n "$(toolexeclibgoexplocaledir)" || list=; \
- files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
- test -n "$$files" || exit 0; \
- echo " ( cd '$(DESTDIR)$(toolexeclibgoexplocaledir)' && rm -f" $$files ")"; \
- cd "$(DESTDIR)$(toolexeclibgoexplocaledir)" && rm -f $$files
-install-toolexeclibgoexplocalecollateDATA: $(toolexeclibgoexplocalecollate_DATA)
- @$(NORMAL_INSTALL)
- test -z "$(toolexeclibgoexplocalecollatedir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgoexplocalecollatedir)"
- @list='$(toolexeclibgoexplocalecollate_DATA)'; test -n "$(toolexeclibgoexplocalecollatedir)" || list=; \
- for p in $$list; do \
- if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
- echo "$$d$$p"; \
- done | $(am__base_list) | \
- while read files; do \
- echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(toolexeclibgoexplocalecollatedir)'"; \
- $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgoexplocalecollatedir)" || exit $$?; \
- done
-
-uninstall-toolexeclibgoexplocalecollateDATA:
- @$(NORMAL_UNINSTALL)
- @list='$(toolexeclibgoexplocalecollate_DATA)'; test -n "$(toolexeclibgoexplocalecollatedir)" || list=; \
- files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
- test -n "$$files" || exit 0; \
- echo " ( cd '$(DESTDIR)$(toolexeclibgoexplocalecollatedir)' && rm -f" $$files ")"; \
- cd "$(DESTDIR)$(toolexeclibgoexplocalecollatedir)" && rm -f $$files
install-toolexeclibgogoDATA: $(toolexeclibgogo_DATA)
@$(NORMAL_INSTALL)
test -z "$(toolexeclibgogodir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgogodir)"
@@ -4151,7 +3992,7 @@ all-am: Makefile $(LIBRARIES) $(LTLIBRARIES) all-multi $(DATA) \
config.h
installdirs: installdirs-recursive
installdirs-am:
- for dir in "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(toolexeclibgodir)" "$(DESTDIR)$(toolexeclibgoarchivedir)" "$(DESTDIR)$(toolexeclibgocompressdir)" "$(DESTDIR)$(toolexeclibgocontainerdir)" "$(DESTDIR)$(toolexeclibgocryptodir)" "$(DESTDIR)$(toolexeclibgocryptox509dir)" "$(DESTDIR)$(toolexeclibgodatabasedir)" "$(DESTDIR)$(toolexeclibgodatabasesqldir)" "$(DESTDIR)$(toolexeclibgodebugdir)" "$(DESTDIR)$(toolexeclibgoencodingdir)" "$(DESTDIR)$(toolexeclibgoexpdir)" "$(DESTDIR)$(toolexeclibgoexphtmldir)" "$(DESTDIR)$(toolexeclibgoexplocaledir)" "$(DESTDIR)$(toolexeclibgoexplocalecollatedir)" "$(DESTDIR)$(toolexeclibgogodir)" "$(DESTDIR)$(toolexeclibgohashdir)" "$(DESTDIR)$(toolexeclibgohtmldir)" "$(DESTDIR)$(toolexeclibgoimagedir)" "$(DESTDIR)$(toolexeclibgoindexdir)" "$(DESTDIR)$(toolexeclibgoiodir)" "$(DESTDIR)$(toolexeclibgologdir)" "$(DESTDIR)$(toolexeclibgomathdir)" "$(DESTDIR)$(toolexeclibgomimedir)" "$(DESTDIR)$(toolexeclibgonetdir)" "$(DESTDIR)$(toolexeclibgonethttpdir)" "$(DESTDIR)$(toolexeclibgonetrpcdir)" "$(DESTDIR)$(toolexeclibgoolddir)" "$(DESTDIR)$(toolexeclibgoosdir)" "$(DESTDIR)$(toolexeclibgopathdir)" "$(DESTDIR)$(toolexeclibgoregexpdir)" "$(DESTDIR)$(toolexeclibgoruntimedir)" "$(DESTDIR)$(toolexeclibgosyncdir)" "$(DESTDIR)$(toolexeclibgotestingdir)" "$(DESTDIR)$(toolexeclibgotextdir)" "$(DESTDIR)$(toolexeclibgotexttemplatedir)" "$(DESTDIR)$(toolexeclibgounicodedir)"; do \
+ for dir in "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(toolexeclibgodir)" "$(DESTDIR)$(toolexeclibgoarchivedir)" "$(DESTDIR)$(toolexeclibgocompressdir)" "$(DESTDIR)$(toolexeclibgocontainerdir)" "$(DESTDIR)$(toolexeclibgocryptodir)" "$(DESTDIR)$(toolexeclibgocryptox509dir)" "$(DESTDIR)$(toolexeclibgodatabasedir)" "$(DESTDIR)$(toolexeclibgodatabasesqldir)" "$(DESTDIR)$(toolexeclibgodebugdir)" "$(DESTDIR)$(toolexeclibgoencodingdir)" "$(DESTDIR)$(toolexeclibgoexpdir)" "$(DESTDIR)$(toolexeclibgogodir)" "$(DESTDIR)$(toolexeclibgohashdir)" "$(DESTDIR)$(toolexeclibgohtmldir)" "$(DESTDIR)$(toolexeclibgoimagedir)" "$(DESTDIR)$(toolexeclibgoindexdir)" "$(DESTDIR)$(toolexeclibgoiodir)" "$(DESTDIR)$(toolexeclibgologdir)" "$(DESTDIR)$(toolexeclibgomathdir)" "$(DESTDIR)$(toolexeclibgomimedir)" "$(DESTDIR)$(toolexeclibgonetdir)" "$(DESTDIR)$(toolexeclibgonethttpdir)" "$(DESTDIR)$(toolexeclibgonetrpcdir)" "$(DESTDIR)$(toolexeclibgoolddir)" "$(DESTDIR)$(toolexeclibgoosdir)" "$(DESTDIR)$(toolexeclibgopathdir)" "$(DESTDIR)$(toolexeclibgoregexpdir)" "$(DESTDIR)$(toolexeclibgoruntimedir)" "$(DESTDIR)$(toolexeclibgosyncdir)" "$(DESTDIR)$(toolexeclibgotestingdir)" "$(DESTDIR)$(toolexeclibgotextdir)" "$(DESTDIR)$(toolexeclibgotexttemplatedir)" "$(DESTDIR)$(toolexeclibgounicodedir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-recursive
@@ -4222,9 +4063,6 @@ install-exec-am: install-multi install-toolexeclibLIBRARIES \
install-toolexeclibgodatabasesqlDATA \
install-toolexeclibgodebugDATA \
install-toolexeclibgoencodingDATA install-toolexeclibgoexpDATA \
- install-toolexeclibgoexphtmlDATA \
- install-toolexeclibgoexplocaleDATA \
- install-toolexeclibgoexplocalecollateDATA \
install-toolexeclibgogoDATA install-toolexeclibgohashDATA \
install-toolexeclibgohtmlDATA install-toolexeclibgoimageDATA \
install-toolexeclibgoindexDATA install-toolexeclibgoioDATA \
@@ -4290,11 +4128,8 @@ uninstall-am: uninstall-toolexeclibLIBRARIES \
uninstall-toolexeclibgodatabasesqlDATA \
uninstall-toolexeclibgodebugDATA \
uninstall-toolexeclibgoencodingDATA \
- uninstall-toolexeclibgoexpDATA \
- uninstall-toolexeclibgoexphtmlDATA \
- uninstall-toolexeclibgoexplocaleDATA \
- uninstall-toolexeclibgoexplocalecollateDATA \
- uninstall-toolexeclibgogoDATA uninstall-toolexeclibgohashDATA \
+ uninstall-toolexeclibgoexpDATA uninstall-toolexeclibgogoDATA \
+ uninstall-toolexeclibgohashDATA \
uninstall-toolexeclibgohtmlDATA \
uninstall-toolexeclibgoimageDATA \
uninstall-toolexeclibgoindexDATA uninstall-toolexeclibgoioDATA \
@@ -4339,9 +4174,6 @@ uninstall-am: uninstall-toolexeclibLIBRARIES \
install-toolexeclibgodatabasesqlDATA \
install-toolexeclibgodebugDATA \
install-toolexeclibgoencodingDATA install-toolexeclibgoexpDATA \
- install-toolexeclibgoexphtmlDATA \
- install-toolexeclibgoexplocaleDATA \
- install-toolexeclibgoexplocalecollateDATA \
install-toolexeclibgogoDATA install-toolexeclibgohashDATA \
install-toolexeclibgohtmlDATA install-toolexeclibgoimageDATA \
install-toolexeclibgoindexDATA install-toolexeclibgoioDATA \
@@ -4371,11 +4203,8 @@ uninstall-am: uninstall-toolexeclibLIBRARIES \
uninstall-toolexeclibgodatabasesqlDATA \
uninstall-toolexeclibgodebugDATA \
uninstall-toolexeclibgoencodingDATA \
- uninstall-toolexeclibgoexpDATA \
- uninstall-toolexeclibgoexphtmlDATA \
- uninstall-toolexeclibgoexplocaleDATA \
- uninstall-toolexeclibgoexplocalecollateDATA \
- uninstall-toolexeclibgogoDATA uninstall-toolexeclibgohashDATA \
+ uninstall-toolexeclibgoexpDATA uninstall-toolexeclibgogoDATA \
+ uninstall-toolexeclibgohashDATA \
uninstall-toolexeclibgohtmlDATA \
uninstall-toolexeclibgoimageDATA \
uninstall-toolexeclibgoindexDATA uninstall-toolexeclibgoioDATA \
@@ -4408,6 +4237,10 @@ mprof.c: $(srcdir)/runtime/mprof.goc goc2c
./goc2c $< > $@.tmp
mv -f $@.tmp $@
+netpoll.c: $(srcdir)/runtime/netpoll.goc goc2c
+ ./goc2c $< > $@.tmp
+ mv -f $@.tmp $@
+
reflect.c: $(srcdir)/runtime/reflect.goc goc2c
./goc2c $< > $@.tmp
mv -f $@.tmp $@
@@ -5163,69 +4996,6 @@ encoding/xml/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: encoding/xml/check
-@go_include@ exp/cookiejar.lo.dep
-exp/cookiejar.lo.dep: $(go_exp_cookiejar_files)
- $(BUILDDEPS)
-exp/cookiejar.lo: $(go_exp_cookiejar_files)
- $(BUILDPACKAGE)
-exp/cookiejar/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: exp/cookiejar/check
-
-@go_include@ exp/ebnf.lo.dep
-exp/ebnf.lo.dep: $(go_exp_ebnf_files)
- $(BUILDDEPS)
-exp/ebnf.lo: $(go_exp_ebnf_files)
- $(BUILDPACKAGE)
-exp/ebnf/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: exp/ebnf/check
-
-@go_include@ exp/html.lo.dep
-exp/html.lo.dep: $(go_exp_html_files)
- $(BUILDDEPS)
-exp/html.lo: $(go_exp_html_files)
- $(BUILDPACKAGE)
-exp/html/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: exp/html/check
-
-@go_include@ exp/html/atom.lo.dep
-exp/html/atom.lo.dep: $(go_exp_html_atom_files)
- $(BUILDDEPS)
-exp/html/atom.lo: $(go_exp_html_atom_files)
- $(BUILDPACKAGE)
-exp/html/atom/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: exp/html/atom/check
-
-@go_include@ exp/locale/collate.lo.dep
-exp/locale/collate.lo.dep: $(go_exp_locale_collate_files)
- $(BUILDDEPS)
-exp/locale/collate.lo: $(go_exp_locale_collate_files)
- $(BUILDPACKAGE)
-exp/locale/collate/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: exp/locale/collate/check
-
-@go_include@ exp/locale/collate/build.lo.dep
-exp/locale/collate/build.lo.dep: $(go_exp_locale_collate_build_files)
- $(BUILDDEPS)
-exp/locale/collate/build.lo: $(go_exp_locale_collate_build_files)
- $(BUILDPACKAGE)
-exp/locale/collate/build/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: exp/locale/collate/build/check
-
-@go_include@ exp/norm.lo.dep
-exp/norm.lo.dep: $(go_exp_norm_files)
- $(BUILDDEPS)
-exp/norm.lo: $(go_exp_norm_files)
- $(BUILDPACKAGE)
-exp/norm/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: exp/norm/check
-
@go_include@ exp/proxy.lo.dep
exp/proxy.lo.dep: $(go_exp_proxy_files)
$(BUILDDEPS)
@@ -5235,15 +5005,6 @@ exp/proxy/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: exp/proxy/check
-@go_include@ exp/ssa.lo.dep
-exp/ssa.lo.dep: $(go_exp_ssa_files)
- $(BUILDDEPS)
-exp/ssa.lo: $(go_exp_ssa_files)
- $(BUILDPACKAGE)
-exp/ssa/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: exp/ssa/check
-
@go_include@ exp/terminal.lo.dep
exp/terminal.lo.dep: $(go_exp_terminal_files)
$(BUILDDEPS)
@@ -5253,24 +5014,6 @@ exp/terminal/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: exp/terminal/check
-@go_include@ exp/utf8string.lo.dep
-exp/utf8string.lo.dep: $(go_exp_utf8string_files)
- $(BUILDDEPS)
-exp/utf8string.lo: $(go_exp_utf8string_files)
- $(BUILDPACKAGE)
-exp/utf8string/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: exp/utf8string/check
-
-@go_include@ exp/inotify.lo.dep
-exp/inotify.lo.dep: $(go_exp_inotify_files)
- $(BUILDDEPS)
-exp/inotify.lo: $(go_exp_inotify_files)
- $(BUILDPACKAGE)
-exp/inotify/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: exp/inotify/check
-
@go_include@ html/template.lo.dep
html/template.lo.dep: $(go_html_template_files)
$(BUILDDEPS)
@@ -5361,15 +5104,6 @@ go/token/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: go/token/check
-@go_include@ go/types.lo.dep
-go/types.lo.dep: $(go_go_types_files)
- $(BUILDDEPS)
-go/types.lo: $(go_go_types_files)
- $(BUILDPACKAGE)
-go/types/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: go/types/check
-
@go_include@ hash/adler32.lo.dep
hash/adler32.lo.dep: $(go_hash_adler32_files)
$(BUILDDEPS)
@@ -5580,6 +5314,15 @@ net/http/cgi/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: net/http/cgi/check
+@go_include@ net/http/cookiejar.lo.dep
+net/http/cookiejar.lo.dep: $(go_net_http_cookiejar_files)
+ $(BUILDDEPS)
+net/http/cookiejar.lo: $(go_net_http_cookiejar_files)
+ $(BUILDPACKAGE)
+net/http/cookiejar/check: $(CHECK_DEPS)
+ @$(CHECK)
+.PHONY: net/http/cookiejar/check
+
@go_include@ net/http/fcgi.lo.dep
net/http/fcgi.lo.dep: $(go_net_http_fcgi_files)
$(BUILDDEPS)
@@ -5625,15 +5368,6 @@ net/rpc/jsonrpc/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: net/rpc/jsonrpc/check
-@go_include@ old/netchan.lo.dep
-old/netchan.lo.dep: $(go_old_netchan_files)
- $(BUILDDEPS)
-old/netchan.lo: $(go_old_netchan_files)
- $(BUILDPACKAGE)
-old/netchan/check: $(CHECK_DEPS)
- @$(CHECK)
-.PHONY: old/netchan/check
-
@go_include@ old/regexp.lo.dep
old/regexp.lo.dep: $(go_old_regexp_files)
$(BUILDDEPS)
@@ -5974,30 +5708,10 @@ encoding/pem.gox: encoding/pem.lo
encoding/xml.gox: encoding/xml.lo
$(BUILDGOX)
-exp/cookiejar.gox: exp/cookiejar.lo
- $(BUILDGOX)
-exp/ebnf.gox: exp/ebnf.lo
- $(BUILDGOX)
-exp/html.gox: exp/html.lo
- $(BUILDGOX)
-exp/html/atom.gox: exp/html/atom.lo
- $(BUILDGOX)
-exp/inotify.gox: exp/inotify.lo
- $(BUILDGOX)
-exp/locale/collate.gox: exp/locale/collate.lo
- $(BUILDGOX)
-exp/locale/collate/build.gox: exp/locale/collate/build.lo
- $(BUILDGOX)
-exp/norm.gox: exp/norm.lo
- $(BUILDGOX)
exp/proxy.gox: exp/proxy.lo
$(BUILDGOX)
-exp/ssa.gox: exp/ssa.lo
- $(BUILDGOX)
exp/terminal.gox: exp/terminal.lo
$(BUILDGOX)
-exp/utf8string.gox: exp/utf8string.lo
- $(BUILDGOX)
html/template.gox: html/template.lo
$(BUILDGOX)
@@ -6018,8 +5732,6 @@ go/scanner.gox: go/scanner.lo
$(BUILDGOX)
go/token.gox: go/token.lo
$(BUILDGOX)
-go/types.gox: go/types.lo
- $(BUILDGOX)
hash/adler32.gox: hash/adler32.lo
$(BUILDGOX)
@@ -6075,6 +5787,8 @@ net/url.gox: net/url.lo
net/http/cgi.gox: net/http/cgi.lo
$(BUILDGOX)
+net/http/cookiejar.gox: net/http/cookiejar.lo
+ $(BUILDGOX)
net/http/fcgi.gox: net/http/fcgi.lo
$(BUILDGOX)
net/http/httptest.gox: net/http/httptest.lo
@@ -6087,8 +5801,6 @@ net/http/pprof.gox: net/http/pprof.lo
net/rpc/jsonrpc.gox: net/rpc/jsonrpc.lo
$(BUILDGOX)
-old/netchan.gox: old/netchan.lo
- $(BUILDGOX)
old/regexp.gox: old/regexp.lo
$(BUILDGOX)
old/template.gox: old/template.lo
diff --git a/libgo/go/archive/tar/common.go b/libgo/go/archive/tar/common.go
index 921b9fe9bdd..60d207c4897 100644
--- a/libgo/go/archive/tar/common.go
+++ b/libgo/go/archive/tar/common.go
@@ -9,12 +9,14 @@
// References:
// http://www.freebsd.org/cgi/man.cgi?query=tar&sektion=5
// http://www.gnu.org/software/tar/manual/html_node/Standard.html
+// http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html
package tar
import (
"errors"
"fmt"
"os"
+ "path"
"time"
)
@@ -33,6 +35,8 @@ const (
TypeCont = '7' // reserved
TypeXHeader = 'x' // extended header
TypeXGlobalHeader = 'g' // global extended header
+ TypeGNULongName = 'L' // Next file has a long name
+ TypeGNULongLink = 'K' // Next file symlinks to a file w/ a long name
)
// A Header represents a single header in a tar archive.
@@ -54,55 +58,172 @@ type Header struct {
ChangeTime time.Time // status change time
}
+// File name constants from the tar spec.
+const (
+ fileNameSize = 100 // Maximum number of bytes in a standard tar name.
+ fileNamePrefixSize = 155 // Maximum number of ustar extension bytes.
+)
+
+// FileInfo returns an os.FileInfo for the Header.
+func (h *Header) FileInfo() os.FileInfo {
+ return headerFileInfo{h}
+}
+
+// headerFileInfo implements os.FileInfo.
+type headerFileInfo struct {
+ h *Header
+}
+
+func (fi headerFileInfo) Size() int64 { return fi.h.Size }
+func (fi headerFileInfo) IsDir() bool { return fi.Mode().IsDir() }
+func (fi headerFileInfo) ModTime() time.Time { return fi.h.ModTime }
+func (fi headerFileInfo) Sys() interface{} { return fi.h }
+
+// Name returns the base name of the file.
+func (fi headerFileInfo) Name() string {
+ if fi.IsDir() {
+ return path.Clean(fi.h.Name)
+ }
+ return fi.h.Name
+}
+
+// Mode returns the permission and mode bits for the headerFileInfo.
+func (fi headerFileInfo) Mode() (mode os.FileMode) {
+ // Set file permission bits.
+ mode = os.FileMode(fi.h.Mode).Perm()
+
+ // Set setuid, setgid and sticky bits.
+ if fi.h.Mode&c_ISUID != 0 {
+ // setuid
+ mode |= os.ModeSetuid
+ }
+ if fi.h.Mode&c_ISGID != 0 {
+ // setgid
+ mode |= os.ModeSetgid
+ }
+ if fi.h.Mode&c_ISVTX != 0 {
+ // sticky
+ mode |= os.ModeSticky
+ }
+
+ // Set file mode bits.
+ // clear perm, setuid, setgid and sticky bits.
+ m := os.FileMode(fi.h.Mode) &^ 07777
+ if m == c_ISDIR {
+ // directory
+ mode |= os.ModeDir
+ }
+ if m == c_ISFIFO {
+ // named pipe (FIFO)
+ mode |= os.ModeNamedPipe
+ }
+ if m == c_ISLNK {
+ // symbolic link
+ mode |= os.ModeSymlink
+ }
+ if m == c_ISBLK {
+ // device file
+ mode |= os.ModeDevice
+ }
+ if m == c_ISCHR {
+ // Unix character device
+ mode |= os.ModeDevice
+ mode |= os.ModeCharDevice
+ }
+ if m == c_ISSOCK {
+ // Unix domain socket
+ mode |= os.ModeSocket
+ }
+
+ switch fi.h.Typeflag {
+ case TypeLink, TypeSymlink:
+ // hard link, symbolic link
+ mode |= os.ModeSymlink
+ case TypeChar:
+ // character device node
+ mode |= os.ModeDevice
+ mode |= os.ModeCharDevice
+ case TypeBlock:
+ // block device node
+ mode |= os.ModeDevice
+ case TypeDir:
+ // directory
+ mode |= os.ModeDir
+ case TypeFifo:
+ // fifo node
+ mode |= os.ModeNamedPipe
+ }
+
+ return mode
+}
+
// sysStat, if non-nil, populates h from system-dependent fields of fi.
var sysStat func(fi os.FileInfo, h *Header) error
// Mode constants from the tar spec.
const (
- c_ISDIR = 040000
- c_ISFIFO = 010000
- c_ISREG = 0100000
- c_ISLNK = 0120000
- c_ISBLK = 060000
- c_ISCHR = 020000
- c_ISSOCK = 0140000
+ c_ISUID = 04000 // Set uid
+ c_ISGID = 02000 // Set gid
+ c_ISVTX = 01000 // Save text (sticky bit)
+ c_ISDIR = 040000 // Directory
+ c_ISFIFO = 010000 // FIFO
+ c_ISREG = 0100000 // Regular file
+ c_ISLNK = 0120000 // Symbolic link
+ c_ISBLK = 060000 // Block special file
+ c_ISCHR = 020000 // Character special file
+ c_ISSOCK = 0140000 // Socket
)
// FileInfoHeader creates a partially-populated Header from fi.
// If fi describes a symlink, FileInfoHeader records link as the link target.
+// If fi describes a directory, a slash is appended to the name.
func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) {
if fi == nil {
return nil, errors.New("tar: FileInfo is nil")
}
+ fm := fi.Mode()
h := &Header{
Name: fi.Name(),
ModTime: fi.ModTime(),
- Mode: int64(fi.Mode().Perm()), // or'd with c_IS* constants later
+ Mode: int64(fm.Perm()), // or'd with c_IS* constants later
}
switch {
- case fi.Mode()&os.ModeType == 0:
+ case fm.IsRegular():
h.Mode |= c_ISREG
h.Typeflag = TypeReg
h.Size = fi.Size()
case fi.IsDir():
h.Typeflag = TypeDir
h.Mode |= c_ISDIR
- case fi.Mode()&os.ModeSymlink != 0:
+ h.Name += "/"
+ case fm&os.ModeSymlink != 0:
h.Typeflag = TypeSymlink
h.Mode |= c_ISLNK
h.Linkname = link
- case fi.Mode()&os.ModeDevice != 0:
- if fi.Mode()&os.ModeCharDevice != 0 {
+ case fm&os.ModeDevice != 0:
+ if fm&os.ModeCharDevice != 0 {
h.Mode |= c_ISCHR
h.Typeflag = TypeChar
} else {
h.Mode |= c_ISBLK
h.Typeflag = TypeBlock
}
- case fi.Mode()&os.ModeSocket != 0:
+ case fm&os.ModeNamedPipe != 0:
+ h.Typeflag = TypeFifo
+ h.Mode |= c_ISFIFO
+ case fm&os.ModeSocket != 0:
h.Mode |= c_ISSOCK
default:
- return nil, fmt.Errorf("archive/tar: unknown file mode %v", fi.Mode())
+ return nil, fmt.Errorf("archive/tar: unknown file mode %v", fm)
+ }
+ if fm&os.ModeSetuid != 0 {
+ h.Mode |= c_ISUID
+ }
+ if fm&os.ModeSetgid != 0 {
+ h.Mode |= c_ISGID
+ }
+ if fm&os.ModeSticky != 0 {
+ h.Mode |= c_ISVTX
}
if sysStat != nil {
return h, sysStat(fi, h)
diff --git a/libgo/go/archive/tar/reader.go b/libgo/go/archive/tar/reader.go
index ad825c6be0b..05f82a40dd9 100644
--- a/libgo/go/archive/tar/reader.go
+++ b/libgo/go/archive/tar/reader.go
@@ -14,6 +14,7 @@ import (
"io/ioutil"
"os"
"strconv"
+ "strings"
"time"
)
@@ -21,24 +22,12 @@ var (
ErrHeader = errors.New("archive/tar: invalid tar header")
)
+const maxNanoSecondIntSize = 9
+
// A Reader provides sequential access to the contents of a tar archive.
// A tar archive consists of a sequence of files.
// The Next method advances to the next file in the archive (including the first),
// and then it can be treated as an io.Reader to access the file's data.
-//
-// Example:
-// tr := tar.NewReader(r)
-// for {
-// hdr, err := tr.Next()
-// if err == io.EOF {
-// // end of tar archive
-// break
-// }
-// if err != nil {
-// // handle error
-// }
-// io.Copy(data, tr)
-// }
type Reader struct {
r io.Reader
err error
@@ -55,13 +44,183 @@ func (tr *Reader) Next() (*Header, error) {
if tr.err == nil {
tr.skipUnread()
}
- if tr.err == nil {
+ if tr.err != nil {
+ return hdr, tr.err
+ }
+ hdr = tr.readHeader()
+ if hdr == nil {
+ return hdr, tr.err
+ }
+ // Check for PAX/GNU header.
+ switch hdr.Typeflag {
+ case TypeXHeader:
+ // PAX extended header
+ headers, err := parsePAX(tr)
+ if err != nil {
+ return nil, err
+ }
+ // We actually read the whole file,
+ // but this skips alignment padding
+ tr.skipUnread()
hdr = tr.readHeader()
+ mergePAX(hdr, headers)
+ return hdr, nil
+ case TypeGNULongName:
+ // We have a GNU long name header. Its contents are the real file name.
+ realname, err := ioutil.ReadAll(tr)
+ if err != nil {
+ return nil, err
+ }
+ hdr, err := tr.Next()
+ hdr.Name = cString(realname)
+ return hdr, err
+ case TypeGNULongLink:
+ // We have a GNU long link header.
+ realname, err := ioutil.ReadAll(tr)
+ if err != nil {
+ return nil, err
+ }
+ hdr, err := tr.Next()
+ hdr.Linkname = cString(realname)
+ return hdr, err
}
return hdr, tr.err
}
-// Parse bytes as a NUL-terminated C-style string.
+// mergePAX merges well known headers according to PAX standard.
+// In general headers with the same name as those found
+// in the header struct overwrite those found in the header
+// struct with higher precision or longer values. Esp. useful
+// for name and linkname fields.
+func mergePAX(hdr *Header, headers map[string]string) error {
+ for k, v := range headers {
+ switch k {
+ case "path":
+ hdr.Name = v
+ case "linkpath":
+ hdr.Linkname = v
+ case "gname":
+ hdr.Gname = v
+ case "uname":
+ hdr.Uname = v
+ case "uid":
+ uid, err := strconv.ParseInt(v, 10, 0)
+ if err != nil {
+ return err
+ }
+ hdr.Uid = int(uid)
+ case "gid":
+ gid, err := strconv.ParseInt(v, 10, 0)
+ if err != nil {
+ return err
+ }
+ hdr.Gid = int(gid)
+ case "atime":
+ t, err := parsePAXTime(v)
+ if err != nil {
+ return err
+ }
+ hdr.AccessTime = t
+ case "mtime":
+ t, err := parsePAXTime(v)
+ if err != nil {
+ return err
+ }
+ hdr.ModTime = t
+ case "ctime":
+ t, err := parsePAXTime(v)
+ if err != nil {
+ return err
+ }
+ hdr.ChangeTime = t
+ case "size":
+ size, err := strconv.ParseInt(v, 10, 0)
+ if err != nil {
+ return err
+ }
+ hdr.Size = int64(size)
+ }
+
+ }
+ return nil
+}
+
+// parsePAXTime takes a string of the form %d.%d as described in
+// the PAX specification.
+func parsePAXTime(t string) (time.Time, error) {
+ buf := []byte(t)
+ pos := bytes.IndexByte(buf, '.')
+ var seconds, nanoseconds int64
+ var err error
+ if pos == -1 {
+ seconds, err = strconv.ParseInt(t, 10, 0)
+ if err != nil {
+ return time.Time{}, err
+ }
+ } else {
+ seconds, err = strconv.ParseInt(string(buf[:pos]), 10, 0)
+ if err != nil {
+ return time.Time{}, err
+ }
+ nano_buf := string(buf[pos+1:])
+ // Pad as needed before converting to a decimal.
+ // For example .030 -> .030000000 -> 30000000 nanoseconds
+ if len(nano_buf) < maxNanoSecondIntSize {
+ // Right pad
+ nano_buf += strings.Repeat("0", maxNanoSecondIntSize-len(nano_buf))
+ } else if len(nano_buf) > maxNanoSecondIntSize {
+ // Right truncate
+ nano_buf = nano_buf[:maxNanoSecondIntSize]
+ }
+ nanoseconds, err = strconv.ParseInt(string(nano_buf), 10, 0)
+ if err != nil {
+ return time.Time{}, err
+ }
+ }
+ ts := time.Unix(seconds, nanoseconds)
+ return ts, nil
+}
+
+// parsePAX parses PAX headers.
+// If an extended header (type 'x') is invalid, ErrHeader is returned
+func parsePAX(r io.Reader) (map[string]string, error) {
+ buf, err := ioutil.ReadAll(r)
+ if err != nil {
+ return nil, err
+ }
+ headers := make(map[string]string)
+ // Each record is constructed as
+ // "%d %s=%s\n", length, keyword, value
+ for len(buf) > 0 {
+ // or the header was empty to start with.
+ var sp int
+ // The size field ends at the first space.
+ sp = bytes.IndexByte(buf, ' ')
+ if sp == -1 {
+ return nil, ErrHeader
+ }
+ // Parse the first token as a decimal integer.
+ n, err := strconv.ParseInt(string(buf[:sp]), 10, 0)
+ if err != nil {
+ return nil, ErrHeader
+ }
+ // Extract everything between the decimal and the n -1 on the
+ // beginning to to eat the ' ', -1 on the end to skip the newline.
+ var record []byte
+ record, buf = buf[sp+1:n-1], buf[n:]
+ // The first equals is guaranteed to mark the end of the key.
+ // Everything else is value.
+ eq := bytes.IndexByte(record, '=')
+ if eq == -1 {
+ return nil, ErrHeader
+ }
+ key, value := record[:eq], record[eq+1:]
+ headers[string(key)] = string(value)
+ }
+ return headers, nil
+}
+
+// cString parses 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
@@ -99,7 +258,7 @@ func (tr *Reader) octal(b []byte) int64 {
return int64(x)
}
-// Skip any unread bytes in the existing file entry, as well as any alignment padding.
+// skipUnread skips any unread bytes in the existing file entry, as well as any alignment padding.
func (tr *Reader) skipUnread() {
nr := tr.nb + tr.pad // number of bytes to skip
tr.nb, tr.pad = 0, 0
diff --git a/libgo/go/archive/tar/reader_test.go b/libgo/go/archive/tar/reader_test.go
index 0a8646c393f..9a196823713 100644
--- a/libgo/go/archive/tar/reader_test.go
+++ b/libgo/go/archive/tar/reader_test.go
@@ -10,6 +10,8 @@ import (
"fmt"
"io"
"os"
+ "reflect"
+ "strings"
"testing"
"time"
)
@@ -108,6 +110,38 @@ var untarTests = []*untarTest{
},
},
},
+ {
+ file: "testdata/pax.tar",
+ headers: []*Header{
+ {
+ Name: "a/123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100",
+ Mode: 0664,
+ Uid: 1000,
+ Gid: 1000,
+ Uname: "shane",
+ Gname: "shane",
+ Size: 7,
+ ModTime: time.Unix(1350244992, 23960108),
+ ChangeTime: time.Unix(1350244992, 23960108),
+ AccessTime: time.Unix(1350244992, 23960108),
+ Typeflag: TypeReg,
+ },
+ {
+ Name: "a/b",
+ Mode: 0777,
+ Uid: 1000,
+ Gid: 1000,
+ Uname: "shane",
+ Gname: "shane",
+ Size: 0,
+ ModTime: time.Unix(1350266320, 910238425),
+ ChangeTime: time.Unix(1350266320, 910238425),
+ AccessTime: time.Unix(1350266320, 910238425),
+ Typeflag: TypeSymlink,
+ Linkname: "123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100",
+ },
+ },
+ },
}
func TestReader(t *testing.T) {
@@ -133,7 +167,7 @@ testLoop:
}
hdr, err := tr.Next()
if err == io.EOF {
- break
+ continue testLoop
}
if hdr != nil || err != nil {
t.Errorf("test %d: Unexpected entry or error: hdr=%v err=%v", i, hdr, err)
@@ -260,3 +294,73 @@ func TestNonSeekable(t *testing.T) {
t.Errorf("Didn't process all files\nexpected: %d\nprocessed %d\n", len(test.headers), nread)
}
}
+
+func TestParsePAXHeader(t *testing.T) {
+ paxTests := [][3]string{
+ {"a", "a=name", "10 a=name\n"}, // Test case involving multiple acceptable lengths
+ {"a", "a=name", "9 a=name\n"}, // Test case involving multiple acceptable length
+ {"mtime", "mtime=1350244992.023960108", "30 mtime=1350244992.023960108\n"}}
+ for _, test := range paxTests {
+ key, expected, raw := test[0], test[1], test[2]
+ reader := bytes.NewBuffer([]byte(raw))
+ headers, err := parsePAX(reader)
+ if err != nil {
+ t.Errorf("Couldn't parse correctly formatted headers: %v", err)
+ continue
+ }
+ if strings.EqualFold(headers[key], expected) {
+ t.Errorf("mtime header incorrectly parsed: got %s, wanted %s", headers[key], expected)
+ continue
+ }
+ trailer := make([]byte, 100)
+ n, err := reader.Read(trailer)
+ if err != io.EOF || n != 0 {
+ t.Error("Buffer wasn't consumed")
+ }
+ }
+ badHeader := bytes.NewBuffer([]byte("3 somelongkey="))
+ if _, err := parsePAX(badHeader); err != ErrHeader {
+ t.Fatal("Unexpected success when parsing bad header")
+ }
+}
+
+func TestParsePAXTime(t *testing.T) {
+ // Some valid PAX time values
+ timestamps := map[string]time.Time{
+ "1350244992.023960108": time.Unix(1350244992, 23960108), // The commoon case
+ "1350244992.02396010": time.Unix(1350244992, 23960100), // Lower precision value
+ "1350244992.0239601089": time.Unix(1350244992, 23960108), // Higher precision value
+ "1350244992": time.Unix(1350244992, 0), // Low precision value
+ }
+ for input, expected := range timestamps {
+ ts, err := parsePAXTime(input)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !ts.Equal(expected) {
+ t.Fatalf("Time parsing failure %s %s", ts, expected)
+ }
+ }
+}
+
+func TestMergePAX(t *testing.T) {
+ hdr := new(Header)
+ // Test a string, integer, and time based value.
+ headers := map[string]string{
+ "path": "a/b/c",
+ "uid": "1000",
+ "mtime": "1350244992.023960108",
+ }
+ err := mergePAX(hdr, headers)
+ if err != nil {
+ t.Fatal(err)
+ }
+ want := &Header{
+ Name: "a/b/c",
+ Uid: 1000,
+ ModTime: time.Unix(1350244992, 23960108),
+ }
+ if !reflect.DeepEqual(hdr, want) {
+ t.Errorf("incorrect merge: got %+v, want %+v", hdr, want)
+ }
+}
diff --git a/libgo/go/archive/tar/tar_test.go b/libgo/go/archive/tar/tar_test.go
index 7b190b6a8b2..dd6310313af 100644
--- a/libgo/go/archive/tar/tar_test.go
+++ b/libgo/go/archive/tar/tar_test.go
@@ -14,13 +14,13 @@ import (
)
func TestFileInfoHeader(t *testing.T) {
- fi, err := os.Lstat("testdata/small.txt")
+ fi, err := os.Stat("testdata/small.txt")
if err != nil {
t.Fatal(err)
}
h, err := FileInfoHeader(fi, "")
if err != nil {
- t.Fatalf("on small.txt: %v", err)
+ t.Fatalf("FileInfoHeader: %v", err)
}
if g, e := h.Name, "small.txt"; g != e {
t.Errorf("Name = %q; want %q", g, e)
@@ -36,6 +36,30 @@ func TestFileInfoHeader(t *testing.T) {
}
}
+func TestFileInfoHeaderDir(t *testing.T) {
+ fi, err := os.Stat("testdata")
+ if err != nil {
+ t.Fatal(err)
+ }
+ h, err := FileInfoHeader(fi, "")
+ if err != nil {
+ t.Fatalf("FileInfoHeader: %v", err)
+ }
+ if g, e := h.Name, "testdata/"; g != e {
+ t.Errorf("Name = %q; want %q", g, e)
+ }
+ // Ignoring c_ISGID for golang.org/issue/4867
+ if g, e := h.Mode&^c_ISGID, int64(fi.Mode().Perm())|c_ISDIR; g != e {
+ t.Errorf("Mode = %#o; want %#o", g, e)
+ }
+ if g, e := h.Size, int64(0); g != e {
+ t.Errorf("Size = %v; want %v", g, e)
+ }
+ if g, e := h.ModTime, fi.ModTime(); !g.Equal(e) {
+ t.Errorf("ModTime = %v; want %v", g, e)
+ }
+}
+
func TestFileInfoHeaderSymlink(t *testing.T) {
h, err := FileInfoHeader(symlink{}, "some-target")
if err != nil {
@@ -98,3 +122,150 @@ func TestRoundTrip(t *testing.T) {
t.Errorf("Data mismatch.\n got %q\nwant %q", rData, data)
}
}
+
+type headerRoundTripTest struct {
+ h *Header
+ fm os.FileMode
+}
+
+func TestHeaderRoundTrip(t *testing.T) {
+ golden := []headerRoundTripTest{
+ // regular file.
+ {
+ h: &Header{
+ Name: "test.txt",
+ Mode: 0644 | c_ISREG,
+ Size: 12,
+ ModTime: time.Unix(1360600916, 0),
+ Typeflag: TypeReg,
+ },
+ fm: 0644,
+ },
+ // hard link.
+ {
+ h: &Header{
+ Name: "hard.txt",
+ Mode: 0644 | c_ISLNK,
+ Size: 0,
+ ModTime: time.Unix(1360600916, 0),
+ Typeflag: TypeLink,
+ },
+ fm: 0644 | os.ModeSymlink,
+ },
+ // symbolic link.
+ {
+ h: &Header{
+ Name: "link.txt",
+ Mode: 0777 | c_ISLNK,
+ Size: 0,
+ ModTime: time.Unix(1360600852, 0),
+ Typeflag: TypeSymlink,
+ },
+ fm: 0777 | os.ModeSymlink,
+ },
+ // character device node.
+ {
+ h: &Header{
+ Name: "dev/null",
+ Mode: 0666 | c_ISCHR,
+ Size: 0,
+ ModTime: time.Unix(1360578951, 0),
+ Typeflag: TypeChar,
+ },
+ fm: 0666 | os.ModeDevice | os.ModeCharDevice,
+ },
+ // block device node.
+ {
+ h: &Header{
+ Name: "dev/sda",
+ Mode: 0660 | c_ISBLK,
+ Size: 0,
+ ModTime: time.Unix(1360578954, 0),
+ Typeflag: TypeBlock,
+ },
+ fm: 0660 | os.ModeDevice,
+ },
+ // directory.
+ {
+ h: &Header{
+ Name: "dir/",
+ Mode: 0755 | c_ISDIR,
+ Size: 0,
+ ModTime: time.Unix(1360601116, 0),
+ Typeflag: TypeDir,
+ },
+ fm: 0755 | os.ModeDir,
+ },
+ // fifo node.
+ {
+ h: &Header{
+ Name: "dev/initctl",
+ Mode: 0600 | c_ISFIFO,
+ Size: 0,
+ ModTime: time.Unix(1360578949, 0),
+ Typeflag: TypeFifo,
+ },
+ fm: 0600 | os.ModeNamedPipe,
+ },
+ // setuid.
+ {
+ h: &Header{
+ Name: "bin/su",
+ Mode: 0755 | c_ISREG | c_ISUID,
+ Size: 23232,
+ ModTime: time.Unix(1355405093, 0),
+ Typeflag: TypeReg,
+ },
+ fm: 0755 | os.ModeSetuid,
+ },
+ // setguid.
+ {
+ h: &Header{
+ Name: "group.txt",
+ Mode: 0750 | c_ISREG | c_ISGID,
+ Size: 0,
+ ModTime: time.Unix(1360602346, 0),
+ Typeflag: TypeReg,
+ },
+ fm: 0750 | os.ModeSetgid,
+ },
+ // sticky.
+ {
+ h: &Header{
+ Name: "sticky.txt",
+ Mode: 0600 | c_ISREG | c_ISVTX,
+ Size: 7,
+ ModTime: time.Unix(1360602540, 0),
+ Typeflag: TypeReg,
+ },
+ fm: 0600 | os.ModeSticky,
+ },
+ }
+
+ for i, g := range golden {
+ fi := g.h.FileInfo()
+ h2, err := FileInfoHeader(fi, "")
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ if got, want := h2.Name, g.h.Name; got != want {
+ t.Errorf("i=%d: Name: got %v, want %v", i, got, want)
+ }
+ if got, want := h2.Size, g.h.Size; got != want {
+ t.Errorf("i=%d: Size: got %v, want %v", i, got, want)
+ }
+ if got, want := h2.Mode, g.h.Mode; got != want {
+ t.Errorf("i=%d: Mode: got %o, want %o", i, got, want)
+ }
+ if got, want := fi.Mode(), g.fm; got != want {
+ t.Errorf("i=%d: fi.Mode: got %o, want %o", i, got, want)
+ }
+ if got, want := h2.ModTime, g.h.ModTime; got != want {
+ t.Errorf("i=%d: ModTime: got %v, want %v", i, got, want)
+ }
+ if sysh, ok := fi.Sys().(*Header); !ok || sysh != g.h {
+ t.Errorf("i=%d: Sys didn't return original *Header", i)
+ }
+ }
+}
diff --git a/libgo/go/archive/tar/testdata/pax.tar b/libgo/go/archive/tar/testdata/pax.tar
new file mode 100644
index 00000000000..9bc24b6587d
Binary files /dev/null and b/libgo/go/archive/tar/testdata/pax.tar differ
diff --git a/libgo/go/archive/tar/testdata/ustar.tar b/libgo/go/archive/tar/testdata/ustar.tar
new file mode 100644
index 00000000000..29679d9a305
Binary files /dev/null and b/libgo/go/archive/tar/testdata/ustar.tar differ
diff --git a/libgo/go/archive/tar/writer.go b/libgo/go/archive/tar/writer.go
index 5af504b437d..d92dd06eab1 100644
--- a/libgo/go/archive/tar/writer.go
+++ b/libgo/go/archive/tar/writer.go
@@ -8,10 +8,14 @@ package tar
// - catch more errors (no first header, etc.)
import (
+ "bytes"
"errors"
"fmt"
"io"
+ "os"
+ "path"
"strconv"
+ "strings"
"time"
)
@@ -19,23 +23,13 @@ var (
ErrWriteTooLong = errors.New("archive/tar: write too long")
ErrFieldTooLong = errors.New("archive/tar: header field too long")
ErrWriteAfterClose = errors.New("archive/tar: write after close")
+ errNameTooLong = errors.New("archive/tar: name too long")
)
// A Writer provides sequential writing of a tar archive in POSIX.1 format.
// A tar archive consists of a sequence of files.
// Call WriteHeader to begin a new file, and then call Write to supply that file's data,
// writing at most hdr.Size bytes in total.
-//
-// Example:
-// tw := tar.NewWriter(w)
-// hdr := new(tar.Header)
-// hdr.Size = length of data in bytes
-// // populate other hdr fields as desired
-// if err := tw.WriteHeader(hdr); err != nil {
-// // handle error
-// }
-// io.Copy(tw, data)
-// tw.Close()
type Writer struct {
w io.Writer
err error
@@ -130,15 +124,31 @@ func (tw *Writer) WriteHeader(hdr *Header) error {
if tw.err != nil {
return tw.err
}
-
+ // Decide whether or not to use PAX extensions
+ // TODO(shanemhansen): we might want to use PAX headers for
+ // subsecond time resolution, but for now let's just capture
+ // the long name/long symlink use case.
+ suffix := hdr.Name
+ prefix := ""
+ if len(hdr.Name) > fileNameSize || len(hdr.Linkname) > fileNameSize {
+ var err error
+ prefix, suffix, err = tw.splitUSTARLongName(hdr.Name)
+ // Either we were unable to pack the long name into ustar format
+ // or the link name is too long; use PAX headers.
+ if err == errNameTooLong || len(hdr.Linkname) > fileNameSize {
+ if err := tw.writePAXHeader(hdr); err != nil {
+ return err
+ }
+ } else if err != nil {
+ return err
+ }
+ }
tw.nb = int64(hdr.Size)
tw.pad = -tw.nb & (blockSize - 1) // blockSize is a power of two
header := make([]byte, blockSize)
s := slicer(header)
-
- // TODO(dsymonds): handle names longer than 100 chars
- copy(s.next(100), []byte(hdr.Name))
+ tw.cString(s.next(fileNameSize), suffix)
// Handle out of range ModTime carefully.
var modTime int64
@@ -159,11 +169,15 @@ func (tw *Writer) WriteHeader(hdr *Header) error {
tw.cString(s.next(32), hdr.Gname) // 297:329
tw.numeric(s.next(8), hdr.Devmajor) // 329:337
tw.numeric(s.next(8), hdr.Devminor) // 337:345
-
+ tw.cString(s.next(155), prefix) // 345:500
// Use the GNU magic instead of POSIX magic if we used any GNU extensions.
if tw.usedBinary {
copy(header[257:265], []byte("ustar \x00"))
}
+ // Use the ustar magic if we used ustar long names.
+ if len(prefix) > 0 {
+ copy(header[257:265], []byte("ustar\000"))
+ }
// The chksum field is terminated by a NUL and a space.
// This is different from the other octal fields.
@@ -181,6 +195,78 @@ func (tw *Writer) WriteHeader(hdr *Header) error {
return tw.err
}
+// writeUSTARLongName splits a USTAR long name hdr.Name.
+// name must be < 256 characters. errNameTooLong is returned
+// if hdr.Name can't be split. The splitting heuristic
+// is compatible with gnu tar.
+func (tw *Writer) splitUSTARLongName(name string) (prefix, suffix string, err error) {
+ length := len(name)
+ if length > fileNamePrefixSize+1 {
+ length = fileNamePrefixSize + 1
+ } else if name[length-1] == '/' {
+ length--
+ }
+ i := strings.LastIndex(name[:length], "/")
+ nlen := length - i - 1
+ if i <= 0 || nlen > fileNameSize || nlen == 0 {
+ err = errNameTooLong
+ return
+ }
+ prefix, suffix = name[:i], name[i+1:]
+ return
+}
+
+// writePaxHeader writes an extended pax header to the
+// archive.
+func (tw *Writer) writePAXHeader(hdr *Header) error {
+ // Prepare extended header
+ ext := new(Header)
+ ext.Typeflag = TypeXHeader
+ // Setting ModTime is required for reader parsing to
+ // succeed, and seems harmless enough.
+ ext.ModTime = hdr.ModTime
+ // The spec asks that we namespace our pseudo files
+ // with the current pid.
+ pid := os.Getpid()
+ dir, file := path.Split(hdr.Name)
+ ext.Name = path.Join(dir,
+ fmt.Sprintf("PaxHeaders.%d", pid), file)[0:100]
+ // Construct the body
+ var buf bytes.Buffer
+ if len(hdr.Name) > fileNameSize {
+ fmt.Fprint(&buf, paxHeader("path="+hdr.Name))
+ }
+ if len(hdr.Linkname) > fileNameSize {
+ fmt.Fprint(&buf, paxHeader("linkpath="+hdr.Linkname))
+ }
+ ext.Size = int64(len(buf.Bytes()))
+ if err := tw.WriteHeader(ext); err != nil {
+ return err
+ }
+ if _, err := tw.Write(buf.Bytes()); err != nil {
+ return err
+ }
+ if err := tw.Flush(); err != nil {
+ return err
+ }
+ return nil
+}
+
+// paxHeader formats a single pax record, prefixing it with the appropriate length
+func paxHeader(msg string) string {
+ const padding = 2 // Extra padding for space and newline
+ size := len(msg) + padding
+ size += len(strconv.Itoa(size))
+ record := fmt.Sprintf("%d %s\n", size, msg)
+ if len(record) != size {
+ // Final adjustment if adding size increased
+ // the number of digits in size
+ size = len(record)
+ record = fmt.Sprintf("%d %s\n", size, msg)
+ }
+ return record
+}
+
// Write writes to the current entry in the tar archive.
// Write returns the error ErrWriteTooLong if more than
// hdr.Size bytes are written after WriteHeader.
diff --git a/libgo/go/archive/tar/writer_test.go b/libgo/go/archive/tar/writer_test.go
index a214e57b9fc..4cf7c72aff3 100644
--- a/libgo/go/archive/tar/writer_test.go
+++ b/libgo/go/archive/tar/writer_test.go
@@ -9,6 +9,7 @@ import (
"fmt"
"io"
"io/ioutil"
+ "os"
"strings"
"testing"
"testing/iotest"
@@ -101,6 +102,27 @@ var writerTests = []*writerTest{
},
},
},
+ // This file was produced using gnu tar 1.17
+ // gnutar -b 4 --format=ustar (longname/)*15 + file.txt
+ {
+ file: "testdata/ustar.tar",
+ entries: []*writerTestEntry{
+ {
+ header: &Header{
+ Name: strings.Repeat("longname/", 15) + "file.txt",
+ Mode: 0644,
+ Uid: 0765,
+ Gid: 024,
+ Size: 06,
+ ModTime: time.Unix(1360135598, 0),
+ Typeflag: '0',
+ Uname: "shane",
+ Gname: "staff",
+ },
+ contents: "hello\n",
+ },
+ },
+ },
}
// Render byte array in a two-character hexadecimal string, spaced for easy visual inspection.
@@ -180,3 +202,61 @@ testLoop:
}
}
}
+
+func TestPax(t *testing.T) {
+ // Create an archive with a large name
+ fileinfo, err := os.Stat("testdata/small.txt")
+ if err != nil {
+ t.Fatal(err)
+ }
+ hdr, err := FileInfoHeader(fileinfo, "")
+ if err != nil {
+ t.Fatalf("os.Stat: %v", err)
+ }
+ // Force a PAX long name to be written
+ longName := strings.Repeat("ab", 100)
+ contents := strings.Repeat(" ", int(hdr.Size))
+ hdr.Name = longName
+ var buf bytes.Buffer
+ writer := NewWriter(&buf)
+ if err := writer.WriteHeader(hdr); err != nil {
+ t.Fatal(err)
+ }
+ if _, err = writer.Write([]byte(contents)); err != nil {
+ t.Fatal(err)
+ }
+ if err := writer.Close(); err != nil {
+ t.Fatal(err)
+ }
+ // Simple test to make sure PAX extensions are in effect
+ if !bytes.Contains(buf.Bytes(), []byte("PaxHeaders.")) {
+ t.Fatal("Expected at least one PAX header to be written.")
+ }
+ // Test that we can get a long name back out of the archive.
+ reader := NewReader(&buf)
+ hdr, err = reader.Next()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if hdr.Name != longName {
+ t.Fatal("Couldn't recover long file name")
+ }
+}
+
+func TestPAXHeader(t *testing.T) {
+ medName := strings.Repeat("CD", 50)
+ longName := strings.Repeat("AB", 100)
+ paxTests := [][2]string{
+ {"name=/etc/hosts", "19 name=/etc/hosts\n"},
+ {"a=b", "6 a=b\n"}, // Single digit length
+ {"a=names", "11 a=names\n"}, // Test case involving carries
+ {"name=" + longName, fmt.Sprintf("210 name=%s\n", longName)},
+ {"name=" + medName, fmt.Sprintf("110 name=%s\n", medName)}}
+
+ for _, test := range paxTests {
+ key, expected := test[0], test[1]
+ if result := paxHeader(key); result != expected {
+ t.Fatalf("paxHeader: got %s, expected %s", result, expected)
+ }
+ }
+}
diff --git a/libgo/go/archive/zip/reader.go b/libgo/go/archive/zip/reader.go
index c10f29a8369..f19cf2d1f1e 100644
--- a/libgo/go/archive/zip/reader.go
+++ b/libgo/go/archive/zip/reader.go
@@ -353,6 +353,11 @@ func readDirectoryEnd(r io.ReaderAt, size int64) (dir *directoryEnd, err error)
if err != nil {
return nil, err
}
+
+ // Make sure directoryOffset points to somewhere in our file.
+ if o := int64(d.directoryOffset); o < 0 || o >= size {
+ return nil, ErrFormat
+ }
return d, nil
}
@@ -407,7 +412,7 @@ func findSignatureInBlock(b []byte) int {
if b[i] == 'P' && b[i+1] == 'K' && b[i+2] == 0x05 && b[i+3] == 0x06 {
// n is length of comment
n := int(b[i+directoryEndLen-2]) | int(b[i+directoryEndLen-1])<<8
- if n+directoryEndLen+i == len(b) {
+ if n+directoryEndLen+i <= len(b) {
return i
}
}
diff --git a/libgo/go/archive/zip/reader_test.go b/libgo/go/archive/zip/reader_test.go
index cf9c59c4b92..833ba28ad52 100644
--- a/libgo/go/archive/zip/reader_test.go
+++ b/libgo/go/archive/zip/reader_test.go
@@ -63,6 +63,24 @@ var tests = []ZipTest{
},
},
},
+ {
+ Name: "test-trailing-junk.zip",
+ Comment: "This is a zipfile comment.",
+ File: []ZipTestFile{
+ {
+ Name: "test.txt",
+ Content: []byte("This is a test text file.\n"),
+ Mtime: "09-05-10 12:12:02",
+ Mode: 0644,
+ },
+ {
+ Name: "gophercolor16x16.png",
+ File: "gophercolor16x16.png",
+ Mtime: "09-05-10 15:52:58",
+ Mode: 0644,
+ },
+ },
+ },
{
Name: "r.zip",
Source: returnRecursiveZip,
@@ -262,7 +280,7 @@ func readTestZip(t *testing.T, zt ZipTest) {
}
}
if err != zt.Error {
- t.Errorf("error=%v, want %v", err, zt.Error)
+ t.Errorf("%s: error=%v, want %v", zt.Name, err, zt.Error)
return
}
diff --git a/libgo/go/archive/zip/struct.go b/libgo/go/archive/zip/struct.go
index ea067f3554f..73972d41cf0 100644
--- a/libgo/go/archive/zip/struct.go
+++ b/libgo/go/archive/zip/struct.go
@@ -64,8 +64,15 @@ const (
zip64ExtraId = 0x0001 // zip64 Extended Information Extra Field
)
+// FileHeader describes a file within a zip file.
+// See the zip spec for details.
type FileHeader struct {
- Name string
+ // Name is the name of the file.
+ // It must be a relative path: it must not start with a drive
+ // letter (e.g. C:) or leading slash, and only forward slashes
+ // are allowed.
+ Name string
+
CreatorVersion uint16
ReaderVersion uint16
Flags uint16
diff --git a/libgo/go/archive/zip/testdata/test-trailing-junk.zip b/libgo/go/archive/zip/testdata/test-trailing-junk.zip
new file mode 100644
index 00000000000..42281b4e305
Binary files /dev/null and b/libgo/go/archive/zip/testdata/test-trailing-junk.zip differ
diff --git a/libgo/go/archive/zip/writer.go b/libgo/go/archive/zip/writer.go
index 4c696e1529e..e9f147cea66 100644
--- a/libgo/go/archive/zip/writer.go
+++ b/libgo/go/archive/zip/writer.go
@@ -163,6 +163,9 @@ func (w *Writer) Close() error {
// Create adds a file to the zip file using the provided name.
// It returns a Writer to which the file contents should be written.
+// The name must be a relative path: it must not start with a drive
+// letter (e.g. C:) or leading slash, and only forward slashes are
+// allowed.
// The file's contents must be written to the io.Writer before the next
// call to Create, CreateHeader, or Close.
func (w *Writer) Create(name string) (io.Writer, error) {
diff --git a/libgo/go/bufio/bufio.go b/libgo/go/bufio/bufio.go
index 33779014c9c..df3501f2ca1 100644
--- a/libgo/go/bufio/bufio.go
+++ b/libgo/go/bufio/bufio.go
@@ -274,11 +274,10 @@ func (b *Reader) ReadSlice(delim byte) (line []byte, err error) {
return b.buf, ErrBufferFull
}
}
- panic("not reached")
}
// ReadLine is a low-level line-reading primitive. Most callers should use
-// ReadBytes('\n') or ReadString('\n') instead.
+// ReadBytes('\n') or ReadString('\n') instead or use a Scanner.
//
// ReadLine tries to return a single line, not including the end-of-line bytes.
// If the line was too long for the buffer then isPrefix is set and the
@@ -331,6 +330,7 @@ func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error) {
// it returns the data read before the error and the error itself (often io.EOF).
// ReadBytes returns err != nil if and only if the returned data does not end in
// delim.
+// For simple uses, a Scanner may be more convenient.
func (b *Reader) ReadBytes(delim byte) (line []byte, err error) {
// Use ReadSlice to look for array,
// accumulating full buffers.
@@ -378,6 +378,7 @@ func (b *Reader) ReadBytes(delim byte) (line []byte, err error) {
// it returns the data read before the error and the error itself (often io.EOF).
// ReadString returns err != nil if and only if the returned data does not end in
// delim.
+// For simple uses, a Scanner may be more convenient.
func (b *Reader) ReadString(delim byte) (line string, err error) {
bytes, err := b.ReadBytes(delim)
return string(bytes), err
diff --git a/libgo/go/bufio/bufio_test.go b/libgo/go/bufio/bufio_test.go
index 418690aa454..79ed0f178e0 100644
--- a/libgo/go/bufio/bufio_test.go
+++ b/libgo/go/bufio/bufio_test.go
@@ -7,6 +7,7 @@ package bufio_test
import (
. "bufio"
"bytes"
+ "errors"
"fmt"
"io"
"io/ioutil"
@@ -434,9 +435,12 @@ func TestWriteErrors(t *testing.T) {
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)
+ // Two flushes, to verify the error is sticky.
+ for i := 0; i < 2; i++ {
+ e = buf.Flush()
+ if e != w.expect {
+ t.Errorf("Flush %d/2 %v: got %v, wanted %v", i+1, w, e, w.expect)
+ }
}
}
}
@@ -953,7 +957,7 @@ func TestNegativeRead(t *testing.T) {
t.Fatal("read did not panic")
case error:
if !strings.Contains(err.Error(), "reader returned negative count from Read") {
- t.Fatal("wrong panic: %v", err)
+ t.Fatalf("wrong panic: %v", err)
}
default:
t.Fatalf("unexpected panic value: %T(%v)", err, err)
@@ -962,6 +966,43 @@ func TestNegativeRead(t *testing.T) {
b.Read(make([]byte, 100))
}
+var errFake = errors.New("fake error")
+
+type errorThenGoodReader struct {
+ didErr bool
+ nread int
+}
+
+func (r *errorThenGoodReader) Read(p []byte) (int, error) {
+ r.nread++
+ if !r.didErr {
+ r.didErr = true
+ return 0, errFake
+ }
+ return len(p), nil
+}
+
+func TestReaderClearError(t *testing.T) {
+ r := &errorThenGoodReader{}
+ b := NewReader(r)
+ buf := make([]byte, 1)
+ if _, err := b.Read(nil); err != nil {
+ t.Fatalf("1st nil Read = %v; want nil", err)
+ }
+ if _, err := b.Read(buf); err != errFake {
+ t.Fatalf("1st Read = %v; want errFake", err)
+ }
+ if _, err := b.Read(nil); err != nil {
+ t.Fatalf("2nd nil Read = %v; want nil", err)
+ }
+ if _, err := b.Read(buf); err != nil {
+ t.Fatalf("3rd Read with buffer = %v; want nil", err)
+ }
+ if r.nread != 2 {
+ t.Errorf("num reads = %d; want 2", r.nread)
+ }
+}
+
// An onlyReader only implements io.Reader, no matter what other methods the underlying implementation may have.
type onlyReader struct {
r io.Reader
diff --git a/libgo/go/bufio/example_test.go b/libgo/go/bufio/example_test.go
new file mode 100644
index 00000000000..08a39441e66
--- /dev/null
+++ b/libgo/go/bufio/example_test.go
@@ -0,0 +1,74 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bufio_test
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+ "strconv"
+ "strings"
+)
+
+// The simplest use of a Scanner, to read standard input as a set of lines.
+func ExampleScanner_lines() {
+ scanner := bufio.NewScanner(os.Stdin)
+ for scanner.Scan() {
+ fmt.Println(scanner.Text()) // Println will add back the final '\n'
+ }
+ if err := scanner.Err(); err != nil {
+ fmt.Fprintln(os.Stderr, "reading standard input:", err)
+ }
+}
+
+// Use a Scanner to implement a simple word-count utility by scanning the
+// input as a sequence of space-delimited tokens.
+func ExampleScanner_words() {
+ // An artificial input source.
+ const input = "Now is the winter of our discontent,\nMade glorious summer by this sun of York.\n"
+ scanner := bufio.NewScanner(strings.NewReader(input))
+ // Set the split function for the scanning operation.
+ scanner.Split(bufio.ScanWords)
+ // Count the words.
+ count := 0
+ for scanner.Scan() {
+ count++
+ }
+ if err := scanner.Err(); err != nil {
+ fmt.Fprintln(os.Stderr, "reading input:", err)
+ }
+ fmt.Printf("%d\n", count)
+ // Output: 15
+}
+
+// Use a Scanner with a custom split function (built by wrapping ScanWords) to validate
+// 32-bit decimal input.
+func ExampleScanner_custom() {
+ // An artificial input source.
+ const input = "1234 5678 1234567901234567890"
+ scanner := bufio.NewScanner(strings.NewReader(input))
+ // Create a custom split function by wrapping the existing ScanWords function.
+ split := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
+ advance, token, err = bufio.ScanWords(data, atEOF)
+ if err == nil && token != nil {
+ _, err = strconv.ParseInt(string(token), 10, 32)
+ }
+ return
+ }
+ // Set the split function for the scanning operation.
+ scanner.Split(split)
+ // Validate the input
+ for scanner.Scan() {
+ fmt.Printf("%s\n", scanner.Text())
+ }
+
+ if err := scanner.Err(); err != nil {
+ fmt.Printf("Invalid input: %s", err)
+ }
+ // Output:
+ // 1234
+ // 5678
+ // Invalid input: strconv.ParseInt: parsing "1234567901234567890": value out of range
+}
diff --git a/libgo/go/bufio/export_test.go b/libgo/go/bufio/export_test.go
new file mode 100644
index 00000000000..3d3bb27d8da
--- /dev/null
+++ b/libgo/go/bufio/export_test.go
@@ -0,0 +1,27 @@
+// Copyright 2013 The Go Authors. 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
+
+// Exported for testing only.
+import (
+ "unicode/utf8"
+)
+
+var IsSpace = isSpace
+
+func (s *Scanner) MaxTokenSize(n int) {
+ if n < utf8.UTFMax || n > 1e9 {
+ panic("bad max token size")
+ }
+ if n < len(s.buf) {
+ s.buf = make([]byte, n)
+ }
+ s.maxTokenSize = n
+}
+
+// ErrOrEOF is like Err, but returns EOF. Used to test a corner case.
+func (s *Scanner) ErrOrEOF() error {
+ return s.err
+}
diff --git a/libgo/go/bufio/scan.go b/libgo/go/bufio/scan.go
new file mode 100644
index 00000000000..2e1a2e99973
--- /dev/null
+++ b/libgo/go/bufio/scan.go
@@ -0,0 +1,346 @@
+// Copyright 2013 The Go Authors. 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 (
+ "bytes"
+ "errors"
+ "io"
+ "unicode/utf8"
+)
+
+// Scanner provides a convenient interface for reading data such as
+// a file of newline-delimited lines of text. Successive calls to
+// the Scan method will step through the 'tokens' of a file, skipping
+// the bytes between the tokens. The specification of a token is
+// defined by a split function of type SplitFunc; the default split
+// function breaks the input into lines with line termination stripped. Split
+// functions are defined in this package for scanning a file into
+// lines, bytes, UTF-8-encoded runes, and space-delimited words. The
+// client may instead provide a custom split function.
+//
+// Scanning stops unrecoverably at EOF, the first I/O error, or a token too
+// large to fit in the buffer. When a scan stops, the reader may have
+// advanced arbitrarily far past the last token. Programs that need more
+// control over error handling or large tokens, or must run sequential scans
+// on a reader, should use bufio.Reader instead.
+//
+type Scanner struct {
+ r io.Reader // The reader provided by the client.
+ split SplitFunc // The function to split the tokens.
+ maxTokenSize int // Maximum size of a token; modified by tests.
+ token []byte // Last token returned by split.
+ buf []byte // Buffer used as argument to split.
+ start int // First non-processed byte in buf.
+ end int // End of data in buf.
+ err error // Sticky error.
+}
+
+// SplitFunc is the signature of the split function used to tokenize the
+// input. The arguments are an initial substring of the remaining unprocessed
+// data and a flag, atEOF, that reports whether the Reader has no more data
+// to give. The return values are the number of bytes to advance the input
+// and the next token to return to the user, plus an error, if any. If the
+// data does not yet hold a complete token, for instance if it has no newline
+// while scanning lines, SplitFunc can return (0, nil) to signal the Scanner
+// to read more data into the slice and try again with a longer slice
+// starting at the same point in the input.
+//
+// If the returned error is non-nil, scanning stops and the error
+// is returned to the client.
+//
+// The function is never called with an empty data slice unless atEOF
+// is true. If atEOF is true, however, data may be non-empty and,
+// as always, holds unprocessed text.
+type SplitFunc func(data []byte, atEOF bool) (advance int, token []byte, err error)
+
+// Errors returned by Scanner.
+var (
+ ErrTooLong = errors.New("bufio.Scanner: token too long")
+ ErrNegativeAdvance = errors.New("bufio.Scanner: SplitFunc returns negative advance count")
+ ErrAdvanceTooFar = errors.New("bufio.Scanner: SplitFunc returns advance count beyond input")
+)
+
+const (
+ // Maximum size used to buffer a token. The actual maximum token size
+ // may be smaller as the buffer may need to include, for instance, a newline.
+ MaxScanTokenSize = 64 * 1024
+)
+
+// NewScanner returns a new Scanner to read from r.
+// The split function defaults to ScanLines.
+func NewScanner(r io.Reader) *Scanner {
+ return &Scanner{
+ r: r,
+ split: ScanLines,
+ maxTokenSize: MaxScanTokenSize,
+ buf: make([]byte, 4096), // Plausible starting size; needn't be large.
+ }
+}
+
+// Err returns the first non-EOF error that was encountered by the Scanner.
+func (s *Scanner) Err() error {
+ if s.err == io.EOF {
+ return nil
+ }
+ return s.err
+}
+
+// Bytes returns the most recent token generated by a call to Scan.
+// The underlying array may point to data that will be overwritten
+// by a subsequent call to Scan. It does no allocation.
+func (s *Scanner) Bytes() []byte {
+ return s.token
+}
+
+// Text returns the most recent token generated by a call to Scan
+// as a newly allocated string holding its bytes.
+func (s *Scanner) Text() string {
+ return string(s.token)
+}
+
+// Scan advances the Scanner to the next token, which will then be
+// available through the Bytes or Text method. It returns false when the
+// scan stops, either by reaching the end of the input or an error.
+// After Scan returns false, the Err method will return any error that
+// occurred during scanning, except that if it was io.EOF, Err
+// will return nil.
+func (s *Scanner) Scan() bool {
+ // Loop until we have a token.
+ for {
+ // See if we can get a token with what we already have.
+ if s.end > s.start {
+ advance, token, err := s.split(s.buf[s.start:s.end], s.err != nil)
+ if err != nil {
+ s.setErr(err)
+ return false
+ }
+ if !s.advance(advance) {
+ return false
+ }
+ s.token = token
+ if token != nil {
+ return true
+ }
+ }
+ // We cannot generate a token with what we are holding.
+ // If we've already hit EOF or an I/O error, we are done.
+ if s.err != nil {
+ // Shut it down.
+ s.start = 0
+ s.end = 0
+ return false
+ }
+ // Must read more data.
+ // First, shift data to beginning of buffer if there's lots of empty space
+ // or space is neded.
+ if s.start > 0 && (s.end == len(s.buf) || s.start > len(s.buf)/2) {
+ copy(s.buf, s.buf[s.start:s.end])
+ s.end -= s.start
+ s.start = 0
+ }
+ // Is the buffer full? If so, resize.
+ if s.end == len(s.buf) {
+ if len(s.buf) >= s.maxTokenSize {
+ s.setErr(ErrTooLong)
+ return false
+ }
+ newSize := len(s.buf) * 2
+ if newSize > s.maxTokenSize {
+ newSize = s.maxTokenSize
+ }
+ newBuf := make([]byte, newSize)
+ copy(newBuf, s.buf[s.start:s.end])
+ s.buf = newBuf
+ s.end -= s.start
+ s.start = 0
+ continue
+ }
+ // Finally we can read some input. Make sure we don't get stuck with
+ // a misbehaving Reader. Officially we don't need to do this, but let's
+ // be extra careful: Scanner is for safe, simple jobs.
+ for loop := 0; ; {
+ n, err := s.r.Read(s.buf[s.end:len(s.buf)])
+ s.end += n
+ if err != nil {
+ s.setErr(err)
+ break
+ }
+ if n > 0 {
+ break
+ }
+ loop++
+ if loop > 100 {
+ s.setErr(io.ErrNoProgress)
+ break
+ }
+ }
+ }
+}
+
+// advance consumes n bytes of the buffer. It reports whether the advance was legal.
+func (s *Scanner) advance(n int) bool {
+ if n < 0 {
+ s.setErr(ErrNegativeAdvance)
+ return false
+ }
+ if n > s.end-s.start {
+ s.setErr(ErrAdvanceTooFar)
+ return false
+ }
+ s.start += n
+ return true
+}
+
+// setErr records the first error encountered.
+func (s *Scanner) setErr(err error) {
+ if s.err == nil || s.err == io.EOF {
+ s.err = err
+ }
+}
+
+// Split sets the split function for the Scanner. If called, it must be
+// called before Scan. The default split function is ScanLines.
+func (s *Scanner) Split(split SplitFunc) {
+ s.split = split
+}
+
+// Split functions
+
+// ScanBytes is a split function for a Scanner that returns each byte as a token.
+func ScanBytes(data []byte, atEOF bool) (advance int, token []byte, err error) {
+ if atEOF && len(data) == 0 {
+ return 0, nil, nil
+ }
+ return 1, data[0:1], nil
+}
+
+var errorRune = []byte(string(utf8.RuneError))
+
+// ScanRunes is a split function for a Scanner that returns each
+// UTF-8-encoded rune as a token. The sequence of runes returned is
+// equivalent to that from a range loop over the input as a string, which
+// means that erroneous UTF-8 encodings translate to U+FFFD = "\xef\xbf\xbd".
+// Because of the Scan interface, this makes it impossible for the client to
+// distinguish correctly encoded replacement runes from encoding errors.
+func ScanRunes(data []byte, atEOF bool) (advance int, token []byte, err error) {
+ if atEOF && len(data) == 0 {
+ return 0, nil, nil
+ }
+
+ // Fast path 1: ASCII.
+ if data[0] < utf8.RuneSelf {
+ return 1, data[0:1], nil
+ }
+
+ // Fast path 2: Correct UTF-8 decode without error.
+ _, width := utf8.DecodeRune(data)
+ if width > 1 {
+ // It's a valid encoding. Width cannot be one for a correctly encoded
+ // non-ASCII rune.
+ return width, data[0:width], nil
+ }
+
+ // We know it's an error: we have width==1 and implicitly r==utf8.RuneError.
+ // Is the error because there wasn't a full rune to be decoded?
+ // FullRune distinguishes correctly between erroneous and incomplete encodings.
+ if !atEOF && !utf8.FullRune(data) {
+ // Incomplete; get more bytes.
+ return 0, nil, nil
+ }
+
+ // We have a real UTF-8 encoding error. Return a properly encoded error rune
+ // but advance only one byte. This matches the behavior of a range loop over
+ // an incorrectly encoded string.
+ return 1, errorRune, nil
+}
+
+// dropCR drops a terminal \r from the data.
+func dropCR(data []byte) []byte {
+ if len(data) > 0 && data[len(data)-1] == '\r' {
+ return data[0 : len(data)-1]
+ }
+ return data
+}
+
+// ScanLines is a split function for a Scanner that returns each line of
+// text, stripped of any trailing end-of-line marker. The returned line may
+// be empty. The end-of-line marker is one optional carriage return followed
+// by one mandatory newline. In regular expression notation, it is `\r?\n`.
+// The last non-empty line of input will be returned even if it has no
+// newline.
+func ScanLines(data []byte, atEOF bool) (advance int, token []byte, err error) {
+ if atEOF && len(data) == 0 {
+ return 0, nil, nil
+ }
+ if i := bytes.IndexByte(data, '\n'); i >= 0 {
+ // We have a full newline-terminated line.
+ return i + 1, dropCR(data[0:i]), nil
+ }
+ // If we're at EOF, we have a final, non-terminated line. Return it.
+ if atEOF {
+ return len(data), dropCR(data), nil
+ }
+ // Request more data.
+ return 0, nil, nil
+}
+
+// isSpace returns whether the character is a Unicode white space character.
+// We avoid dependency on the unicode package, but check validity of the implementation
+// in the tests.
+func isSpace(r rune) bool {
+ if r <= '\u00FF' {
+ // Obvious ASCII ones: \t through \r plus space. Plus two Latin-1 oddballs.
+ switch r {
+ case ' ', '\t', '\n', '\v', '\f', '\r':
+ return true
+ case '\u0085', '\u00A0':
+ return true
+ }
+ return false
+ }
+ // High-valued ones.
+ if '\u2000' <= r && r <= '\u200a' {
+ return true
+ }
+ switch r {
+ case '\u1680', '\u180e', '\u2028', '\u2029', '\u202f', '\u205f', '\u3000':
+ return true
+ }
+ return false
+}
+
+// ScanWords is a split function for a Scanner that returns each
+// space-separated word of text, with surrounding spaces deleted. It will
+// never return an empty string. The definition of space is set by
+// unicode.IsSpace.
+func ScanWords(data []byte, atEOF bool) (advance int, token []byte, err error) {
+ // Skip leading spaces.
+ start := 0
+ for width := 0; start < len(data); start += width {
+ var r rune
+ r, width = utf8.DecodeRune(data[start:])
+ if !isSpace(r) {
+ break
+ }
+ }
+ if atEOF && len(data) == 0 {
+ return 0, nil, nil
+ }
+ // Scan until space, marking end of word.
+ for width, i := 0, start; i < len(data); i += width {
+ var r rune
+ r, width = utf8.DecodeRune(data[i:])
+ if isSpace(r) {
+ return i + width, data[start:i], nil
+ }
+ }
+ // If we're at EOF, we have a final, non-empty, non-terminated word. Return it.
+ if atEOF && len(data) > start {
+ return len(data), data[start:], nil
+ }
+ // Request more data.
+ return 0, nil, nil
+}
diff --git a/libgo/go/bufio/scan_test.go b/libgo/go/bufio/scan_test.go
new file mode 100644
index 00000000000..c1483b26858
--- /dev/null
+++ b/libgo/go/bufio/scan_test.go
@@ -0,0 +1,406 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bufio_test
+
+import (
+ . "bufio"
+ "bytes"
+ "errors"
+ "io"
+ "strings"
+ "testing"
+ "unicode"
+ "unicode/utf8"
+)
+
+// Test white space table matches the Unicode definition.
+func TestSpace(t *testing.T) {
+ for r := rune(0); r <= utf8.MaxRune; r++ {
+ if IsSpace(r) != unicode.IsSpace(r) {
+ t.Fatalf("white space property disagrees: %#U should be %t", r, unicode.IsSpace(r))
+ }
+ }
+}
+
+var scanTests = []string{
+ "",
+ "a",
+ "¼",
+ "☹",
+ "\x81", // UTF-8 error
+ "\uFFFD", // correctly encoded RuneError
+ "abcdefgh",
+ "abc def\n\t\tgh ",
+ "abc¼☹\x81\uFFFD日本語\x82abc",
+}
+
+func TestScanByte(t *testing.T) {
+ for n, test := range scanTests {
+ buf := bytes.NewBufferString(test)
+ s := NewScanner(buf)
+ s.Split(ScanBytes)
+ var i int
+ for i = 0; s.Scan(); i++ {
+ if b := s.Bytes(); len(b) != 1 || b[0] != test[i] {
+ t.Errorf("#%d: %d: expected %q got %q", n, i, test, b)
+ }
+ }
+ if i != len(test) {
+ t.Errorf("#%d: termination expected at %d; got %d", n, len(test), i)
+ }
+ err := s.Err()
+ if err != nil {
+ t.Errorf("#%d: %v", n, err)
+ }
+ }
+}
+
+// Test that the rune splitter returns same sequence of runes (not bytes) as for range string.
+func TestScanRune(t *testing.T) {
+ for n, test := range scanTests {
+ buf := bytes.NewBufferString(test)
+ s := NewScanner(buf)
+ s.Split(ScanRunes)
+ var i, runeCount int
+ var expect rune
+ // Use a string range loop to validate the sequence of runes.
+ for i, expect = range string(test) {
+ if !s.Scan() {
+ break
+ }
+ runeCount++
+ got, _ := utf8.DecodeRune(s.Bytes())
+ if got != expect {
+ t.Errorf("#%d: %d: expected %q got %q", n, i, expect, got)
+ }
+ }
+ if s.Scan() {
+ t.Errorf("#%d: scan ran too long, got %q", n, s.Text())
+ }
+ testRuneCount := utf8.RuneCountInString(test)
+ if runeCount != testRuneCount {
+ t.Errorf("#%d: termination expected at %d; got %d", n, testRuneCount, runeCount)
+ }
+ err := s.Err()
+ if err != nil {
+ t.Errorf("#%d: %v", n, err)
+ }
+ }
+}
+
+var wordScanTests = []string{
+ "",
+ " ",
+ "\n",
+ "a",
+ " a ",
+ "abc def",
+ " abc def ",
+ " abc\tdef\nghi\rjkl\fmno\vpqr\u0085stu\u00a0\n",
+}
+
+// Test that the word splitter returns the same data as strings.Fields.
+func TestScanWords(t *testing.T) {
+ for n, test := range wordScanTests {
+ buf := bytes.NewBufferString(test)
+ s := NewScanner(buf)
+ s.Split(ScanWords)
+ words := strings.Fields(test)
+ var wordCount int
+ for wordCount = 0; wordCount < len(words); wordCount++ {
+ if !s.Scan() {
+ break
+ }
+ got := s.Text()
+ if got != words[wordCount] {
+ t.Errorf("#%d: %d: expected %q got %q", n, wordCount, words[wordCount], got)
+ }
+ }
+ if s.Scan() {
+ t.Errorf("#%d: scan ran too long, got %q", n, s.Text())
+ }
+ if wordCount != len(words) {
+ t.Errorf("#%d: termination expected at %d; got %d", n, len(words), wordCount)
+ }
+ err := s.Err()
+ if err != nil {
+ t.Errorf("#%d: %v", n, err)
+ }
+ }
+}
+
+// slowReader is a reader that returns only a few bytes at a time, to test the incremental
+// reads in Scanner.Scan.
+type slowReader struct {
+ max int
+ buf *bytes.Buffer
+}
+
+func (sr *slowReader) Read(p []byte) (n int, err error) {
+ if len(p) > sr.max {
+ p = p[0:sr.max]
+ }
+ return sr.buf.Read(p)
+}
+
+// genLine writes to buf a predictable but non-trivial line of text of length
+// n, including the terminal newline and an occasional carriage return.
+// If addNewline is false, the \r and \n are not emitted.
+func genLine(buf *bytes.Buffer, lineNum, n int, addNewline bool) {
+ buf.Reset()
+ doCR := lineNum%5 == 0
+ if doCR {
+ n--
+ }
+ for i := 0; i < n-1; i++ { // Stop early for \n.
+ c := 'a' + byte(lineNum+i)
+ if c == '\n' || c == '\r' { // Don't confuse us.
+ c = 'N'
+ }
+ buf.WriteByte(c)
+ }
+ if addNewline {
+ if doCR {
+ buf.WriteByte('\r')
+ }
+ buf.WriteByte('\n')
+ }
+ return
+}
+
+// Test the line splitter, including some carriage returns but no long lines.
+func TestScanLongLines(t *testing.T) {
+ const smallMaxTokenSize = 256 // Much smaller for more efficient testing.
+ // Build a buffer of lots of line lengths up to but not exceeding smallMaxTokenSize.
+ tmp := new(bytes.Buffer)
+ buf := new(bytes.Buffer)
+ lineNum := 0
+ j := 0
+ for i := 0; i < 2*smallMaxTokenSize; i++ {
+ genLine(tmp, lineNum, j, true)
+ if j < smallMaxTokenSize {
+ j++
+ } else {
+ j--
+ }
+ buf.Write(tmp.Bytes())
+ lineNum++
+ }
+ s := NewScanner(&slowReader{1, buf})
+ s.Split(ScanLines)
+ s.MaxTokenSize(smallMaxTokenSize)
+ j = 0
+ for lineNum := 0; s.Scan(); lineNum++ {
+ genLine(tmp, lineNum, j, false)
+ if j < smallMaxTokenSize {
+ j++
+ } else {
+ j--
+ }
+ line := tmp.String() // We use the string-valued token here, for variety.
+ if s.Text() != line {
+ t.Errorf("%d: bad line: %d %d\n%.100q\n%.100q\n", lineNum, len(s.Bytes()), len(line), s.Text(), line)
+ }
+ }
+ err := s.Err()
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+// Test that the line splitter errors out on a long line.
+func TestScanLineTooLong(t *testing.T) {
+ const smallMaxTokenSize = 256 // Much smaller for more efficient testing.
+ // Build a buffer of lots of line lengths up to but not exceeding smallMaxTokenSize.
+ tmp := new(bytes.Buffer)
+ buf := new(bytes.Buffer)
+ lineNum := 0
+ j := 0
+ for i := 0; i < 2*smallMaxTokenSize; i++ {
+ genLine(tmp, lineNum, j, true)
+ j++
+ buf.Write(tmp.Bytes())
+ lineNum++
+ }
+ s := NewScanner(&slowReader{3, buf})
+ s.Split(ScanLines)
+ s.MaxTokenSize(smallMaxTokenSize)
+ j = 0
+ for lineNum := 0; s.Scan(); lineNum++ {
+ genLine(tmp, lineNum, j, false)
+ if j < smallMaxTokenSize {
+ j++
+ } else {
+ j--
+ }
+ line := tmp.Bytes()
+ if !bytes.Equal(s.Bytes(), line) {
+ t.Errorf("%d: bad line: %d %d\n%.100q\n%.100q\n", lineNum, len(s.Bytes()), len(line), s.Bytes(), line)
+ }
+ }
+ err := s.Err()
+ if err != ErrTooLong {
+ t.Fatalf("expected ErrTooLong; got %s", err)
+ }
+}
+
+// Test that the line splitter handles a final line without a newline.
+func testNoNewline(text string, lines []string, t *testing.T) {
+ buf := bytes.NewBufferString(text)
+ s := NewScanner(&slowReader{7, buf})
+ s.Split(ScanLines)
+ for lineNum := 0; s.Scan(); lineNum++ {
+ line := lines[lineNum]
+ if s.Text() != line {
+ t.Errorf("%d: bad line: %d %d\n%.100q\n%.100q\n", lineNum, len(s.Bytes()), len(line), s.Bytes(), line)
+ }
+ }
+ err := s.Err()
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+var noNewlineLines = []string{
+ "abcdefghijklmn\nopqrstuvwxyz",
+}
+
+// Test that the line splitter handles a final line without a newline.
+func TestScanLineNoNewline(t *testing.T) {
+ const text = "abcdefghijklmn\nopqrstuvwxyz"
+ lines := []string{
+ "abcdefghijklmn",
+ "opqrstuvwxyz",
+ }
+ testNoNewline(text, lines, t)
+}
+
+// Test that the line splitter handles a final line with a carriage return but nonewline.
+func TestScanLineReturnButNoNewline(t *testing.T) {
+ const text = "abcdefghijklmn\nopqrstuvwxyz\r"
+ lines := []string{
+ "abcdefghijklmn",
+ "opqrstuvwxyz",
+ }
+ testNoNewline(text, lines, t)
+}
+
+// Test that the line splitter handles a final empty line.
+func TestScanLineEmptyFinalLine(t *testing.T) {
+ const text = "abcdefghijklmn\nopqrstuvwxyz\n\n"
+ lines := []string{
+ "abcdefghijklmn",
+ "opqrstuvwxyz",
+ "",
+ }
+ testNoNewline(text, lines, t)
+}
+
+// Test that the line splitter handles a final empty line with a carriage return but no newline.
+func TestScanLineEmptyFinalLineWithCR(t *testing.T) {
+ const text = "abcdefghijklmn\nopqrstuvwxyz\n\r"
+ lines := []string{
+ "abcdefghijklmn",
+ "opqrstuvwxyz",
+ "",
+ }
+ testNoNewline(text, lines, t)
+}
+
+var testError = errors.New("testError")
+
+// Test the correct error is returned when the split function errors out.
+func TestSplitError(t *testing.T) {
+ // Create a split function that delivers a little data, then a predictable error.
+ numSplits := 0
+ const okCount = 7
+ errorSplit := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
+ if atEOF {
+ panic("didn't get enough data")
+ }
+ if numSplits >= okCount {
+ return 0, nil, testError
+ }
+ numSplits++
+ return 1, data[0:1], nil
+ }
+ // Read the data.
+ const text = "abcdefghijklmnopqrstuvwxyz"
+ buf := bytes.NewBufferString(text)
+ s := NewScanner(&slowReader{1, buf})
+ s.Split(errorSplit)
+ var i int
+ for i = 0; s.Scan(); i++ {
+ if len(s.Bytes()) != 1 || text[i] != s.Bytes()[0] {
+ t.Errorf("#%d: expected %q got %q", i, text[i], s.Bytes()[0])
+ }
+ }
+ // Check correct termination location and error.
+ if i != okCount {
+ t.Errorf("unexpected termination; expected %d tokens got %d", okCount, i)
+ }
+ err := s.Err()
+ if err != testError {
+ t.Fatalf("expected %q got %v", testError, err)
+ }
+}
+
+// Test that an EOF is overridden by a user-generated scan error.
+func TestErrAtEOF(t *testing.T) {
+ s := NewScanner(strings.NewReader("1 2 33"))
+ // This spitter will fail on last entry, after s.err==EOF.
+ split := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
+ advance, token, err = ScanWords(data, atEOF)
+ if len(token) > 1 {
+ if s.ErrOrEOF() != io.EOF {
+ t.Fatal("not testing EOF")
+ }
+ err = testError
+ }
+ return
+ }
+ s.Split(split)
+ for s.Scan() {
+ }
+ if s.Err() != testError {
+ t.Fatal("wrong error:", s.Err())
+ }
+}
+
+// Test for issue 5268.
+type alwaysError struct{}
+
+func (alwaysError) Read(p []byte) (int, error) {
+ return 0, io.ErrUnexpectedEOF
+}
+
+func TestNonEOFWithEmptyRead(t *testing.T) {
+ scanner := NewScanner(alwaysError{})
+ for scanner.Scan() {
+ t.Fatal("read should fail")
+ }
+ err := scanner.Err()
+ if err != io.ErrUnexpectedEOF {
+ t.Errorf("unexpected error: %v", err)
+ }
+}
+
+// Test that Scan finishes if we have endless empty reads.
+type endlessZeros struct{}
+
+func (endlessZeros) Read(p []byte) (int, error) {
+ return 0, nil
+}
+
+func TestBadReader(t *testing.T) {
+ scanner := NewScanner(endlessZeros{})
+ for scanner.Scan() {
+ t.Fatal("read should fail")
+ }
+ err := scanner.Err()
+ if err != io.ErrNoProgress {
+ t.Errorf("unexpected error: %v", err)
+ }
+}
diff --git a/libgo/go/builtin/builtin.go b/libgo/go/builtin/builtin.go
index 91d263a6234..128a1b5f8fc 100644
--- a/libgo/go/builtin/builtin.go
+++ b/libgo/go/builtin/builtin.go
@@ -13,6 +13,12 @@ package builtin
// bool is the set of boolean values, true and false.
type bool bool
+// true and false are the two untyped boolean values.
+const (
+ true = 0 == 0 // Untyped bool.
+ false = 0 != 0 // Untyped bool.
+)
+
// uint8 is the set of all unsigned 8-bit integers.
// Range: 0 through 255.
type uint8 uint8
@@ -85,6 +91,15 @@ type byte byte
// used, by convention, to distinguish character values from integer values.
type rune rune
+// iota is a predeclared identifier representing the untyped integer ordinal
+// number of the current const specification in a (usually parenthesized)
+// const declaration. It is zero-indexed.
+const iota = 0 // Untyped int.
+
+// nil is a predeclared identifier representing the zero value for a
+// pointer, channel, func, interface, map, or slice type.
+var nil Type // Type must be a pointer, channel, func, interface, map, or slice type
+
// Type is here for the purposes of documentation only. It is a stand-in
// for any Go type, but represents the same type for any given function
// invocation.
@@ -114,6 +129,8 @@ type ComplexType complex64
// result of append, often in the variable holding the slice itself:
// slice = append(slice, elem1, elem2)
// slice = append(slice, anotherSlice...)
+// As a special case, it is legal to append a string to a byte slice, like this:
+// slice = append([]byte("hello "), "world"...)
func append(slice []Type, elems ...Type) []Type
// The copy built-in function copies elements from a source slice into a
diff --git a/libgo/go/bytes/buffer.go b/libgo/go/bytes/buffer.go
index 85c1577985d..46ca1d5ad3f 100644
--- a/libgo/go/bytes/buffer.go
+++ b/libgo/go/bytes/buffer.go
@@ -87,6 +87,13 @@ func (b *Buffer) grow(n int) int {
var buf []byte
if b.buf == nil && n <= len(b.bootstrap) {
buf = b.bootstrap[0:]
+ } else if m+n <= cap(b.buf)/2 {
+ // We can slide things down instead of allocating a new
+ // slice. We only need m+n <= cap(b.buf) to slide, but
+ // we instead let capacity get twice as large so we
+ // don't spend all our time copying.
+ copy(b.buf[:], b.buf[b.off:])
+ buf = b.buf[:m]
} else {
// not enough space anywhere
buf = makeSlice(2*cap(b.buf) + n)
@@ -112,20 +119,18 @@ func (b *Buffer) Grow(n int) {
b.buf = b.buf[0:m]
}
-// Write appends the contents of p to the buffer. The return
-// value n is the length of p; err is always nil.
-// If the buffer becomes too large, Write will panic with
-// ErrTooLarge.
+// Write appends the contents of p to the buffer, growing the buffer as
+// needed. The return value n is the length of p; err is always nil. If the
+// buffer becomes too large, Write will panic with ErrTooLarge.
func (b *Buffer) Write(p []byte) (n int, err error) {
b.lastRead = opInvalid
m := b.grow(len(p))
return copy(b.buf[m:], p), nil
}
-// WriteString appends the contents of s to the buffer. The return
-// value n is the length of s; err is always nil.
-// If the buffer becomes too large, WriteString will panic with
-// ErrTooLarge.
+// WriteString appends the contents of s to the buffer, growing the buffer as
+// needed. The return value n is the length of s; err is always nil. If the
+// buffer becomes too large, WriteString will panic with ErrTooLarge.
func (b *Buffer) WriteString(s string) (n int, err error) {
b.lastRead = opInvalid
m := b.grow(len(s))
@@ -138,12 +143,10 @@ func (b *Buffer) WriteString(s string) (n int, err error) {
// underlying buffer.
const MinRead = 512
-// ReadFrom reads data from r until EOF and appends it to the buffer.
-// The return value n is the number of bytes read.
-// Any error except io.EOF encountered during the read
-// is also returned.
-// If the buffer becomes too large, ReadFrom will panic with
-// ErrTooLarge.
+// ReadFrom reads data from r until EOF and appends it to the buffer, growing
+// the buffer as needed. The return value n is the number of bytes read. Any
+// error except io.EOF encountered during the read is also returned. If the
+// buffer becomes too large, ReadFrom will panic with ErrTooLarge.
func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) {
b.lastRead = opInvalid
// If buffer is empty, reset to recover space.
@@ -188,10 +191,10 @@ func makeSlice(n int) []byte {
return make([]byte, n)
}
-// WriteTo writes data to w until the buffer is drained or an error
-// occurs. The return value n is the number of bytes written; it always
-// fits into an int, but it is int64 to match the io.WriterTo interface.
-// Any error encountered during the write is also returned.
+// WriteTo writes data to w until the buffer is drained or an error occurs.
+// The return value n is the number of bytes written; it always fits into an
+// int, but it is int64 to match the io.WriterTo interface. Any error
+// encountered during the write is also returned.
func (b *Buffer) WriteTo(w io.Writer) (n int64, err error) {
b.lastRead = opInvalid
if b.off < len(b.buf) {
@@ -216,10 +219,9 @@ func (b *Buffer) WriteTo(w io.Writer) (n int64, err error) {
return
}
-// WriteByte appends the byte c to the buffer.
-// The returned error is always nil, but is included
-// to match bufio.Writer's WriteByte.
-// If the buffer becomes too large, WriteByte will panic with
+// WriteByte appends the byte c to the buffer, growing the buffer as needed.
+// The returned error is always nil, but is included to match bufio.Writer's
+// WriteByte. If the buffer becomes too large, WriteByte will panic with
// ErrTooLarge.
func (b *Buffer) WriteByte(c byte) error {
b.lastRead = opInvalid
@@ -228,12 +230,10 @@ func (b *Buffer) WriteByte(c byte) error {
return nil
}
-// WriteRune appends the UTF-8 encoding of Unicode
-// code point r to the buffer, returning its length and
-// an error, which is always nil but is included
-// to match bufio.Writer's WriteRune.
-// If the buffer becomes too large, WriteRune will panic with
-// ErrTooLarge.
+// WriteRune appends the UTF-8 encoding of Unicode code point r to the
+// buffer, returning its length and an error, which is always nil but is
+// included to match bufio.Writer's WriteRune. The buffer is grown as needed;
+// if it becomes too large, WriteRune will panic with ErrTooLarge.
func (b *Buffer) WriteRune(r rune) (n int, err error) {
if r < utf8.RuneSelf {
b.WriteByte(byte(r))
diff --git a/libgo/go/bytes/buffer_test.go b/libgo/go/bytes/buffer_test.go
index f9fb2625a0f..75145b05e92 100644
--- a/libgo/go/bytes/buffer_test.go
+++ b/libgo/go/bytes/buffer_test.go
@@ -475,3 +475,53 @@ func TestUnreadByte(t *testing.T) {
t.Errorf("ReadByte = %q; want %q", c, 'm')
}
}
+
+// Tests that we occasionally compact. Issue 5154.
+func TestBufferGrowth(t *testing.T) {
+ var b Buffer
+ buf := make([]byte, 1024)
+ b.Write(buf[0:1])
+ var cap0 int
+ for i := 0; i < 5<<10; i++ {
+ b.Write(buf)
+ b.Read(buf)
+ if i == 0 {
+ cap0 = b.Cap()
+ }
+ }
+ cap1 := b.Cap()
+ // (*Buffer).grow allows for 2x capacity slop before sliding,
+ // so set our error threshold at 3x.
+ if cap1 > cap0*3 {
+ t.Errorf("buffer cap = %d; too big (grew from %d)", cap1, cap0)
+ }
+}
+
+// From Issue 5154.
+func BenchmarkBufferNotEmptyWriteRead(b *testing.B) {
+ buf := make([]byte, 1024)
+ for i := 0; i < b.N; i++ {
+ var b Buffer
+ b.Write(buf[0:1])
+ for i := 0; i < 5<<10; i++ {
+ b.Write(buf)
+ b.Read(buf)
+ }
+ }
+}
+
+// Check that we don't compact too often. From Issue 5154.
+func BenchmarkBufferFullSmallReads(b *testing.B) {
+ buf := make([]byte, 1024)
+ for i := 0; i < b.N; i++ {
+ var b Buffer
+ b.Write(buf)
+ for b.Len()+20 < b.Cap() {
+ b.Write(buf[:10])
+ }
+ for i := 0; i < 5<<10; i++ {
+ b.Read(buf[:1])
+ b.Write(buf[:1])
+ }
+ }
+}
diff --git a/libgo/go/bytes/bytes.go b/libgo/go/bytes/bytes.go
index e3ee5b1d88a..e42f7443946 100644
--- a/libgo/go/bytes/bytes.go
+++ b/libgo/go/bytes/bytes.go
@@ -37,10 +37,6 @@ func Compare(a, b []byte) int {
return 0
}
-// Equal returns a boolean reporting whether a == b.
-// A nil argument is equivalent to an empty slice.
-func Equal(a, b []byte) bool
-
func equalPortable(a, b []byte) bool {
if len(a) != len(b) {
return false
@@ -465,10 +461,10 @@ func isSeparator(r rune) bool {
return unicode.IsSpace(r)
}
-// BUG(r): The rule Title uses for word boundaries does not handle Unicode punctuation properly.
-
// Title returns a copy of s with all Unicode letters that begin words
// mapped to their title case.
+//
+// BUG: The rule Title uses for word boundaries does not handle Unicode punctuation properly.
func Title(s []byte) []byte {
// Use a closure here to remember state.
// Hackish but effective. Depends on Map scanning in order and calling
@@ -515,6 +511,24 @@ func TrimFunc(s []byte, f func(r rune) bool) []byte {
return TrimRightFunc(TrimLeftFunc(s, f), f)
}
+// TrimPrefix returns s without the provided leading prefix string.
+// If s doesn't start with prefix, s is returned unchanged.
+func TrimPrefix(s, prefix []byte) []byte {
+ if HasPrefix(s, prefix) {
+ return s[len(prefix):]
+ }
+ return s
+}
+
+// TrimSuffix returns s without the provided trailing suffix string.
+// If s doesn't end with suffix, s is returned unchanged.
+func TrimSuffix(s, suffix []byte) []byte {
+ if HasSuffix(s, suffix) {
+ return s[:len(s)-len(suffix)]
+ }
+ return s
+}
+
// IndexFunc interprets s as a sequence of UTF-8-encoded Unicode code points.
// It returns the byte index in s of the first Unicode
// code point satisfying f(c), or -1 if none do.
@@ -553,7 +567,10 @@ func indexFunc(s []byte, f func(r rune) bool, truth bool) int {
// inverted.
func lastIndexFunc(s []byte, f func(r rune) bool, truth bool) int {
for i := len(s); i > 0; {
- r, size := utf8.DecodeLastRune(s[0:i])
+ r, size := rune(s[i-1]), 1
+ if r >= utf8.RuneSelf {
+ r, size = utf8.DecodeLastRune(s[0:i])
+ }
i -= size
if f(r) == truth {
return i
diff --git a/libgo/go/bytes/bytes_decl.go b/libgo/go/bytes/bytes_decl.go
index 5d2b9e6393a..fbf92827527 100644
--- a/libgo/go/bytes/bytes_decl.go
+++ b/libgo/go/bytes/bytes_decl.go
@@ -4,5 +4,13 @@
package bytes
+//go:noescape
+
// IndexByte returns the index of the first instance of c in s, or -1 if c is not present in s.
func IndexByte(s []byte, c byte) int // asm_$GOARCH.s
+
+//go:noescape
+
+// Equal returns a boolean reporting whether a == b.
+// A nil argument is equivalent to an empty slice.
+func Equal(a, b []byte) bool // asm_arm.s or ../runtime/asm_{386,amd64}.s
diff --git a/libgo/go/bytes/bytes_test.go b/libgo/go/bytes/bytes_test.go
index 05956d460a9..d296224ac42 100644
--- a/libgo/go/bytes/bytes_test.go
+++ b/libgo/go/bytes/bytes_test.go
@@ -61,6 +61,10 @@ var compareTests = []struct {
{[]byte("ab"), []byte("x"), -1},
{[]byte("x"), []byte("a"), 1},
{[]byte("b"), []byte("x"), -1},
+ // test runtime·memeq's chunked implementation
+ {[]byte("abcdefgh"), []byte("abcdefgh"), 0},
+ {[]byte("abcdefghi"), []byte("abcdefghi"), 0},
+ {[]byte("abcdefghi"), []byte("abcdefghj"), -1},
// nil tests
{nil, nil, 0},
{[]byte(""), nil, 0},
@@ -86,6 +90,58 @@ func TestCompare(t *testing.T) {
}
}
+func TestEqual(t *testing.T) {
+ var size = 128
+ if testing.Short() {
+ size = 32
+ }
+ a := make([]byte, size)
+ b := make([]byte, size)
+ b_init := make([]byte, size)
+ // randomish but deterministic data
+ for i := 0; i < size; i++ {
+ a[i] = byte(17 * i)
+ b_init[i] = byte(23*i + 100)
+ }
+
+ for len := 0; len <= size; len++ {
+ for x := 0; x <= size-len; x++ {
+ for y := 0; y <= size-len; y++ {
+ copy(b, b_init)
+ copy(b[y:y+len], a[x:x+len])
+ if !Equal(a[x:x+len], b[y:y+len]) || !Equal(b[y:y+len], a[x:x+len]) {
+ t.Errorf("Equal(%d, %d, %d) = false", len, x, y)
+ }
+ }
+ }
+ }
+}
+
+// make sure Equal returns false for minimally different strings. The data
+// is all zeros except for a single one in one location.
+func TestNotEqual(t *testing.T) {
+ var size = 128
+ if testing.Short() {
+ size = 32
+ }
+ a := make([]byte, size)
+ b := make([]byte, size)
+
+ for len := 0; len <= size; len++ {
+ for x := 0; x <= size-len; x++ {
+ for y := 0; y <= size-len; y++ {
+ for diffpos := x; diffpos < x+len; diffpos++ {
+ a[diffpos] = 1
+ if Equal(a[x:x+len], b[y:y+len]) || Equal(b[y:y+len], a[x:x+len]) {
+ t.Errorf("NotEqual(%d, %d, %d, %d) = true", len, x, y, diffpos)
+ }
+ a[diffpos] = 0
+ }
+ }
+ }
+ }
+}
+
var indexTests = []BinOpTest{
{"", "", 0},
{"", "a", -1},
@@ -303,10 +359,30 @@ func bmIndexByte(b *testing.B, index func([]byte, byte) int, n int) {
buf[n-1] = '\x00'
}
+func BenchmarkEqual0(b *testing.B) {
+ var buf [4]byte
+ buf1 := buf[0:0]
+ buf2 := buf[1:1]
+ for i := 0; i < b.N; i++ {
+ eq := Equal(buf1, buf2)
+ if !eq {
+ b.Fatal("bad equal")
+ }
+ }
+}
+
+func BenchmarkEqual1(b *testing.B) { bmEqual(b, Equal, 1) }
+func BenchmarkEqual6(b *testing.B) { bmEqual(b, Equal, 6) }
+func BenchmarkEqual9(b *testing.B) { bmEqual(b, Equal, 9) }
+func BenchmarkEqual15(b *testing.B) { bmEqual(b, Equal, 15) }
+func BenchmarkEqual16(b *testing.B) { bmEqual(b, Equal, 16) }
+func BenchmarkEqual20(b *testing.B) { bmEqual(b, Equal, 20) }
func BenchmarkEqual32(b *testing.B) { bmEqual(b, Equal, 32) }
func BenchmarkEqual4K(b *testing.B) { bmEqual(b, Equal, 4<<10) }
func BenchmarkEqual4M(b *testing.B) { bmEqual(b, Equal, 4<<20) }
func BenchmarkEqual64M(b *testing.B) { bmEqual(b, Equal, 64<<20) }
+func BenchmarkEqualPort1(b *testing.B) { bmEqual(b, EqualPortable, 1) }
+func BenchmarkEqualPort6(b *testing.B) { bmEqual(b, EqualPortable, 6) }
func BenchmarkEqualPort32(b *testing.B) { bmEqual(b, EqualPortable, 32) }
func BenchmarkEqualPort4K(b *testing.B) { bmEqual(b, EqualPortable, 4<<10) }
func BenchmarkEqualPortable4M(b *testing.B) { bmEqual(b, EqualPortable, 4<<20) }
@@ -794,8 +870,8 @@ func TestRunes(t *testing.T) {
}
type TrimTest struct {
- f string
- in, cutset, out string
+ f string
+ in, arg, out string
}
var trimTests = []TrimTest{
@@ -820,12 +896,17 @@ var trimTests = []TrimTest{
{"TrimRight", "", "123", ""},
{"TrimRight", "", "", ""},
{"TrimRight", "☺\xc0", "☺", "☺\xc0"},
+ {"TrimPrefix", "aabb", "a", "abb"},
+ {"TrimPrefix", "aabb", "b", "aabb"},
+ {"TrimSuffix", "aabb", "a", "aabb"},
+ {"TrimSuffix", "aabb", "b", "aab"},
}
func TestTrim(t *testing.T) {
for _, tc := range trimTests {
name := tc.f
var f func([]byte, string) []byte
+ var fb func([]byte, []byte) []byte
switch name {
case "Trim":
f = Trim
@@ -833,12 +914,21 @@ func TestTrim(t *testing.T) {
f = TrimLeft
case "TrimRight":
f = TrimRight
+ case "TrimPrefix":
+ fb = TrimPrefix
+ case "TrimSuffix":
+ fb = TrimSuffix
default:
t.Errorf("Undefined trim function %s", name)
}
- actual := string(f([]byte(tc.in), tc.cutset))
+ var actual string
+ if f != nil {
+ actual = string(f([]byte(tc.in), tc.arg))
+ } else {
+ actual = string(fb([]byte(tc.in), []byte(tc.arg)))
+ }
if actual != tc.out {
- t.Errorf("%s(%q, %q) = %q; want %q", name, tc.in, tc.cutset, actual, tc.out)
+ t.Errorf("%s(%q, %q) = %q; want %q", name, tc.in, tc.arg, actual, tc.out)
}
}
}
@@ -1059,3 +1149,10 @@ func BenchmarkFieldsFunc(b *testing.B) {
FieldsFunc(fieldsInput, unicode.IsSpace)
}
}
+
+func BenchmarkTrimSpace(b *testing.B) {
+ s := []byte(" Some text. \n")
+ for i := 0; i < b.N; i++ {
+ TrimSpace(s)
+ }
+}
diff --git a/libgo/go/bytes/equal_test.go b/libgo/go/bytes/equal_test.go
new file mode 100644
index 00000000000..1bf19a74b80
--- /dev/null
+++ b/libgo/go/bytes/equal_test.go
@@ -0,0 +1,47 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+// +build linux
+
+package bytes_test
+
+import (
+ . "bytes"
+ "syscall"
+ "testing"
+ "unsafe"
+)
+
+// This file tests the situation where memeq is checking
+// data very near to a page boundary. We want to make sure
+// equal does not read across the boundary and cause a page
+// fault where it shouldn't.
+
+// This test runs only on linux. The code being tested is
+// not OS-specific, so it does not need to be tested on all
+// operating systems.
+
+func TestEqualNearPageBoundary(t *testing.T) {
+ pagesize := syscall.Getpagesize()
+ b := make([]byte, 4*pagesize)
+ i := pagesize
+ for ; uintptr(unsafe.Pointer(&b[i]))%uintptr(pagesize) != 0; i++ {
+ }
+ syscall.Mprotect(b[i-pagesize:i], 0)
+ syscall.Mprotect(b[i+pagesize:i+2*pagesize], 0)
+ defer syscall.Mprotect(b[i-pagesize:i], syscall.PROT_READ|syscall.PROT_WRITE)
+ defer syscall.Mprotect(b[i+pagesize:i+2*pagesize], syscall.PROT_READ|syscall.PROT_WRITE)
+
+ // both of these should fault
+ //pagesize += int(b[i-1])
+ //pagesize += int(b[i+pagesize])
+
+ for j := 0; j < pagesize; j++ {
+ b[i+j] = 'A'
+ }
+ for j := 0; j <= pagesize; j++ {
+ Equal(b[i:i+j], b[i+pagesize-j:i+pagesize])
+ Equal(b[i+pagesize-j:i+pagesize], b[i:i+j])
+ }
+}
diff --git a/libgo/go/bytes/example_test.go b/libgo/go/bytes/example_test.go
index dc66b6a40f6..ad2dbc69b77 100644
--- a/libgo/go/bytes/example_test.go
+++ b/libgo/go/bytes/example_test.go
@@ -66,3 +66,20 @@ func ExampleCompare_search() {
// Found it!
}
}
+
+func ExampleTrimSuffix() {
+ var b = []byte("Hello, goodbye, etc!")
+ b = bytes.TrimSuffix(b, []byte("goodbye, etc!"))
+ b = bytes.TrimSuffix(b, []byte("gopher"))
+ b = append(b, bytes.TrimSuffix([]byte("world!"), []byte("x!"))...)
+ os.Stdout.Write(b)
+ // Output: Hello, world!
+}
+
+func ExampleTrimPrefix() {
+ var b = []byte("Goodbye,, world!")
+ b = bytes.TrimPrefix(b, []byte("Goodbye,"))
+ b = bytes.TrimPrefix(b, []byte("See ya,"))
+ fmt.Printf("Hello%s", b)
+ // Output: Hello, world!
+}
diff --git a/libgo/go/bytes/export_test.go b/libgo/go/bytes/export_test.go
index f61523e60bb..3b915d5ead8 100644
--- a/libgo/go/bytes/export_test.go
+++ b/libgo/go/bytes/export_test.go
@@ -7,3 +7,7 @@ package bytes
// Export func for testing
var IndexBytePortable = indexBytePortable
var EqualPortable = equalPortable
+
+func (b *Buffer) Cap() int {
+ return cap(b.buf)
+}
diff --git a/libgo/go/compress/bzip2/huffman.go b/libgo/go/compress/bzip2/huffman.go
index 078c1cb8954..f755019bb50 100644
--- a/libgo/go/compress/bzip2/huffman.go
+++ b/libgo/go/compress/bzip2/huffman.go
@@ -54,8 +54,6 @@ func (t huffmanTree) Decode(br *bitReader) (v uint16) {
nodeIndex = node.right
}
}
-
- panic("unreachable")
}
// newHuffmanTree builds a Huffman tree from a slice containing the code
diff --git a/libgo/go/compress/flate/deflate_test.go b/libgo/go/compress/flate/deflate_test.go
index 8f4e196b427..8c4a6d6b36f 100644
--- a/libgo/go/compress/flate/deflate_test.go
+++ b/libgo/go/compress/flate/deflate_test.go
@@ -158,7 +158,6 @@ func (b *syncBuffer) Read(p []byte) (n int, err error) {
}
<-b.ready
}
- panic("unreachable")
}
func (b *syncBuffer) signal() {
diff --git a/libgo/go/compress/flate/inflate.go b/libgo/go/compress/flate/inflate.go
index a8d64601925..beca34b4d8c 100644
--- a/libgo/go/compress/flate/inflate.go
+++ b/libgo/go/compress/flate/inflate.go
@@ -263,7 +263,6 @@ func (f *decompressor) Read(b []byte) (int, error) {
}
f.step(f)
}
- panic("unreachable")
}
func (f *decompressor) Close() error {
@@ -495,7 +494,6 @@ func (f *decompressor) huffmanBlock() {
return
}
}
- panic("unreached")
}
// copyHist copies f.copyLen bytes from f.hist (f.copyDist bytes ago) to itself.
@@ -642,7 +640,6 @@ func (f *decompressor) huffSym(h *huffmanDecoder) (int, error) {
return int(chunk >> huffmanValueShift), nil
}
}
- return 0, CorruptInputError(f.roffset)
}
// Flush any buffered output to the underlying writer.
diff --git a/libgo/go/compress/flate/token.go b/libgo/go/compress/flate/token.go
index 38aea5fa650..4d491768717 100644
--- a/libgo/go/compress/flate/token.go
+++ b/libgo/go/compress/flate/token.go
@@ -99,5 +99,4 @@ func offsetCode(off uint32) uint32 {
default:
return offsetCodes[off>>14] + 28
}
- panic("unreachable")
}
diff --git a/libgo/go/compress/gzip/gunzip.go b/libgo/go/compress/gzip/gunzip.go
index 33736f63508..1fb9b0964ce 100644
--- a/libgo/go/compress/gzip/gunzip.go
+++ b/libgo/go/compress/gzip/gunzip.go
@@ -120,7 +120,6 @@ func (z *Reader) readString() (string, error) {
return string(z.buf[0:i]), nil
}
}
- panic("not reached")
}
func (z *Reader) read2() (uint32, error) {
diff --git a/libgo/go/compress/gzip/gzip.go b/libgo/go/compress/gzip/gzip.go
index 3035dfffccf..45558b74289 100644
--- a/libgo/go/compress/gzip/gzip.go
+++ b/libgo/go/compress/gzip/gzip.go
@@ -28,7 +28,7 @@ type Writer struct {
Header
w io.Writer
level int
- compressor io.WriteCloser
+ compressor *flate.Writer
digest hash.Hash32
size uint32
closed bool
@@ -191,6 +191,28 @@ func (z *Writer) Write(p []byte) (int, error) {
return n, z.err
}
+// Flush flushes any pending compressed data to the underlying writer.
+//
+// It is useful mainly in compressed network protocols, to ensure that
+// a remote reader has enough data to reconstruct a packet. Flush does
+// not return until the data has been written. If the underlying
+// writer returns an error, Flush returns that error.
+//
+// In the terminology of the zlib library, Flush is equivalent to Z_SYNC_FLUSH.
+func (z *Writer) Flush() error {
+ if z.err != nil {
+ return z.err
+ }
+ if z.closed {
+ return nil
+ }
+ if z.compressor == nil {
+ z.Write(nil)
+ }
+ z.err = z.compressor.Flush()
+ return z.err
+}
+
// Close closes the Writer. It does not close the underlying io.Writer.
func (z *Writer) Close() error {
if z.err != nil {
diff --git a/libgo/go/compress/gzip/gzip_test.go b/libgo/go/compress/gzip/gzip_test.go
index 6f7b5936449..4d1af94381c 100644
--- a/libgo/go/compress/gzip/gzip_test.go
+++ b/libgo/go/compress/gzip/gzip_test.go
@@ -157,3 +157,43 @@ func TestLatin1RoundTrip(t *testing.T) {
}
}
}
+
+func TestWriterFlush(t *testing.T) {
+ buf := new(bytes.Buffer)
+
+ w := NewWriter(buf)
+ w.Comment = "comment"
+ w.Extra = []byte("extra")
+ w.ModTime = time.Unix(1e8, 0)
+ w.Name = "name"
+
+ n0 := buf.Len()
+ if n0 != 0 {
+ t.Fatalf("buffer size = %d before writes; want 0", n0)
+ }
+
+ if err := w.Flush(); err != nil {
+ t.Fatal(err)
+ }
+
+ n1 := buf.Len()
+ if n1 == 0 {
+ t.Fatal("no data after first flush")
+ }
+
+ w.Write([]byte("x"))
+
+ n2 := buf.Len()
+ if n1 != n2 {
+ t.Fatalf("after writing a single byte, size changed from %d to %d; want no change", n1, n2)
+ }
+
+ if err := w.Flush(); err != nil {
+ t.Fatal(err)
+ }
+
+ n3 := buf.Len()
+ if n2 == n3 {
+ t.Fatal("Flush didn't flush any data")
+ }
+}
diff --git a/libgo/go/compress/lzw/reader.go b/libgo/go/compress/lzw/reader.go
index 0ed742c8977..efbc758f94b 100644
--- a/libgo/go/compress/lzw/reader.go
+++ b/libgo/go/compress/lzw/reader.go
@@ -121,7 +121,6 @@ func (d *decoder) Read(b []byte) (int, error) {
}
d.decode()
}
- panic("unreachable")
}
// decode decompresses bytes from r and leaves them in d.toRead.
@@ -203,7 +202,6 @@ func (d *decoder) decode() {
return
}
}
- panic("unreachable")
}
func (d *decoder) flush() {
diff --git a/libgo/go/container/heap/example_test.go b/libgo/go/container/heap/example_test.go
deleted file mode 100644
index 70f654a0079..00000000000
--- a/libgo/go/container/heap/example_test.go
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This example demonstrates a priority queue built using the heap interface.
-package heap_test
-
-import (
- "container/heap"
- "fmt"
-)
-
-// An Item is something we manage in a priority queue.
-type Item struct {
- value string // The value of the item; arbitrary.
- priority int // The priority of the item in the queue.
- // The index is needed by changePriority and is maintained by the heap.Interface methods.
- index int // The index of the item in the heap.
-}
-
-// A PriorityQueue implements heap.Interface and holds Items.
-type PriorityQueue []*Item
-
-func (pq PriorityQueue) Len() int { return len(pq) }
-
-func (pq PriorityQueue) Less(i, j int) bool {
- // We want Pop to give us the highest, not lowest, priority so we use greater than here.
- return pq[i].priority > pq[j].priority
-}
-
-func (pq PriorityQueue) Swap(i, j int) {
- pq[i], pq[j] = pq[j], pq[i]
- pq[i].index = i
- pq[j].index = j
-}
-
-func (pq *PriorityQueue) Push(x interface{}) {
- // Push and Pop use pointer receivers because they modify the slice's length,
- // not just its contents.
- n := len(*pq)
- item := x.(*Item)
- item.index = n
- *pq = append(*pq, item)
-}
-
-func (pq *PriorityQueue) Pop() interface{} {
- a := *pq
- n := len(a)
- item := a[n-1]
- item.index = -1 // for safety
- *pq = a[0 : n-1]
- return item
-}
-
-// update is not used by the example but shows how to take the top item from
-// the queue, update its priority and value, and put it back.
-func (pq *PriorityQueue) update(value string, priority int) {
- item := heap.Pop(pq).(*Item)
- item.value = value
- item.priority = priority
- heap.Push(pq, item)
-}
-
-// changePriority is not used by the example but shows how to change the
-// priority of an arbitrary item.
-func (pq *PriorityQueue) changePriority(item *Item, priority int) {
- heap.Remove(pq, item.index)
- item.priority = priority
- heap.Push(pq, item)
-}
-
-// This example pushes 10 items into a PriorityQueue and takes them out in
-// order of priority.
-func Example() {
- const nItem = 10
- // Random priorities for the items (a permutation of 0..9, times 11)).
- priorities := [nItem]int{
- 77, 22, 44, 55, 11, 88, 33, 99, 00, 66,
- }
- values := [nItem]string{
- "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
- }
- // Create a priority queue and put some items in it.
- pq := make(PriorityQueue, 0, nItem)
- for i := 0; i < cap(pq); i++ {
- item := &Item{
- value: values[i],
- priority: priorities[i],
- }
- heap.Push(&pq, item)
- }
- // Take the items out; should arrive in decreasing priority order.
- // For example, the highest priority (99) is the seventh item, so output starts with 99:"seven".
- for i := 0; i < nItem; i++ {
- item := heap.Pop(&pq).(*Item)
- fmt.Printf("%.2d:%s ", item.priority, item.value)
- }
- // Output:
- // 99:seven 88:five 77:zero 66:nine 55:three 44:two 33:six 22:one 11:four 00:eight
-}
diff --git a/libgo/go/container/heap/heap.go b/libgo/go/container/heap/heap.go
index bbaf40a989d..c37e50e3c40 100644
--- a/libgo/go/container/heap/heap.go
+++ b/libgo/go/container/heap/heap.go
@@ -4,13 +4,13 @@
// Package heap provides heap operations for any type that implements
// heap.Interface. A heap is a tree with the property that each node is the
-// highest-valued node in its subtree.
+// minimum-valued node in its subtree.
//
// A heap is a common way to implement a priority queue. To build a priority
// queue, implement the Heap interface with the (negative) priority as the
// ordering for the Less method, so Push adds items while Pop removes the
// highest-priority item from the queue. The Examples include such an
-// implementation; the file example_test.go has the complete source.
+// implementation; the file example_pq_test.go has the complete source.
//
package heap
@@ -90,7 +90,7 @@ func up(h Interface, j int) {
func down(h Interface, i, n int) {
for {
j1 := 2*i + 1
- if j1 >= n {
+ if j1 >= n || j1 < 0 { // j1 < 0 after int overflow
break
}
j := j1 // left child
diff --git a/libgo/go/container/heap/heap_test.go b/libgo/go/container/heap/heap_test.go
index 73f33e8d2cf..274d587d874 100644
--- a/libgo/go/container/heap/heap_test.go
+++ b/libgo/go/container/heap/heap_test.go
@@ -2,10 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package heap_test
+package heap
import (
- . "container/heap"
"testing"
)
diff --git a/libgo/go/crypto/cipher/cbc.go b/libgo/go/crypto/cipher/cbc.go
index 6fab9b42131..913a5643f22 100644
--- a/libgo/go/crypto/cipher/cbc.go
+++ b/libgo/go/crypto/cipher/cbc.go
@@ -42,6 +42,12 @@ func NewCBCEncrypter(b Block, iv []byte) BlockMode {
func (x *cbcEncrypter) BlockSize() int { return x.blockSize }
func (x *cbcEncrypter) CryptBlocks(dst, src []byte) {
+ if len(src)%x.blockSize != 0 {
+ panic("crypto/cipher: input not full blocks")
+ }
+ if len(dst) < len(src) {
+ panic("crypto/cipher: output smaller than input")
+ }
for len(src) > 0 {
for i := 0; i < x.blockSize; i++ {
x.iv[i] ^= src[i]
@@ -70,6 +76,12 @@ func NewCBCDecrypter(b Block, iv []byte) BlockMode {
func (x *cbcDecrypter) BlockSize() int { return x.blockSize }
func (x *cbcDecrypter) CryptBlocks(dst, src []byte) {
+ if len(src)%x.blockSize != 0 {
+ panic("crypto/cipher: input not full blocks")
+ }
+ if len(dst) < len(src) {
+ panic("crypto/cipher: output smaller than input")
+ }
for len(src) > 0 {
x.b.Decrypt(x.tmp, src[:x.blockSize])
for i := 0; i < x.blockSize; i++ {
diff --git a/libgo/go/crypto/cipher/cipher_test.go b/libgo/go/crypto/cipher/cipher_test.go
new file mode 100644
index 00000000000..8da5bce93ff
--- /dev/null
+++ b/libgo/go/crypto/cipher/cipher_test.go
@@ -0,0 +1,36 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cipher_test
+
+import (
+ "crypto/aes"
+ "crypto/cipher"
+ "testing"
+)
+
+func TestCryptBlocks(t *testing.T) {
+ buf := make([]byte, 16)
+ block, _ := aes.NewCipher(buf)
+
+ mode := cipher.NewCBCDecrypter(block, buf)
+ mustPanic(t, "crypto/cipher: input not full blocks", func() { mode.CryptBlocks(buf, buf[:3]) })
+ mustPanic(t, "crypto/cipher: output smaller than input", func() { mode.CryptBlocks(buf[:3], buf) })
+
+ mode = cipher.NewCBCEncrypter(block, buf)
+ mustPanic(t, "crypto/cipher: input not full blocks", func() { mode.CryptBlocks(buf, buf[:3]) })
+ mustPanic(t, "crypto/cipher: output smaller than input", func() { mode.CryptBlocks(buf[:3], buf) })
+}
+
+func mustPanic(t *testing.T, msg string, f func()) {
+ defer func() {
+ err := recover()
+ if err == nil {
+ t.Errorf("function did not panic, wanted %q", msg)
+ } else if err != msg {
+ t.Errorf("got panic %v, wanted %q", err, msg)
+ }
+ }()
+ f()
+}
diff --git a/libgo/go/crypto/cipher/example_test.go b/libgo/go/crypto/cipher/example_test.go
index e0027cac23b..373f6791be4 100644
--- a/libgo/go/crypto/cipher/example_test.go
+++ b/libgo/go/crypto/cipher/example_test.go
@@ -233,7 +233,7 @@ func ExampleStreamReader() {
}
defer outFile.Close()
- reader := &cipher.StreamReader{stream, inFile}
+ reader := &cipher.StreamReader{S: stream, R: inFile}
// Copy the input file to the output file, decrypting as we go.
if _, err := io.Copy(outFile, reader); err != nil {
panic(err)
@@ -270,7 +270,7 @@ func ExampleStreamWriter() {
}
defer outFile.Close()
- writer := &cipher.StreamWriter{stream, outFile, nil}
+ writer := &cipher.StreamWriter{S: stream, W: outFile}
// Copy the input file to the output file, encrypting as we go.
if _, err := io.Copy(writer, inFile); err != nil {
panic(err)
diff --git a/libgo/go/crypto/dsa/dsa.go b/libgo/go/crypto/dsa/dsa.go
index 05766a2f136..5a2a65744ed 100644
--- a/libgo/go/crypto/dsa/dsa.go
+++ b/libgo/go/crypto/dsa/dsa.go
@@ -144,8 +144,6 @@ GeneratePrimes:
params.G = g
return
}
-
- panic("unreachable")
}
// GenerateKey generates a public&private key pair. The Parameters of the
diff --git a/libgo/go/crypto/dsa/dsa_test.go b/libgo/go/crypto/dsa/dsa_test.go
index 177aa444dfd..568416d0dfb 100644
--- a/libgo/go/crypto/dsa/dsa_test.go
+++ b/libgo/go/crypto/dsa/dsa_test.go
@@ -63,8 +63,9 @@ func testParameterGeneration(t *testing.T, sizes ParameterSizes, L, N int) {
}
func TestParameterGeneration(t *testing.T) {
- // This test is too slow to run all the time.
- return
+ if testing.Short() {
+ t.Skip("skipping parameter generation test in short mode")
+ }
testParameterGeneration(t, L1024N160, 1024, 160)
testParameterGeneration(t, L2048N224, 2048, 224)
diff --git a/libgo/go/crypto/ecdsa/ecdsa.go b/libgo/go/crypto/ecdsa/ecdsa.go
index 512d20c635c..25500022939 100644
--- a/libgo/go/crypto/ecdsa/ecdsa.go
+++ b/libgo/go/crypto/ecdsa/ecdsa.go
@@ -49,7 +49,7 @@ func randFieldElement(c elliptic.Curve, rand io.Reader) (k *big.Int, err error)
return
}
-// GenerateKey generates a public&private key pair.
+// GenerateKey generates a public and private key pair.
func GenerateKey(c elliptic.Curve, rand io.Reader) (priv *PrivateKey, err error) {
k, err := randFieldElement(c, rand)
if err != nil {
diff --git a/libgo/go/crypto/md5/gen.go b/libgo/go/crypto/md5/gen.go
index 966bdae267b..275b4aeea39 100644
--- a/libgo/go/crypto/md5/gen.go
+++ b/libgo/go/crypto/md5/gen.go
@@ -161,6 +161,11 @@ var data = Data{
}
var program = `
+// DO NOT EDIT.
+// Generate with: go run gen.go{{if .Full}} -full{{end}} | gofmt >md5block.go
+
+// +build !amd64
+
package md5
import (
@@ -186,6 +191,16 @@ import (
}
{{end}}
+const x86 = runtime.GOARCH == "amd64" || runtime.GOARCH == "386"
+
+var littleEndian bool
+
+func init() {
+ x := uint32(0x04030201)
+ y := [4]byte{0x1, 0x2, 0x3, 0x4}
+ littleEndian = *(*[4]byte)(unsafe.Pointer(&x)) == y
+}
+
func block(dig *digest, p []byte) {
a := dig.s[0]
b := dig.s[1]
@@ -197,13 +212,13 @@ func block(dig *digest, p []byte) {
aa, bb, cc, dd := a, b, c, d
// This is a constant condition - it is not evaluated on each iteration.
- if runtime.GOARCH == "amd64" || runtime.GOARCH == "386" {
+ if x86 {
// MD5 was designed so that x86 processors can just iterate
// over the block data directly as uint32s, and we generate
// less code and run 1.3x faster if we take advantage of that.
// My apologies.
X = (*[16]uint32)(unsafe.Pointer(&p[0]))
- } else if uintptr(unsafe.Pointer(&p[0]))&(unsafe.Alignof(uint32(0))-1) == 0 {
+ } else if littleEndian && uintptr(unsafe.Pointer(&p[0]))&(unsafe.Alignof(uint32(0))-1) == 0 {
X = (*[16]uint32)(unsafe.Pointer(&p[0]))
} else {
X = &xbuf
diff --git a/libgo/go/crypto/md5/md5_test.go b/libgo/go/crypto/md5/md5_test.go
index cac39ad054b..3ef4519b9ad 100644
--- a/libgo/go/crypto/md5/md5_test.go
+++ b/libgo/go/crypto/md5/md5_test.go
@@ -2,10 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package md5_test
+package md5
import (
- "crypto/md5"
"fmt"
"io"
"testing"
@@ -54,7 +53,7 @@ var golden = []md5Test{
func TestGolden(t *testing.T) {
for i := 0; i < len(golden); i++ {
g := golden[i]
- c := md5.New()
+ c := New()
buf := make([]byte, len(g.in)+4)
for j := 0; j < 3+4; j++ {
if j < 2 {
@@ -79,14 +78,14 @@ func TestGolden(t *testing.T) {
}
func ExampleNew() {
- h := md5.New()
+ h := New()
io.WriteString(h, "The fog is getting thicker!")
io.WriteString(h, "And Leon's getting laaarger!")
fmt.Printf("%x", h.Sum(nil))
// Output: e2c569be17396eca2a2e3c11578123ed
}
-var bench = md5.New()
+var bench = New()
var buf = make([]byte, 8192+1)
var sum = make([]byte, bench.Size())
diff --git a/libgo/go/crypto/md5/md5block.go b/libgo/go/crypto/md5/md5block.go
index 0ca42177403..a376fbee99b 100644
--- a/libgo/go/crypto/md5/md5block.go
+++ b/libgo/go/crypto/md5/md5block.go
@@ -1,3 +1,8 @@
+// DO NOT EDIT.
+// Generate with: go run gen.go -full | gofmt >md5block.go
+
+// +build !amd64,!386
+
package md5
import (
diff --git a/libgo/go/crypto/md5/md5block_decl.go b/libgo/go/crypto/md5/md5block_decl.go
new file mode 100644
index 00000000000..14190c6ff29
--- /dev/null
+++ b/libgo/go/crypto/md5/md5block_decl.go
@@ -0,0 +1,9 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build amd64 386
+
+package md5
+
+func block(dig *digest, p []byte)
diff --git a/libgo/go/crypto/rand/util.go b/libgo/go/crypto/rand/util.go
index 50e5b162bdd..0cd5e0e022f 100644
--- a/libgo/go/crypto/rand/util.go
+++ b/libgo/go/crypto/rand/util.go
@@ -98,12 +98,13 @@ func Prime(rand io.Reader, bits int) (p *big.Int, err error) {
return
}
}
-
- return
}
-// Int returns a uniform random value in [0, max).
+// Int returns a uniform random value in [0, max). It panics if max <= 0.
func Int(rand io.Reader, max *big.Int) (n *big.Int, err error) {
+ if max.Sign() <= 0 {
+ panic("crypto/rand: argument to Int is <= 0")
+ }
k := (max.BitLen() + 7) / 8
// b is the number of bits in the most significant byte of max.
@@ -130,6 +131,4 @@ func Int(rand io.Reader, max *big.Int) (n *big.Int, err error) {
return
}
}
-
- return
}
diff --git a/libgo/go/crypto/rc4/rc4.go b/libgo/go/crypto/rc4/rc4.go
index 1bb278f74a4..3d717c63b0c 100644
--- a/libgo/go/crypto/rc4/rc4.go
+++ b/libgo/go/crypto/rc4/rc4.go
@@ -13,7 +13,7 @@ import "strconv"
// A Cipher is an instance of RC4 using a particular key.
type Cipher struct {
- s [256]byte
+ s [256]uint32
i, j uint8
}
@@ -32,27 +32,16 @@ func NewCipher(key []byte) (*Cipher, error) {
}
var c Cipher
for i := 0; i < 256; i++ {
- c.s[i] = uint8(i)
+ c.s[i] = uint32(i)
}
var j uint8 = 0
for i := 0; i < 256; i++ {
- j += c.s[i] + key[i%k]
+ j += uint8(c.s[i]) + key[i%k]
c.s[i], c.s[j] = c.s[j], c.s[i]
}
return &c, nil
}
-// XORKeyStream sets dst to the result of XORing src with the key stream.
-// Dst and src may be the same slice but otherwise should not overlap.
-func (c *Cipher) XORKeyStream(dst, src []byte) {
- for i := range src {
- c.i += 1
- c.j += c.s[c.i]
- c.s[c.i], c.s[c.j] = c.s[c.j], c.s[c.i]
- dst[i] = src[i] ^ c.s[c.s[c.i]+c.s[c.j]]
- }
-}
-
// Reset zeros the key data so that it will no longer appear in the
// process's memory.
func (c *Cipher) Reset() {
diff --git a/libgo/go/crypto/rc4/rc4_asm.go b/libgo/go/crypto/rc4/rc4_asm.go
new file mode 100644
index 00000000000..c582a4488b8
--- /dev/null
+++ b/libgo/go/crypto/rc4/rc4_asm.go
@@ -0,0 +1,18 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build amd64 arm 386
+
+package rc4
+
+func xorKeyStream(dst, src *byte, n int, state *[256]uint32, i, j *uint8)
+
+// XORKeyStream sets dst to the result of XORing src with the key stream.
+// Dst and src may be the same slice but otherwise should not overlap.
+func (c *Cipher) XORKeyStream(dst, src []byte) {
+ if len(src) == 0 {
+ return
+ }
+ xorKeyStream(&dst[0], &src[0], len(src), &c.s, &c.i, &c.j)
+}
diff --git a/libgo/go/crypto/rc4/rc4_ref.go b/libgo/go/crypto/rc4/rc4_ref.go
new file mode 100644
index 00000000000..13d52b95dd3
--- /dev/null
+++ b/libgo/go/crypto/rc4/rc4_ref.go
@@ -0,0 +1,20 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !amd64,!arm,!386
+
+package rc4
+
+// XORKeyStream sets dst to the result of XORing src with the key stream.
+// Dst and src may be the same slice but otherwise should not overlap.
+func (c *Cipher) XORKeyStream(dst, src []byte) {
+ i, j := c.i, c.j
+ for k, v := range src {
+ i += 1
+ j += uint8(c.s[i])
+ c.s[i], c.s[j] = c.s[j], c.s[i]
+ dst[k] = v ^ byte(c.s[byte(c.s[i]+c.s[j])])
+ }
+ c.i, c.j = i, j
+}
diff --git a/libgo/go/crypto/rc4/rc4_test.go b/libgo/go/crypto/rc4/rc4_test.go
index 6265d9408f4..7b4df6791d9 100644
--- a/libgo/go/crypto/rc4/rc4_test.go
+++ b/libgo/go/crypto/rc4/rc4_test.go
@@ -5,6 +5,8 @@
package rc4
import (
+ "bytes"
+ "fmt"
"testing"
)
@@ -37,23 +39,124 @@ var golden = []rc4Test{
[]byte{0x57, 0x69, 0x6b, 0x69},
[]byte{0x60, 0x44, 0xdb, 0x6d, 0x41, 0xb7},
},
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{
+ 0xde, 0x18, 0x89, 0x41, 0xa3, 0x37, 0x5d, 0x3a,
+ 0x8a, 0x06, 0x1e, 0x67, 0x57, 0x6e, 0x92, 0x6d,
+ 0xc7, 0x1a, 0x7f, 0xa3, 0xf0, 0xcc, 0xeb, 0x97,
+ 0x45, 0x2b, 0x4d, 0x32, 0x27, 0x96, 0x5f, 0x9e,
+ 0xa8, 0xcc, 0x75, 0x07, 0x6d, 0x9f, 0xb9, 0xc5,
+ 0x41, 0x7a, 0xa5, 0xcb, 0x30, 0xfc, 0x22, 0x19,
+ 0x8b, 0x34, 0x98, 0x2d, 0xbb, 0x62, 0x9e, 0xc0,
+ 0x4b, 0x4f, 0x8b, 0x05, 0xa0, 0x71, 0x08, 0x50,
+ 0x92, 0xa0, 0xc3, 0x58, 0x4a, 0x48, 0xe4, 0xa3,
+ 0x0a, 0x39, 0x7b, 0x8a, 0xcd, 0x1d, 0x00, 0x9e,
+ 0xc8, 0x7d, 0x68, 0x11, 0xf2, 0x2c, 0xf4, 0x9c,
+ 0xa3, 0xe5, 0x93, 0x54, 0xb9, 0x45, 0x15, 0x35,
+ 0xa2, 0x18, 0x7a, 0x86, 0x42, 0x6c, 0xca, 0x7d,
+ 0x5e, 0x82, 0x3e, 0xba, 0x00, 0x44, 0x12, 0x67,
+ 0x12, 0x57, 0xb8, 0xd8, 0x60, 0xae, 0x4c, 0xbd,
+ 0x4c, 0x49, 0x06, 0xbb, 0xc5, 0x35, 0xef, 0xe1,
+ 0x58, 0x7f, 0x08, 0xdb, 0x33, 0x95, 0x5c, 0xdb,
+ 0xcb, 0xad, 0x9b, 0x10, 0xf5, 0x3f, 0xc4, 0xe5,
+ 0x2c, 0x59, 0x15, 0x65, 0x51, 0x84, 0x87, 0xfe,
+ 0x08, 0x4d, 0x0e, 0x3f, 0x03, 0xde, 0xbc, 0xc9,
+ 0xda, 0x1c, 0xe9, 0x0d, 0x08, 0x5c, 0x2d, 0x8a,
+ 0x19, 0xd8, 0x37, 0x30, 0x86, 0x16, 0x36, 0x92,
+ 0x14, 0x2b, 0xd8, 0xfc, 0x5d, 0x7a, 0x73, 0x49,
+ 0x6a, 0x8e, 0x59, 0xee, 0x7e, 0xcf, 0x6b, 0x94,
+ 0x06, 0x63, 0xf4, 0xa6, 0xbe, 0xe6, 0x5b, 0xd2,
+ 0xc8, 0x5c, 0x46, 0x98, 0x6c, 0x1b, 0xef, 0x34,
+ 0x90, 0xd3, 0x7b, 0x38, 0xda, 0x85, 0xd3, 0x2e,
+ 0x97, 0x39, 0xcb, 0x23, 0x4a, 0x2b, 0xe7, 0x40,
+ },
+ },
+}
+
+func testEncrypt(t *testing.T, desc string, c *Cipher, src, expect []byte) {
+ dst := make([]byte, len(src))
+ c.XORKeyStream(dst, src)
+ for i, v := range dst {
+ if v != expect[i] {
+ t.Fatalf("%s: mismatch at byte %d:\nhave %x\nwant %x", desc, i, dst, expect)
+ }
+ }
}
func TestGolden(t *testing.T) {
- for i := 0; i < len(golden); i++ {
- g := golden[i]
- c, err := NewCipher(g.key)
- if err != nil {
- t.Errorf("Failed to create cipher at golden index %d", i)
- return
+ for gi, g := range golden {
+ data := make([]byte, len(g.keystream))
+ for i := range data {
+ data[i] = byte(i)
}
- keystream := make([]byte, len(g.keystream))
- c.XORKeyStream(keystream, keystream)
- for j, v := range keystream {
- if g.keystream[j] != v {
- t.Errorf("Failed at golden index %d", i)
- break
+
+ expect := make([]byte, len(g.keystream))
+ for i := range expect {
+ expect[i] = byte(i) ^ g.keystream[i]
+ }
+
+ for size := 1; size <= len(g.keystream); size++ {
+ c, err := NewCipher(g.key)
+ if err != nil {
+ t.Fatalf("#%d: NewCipher: %v", gi, err)
+ }
+
+ off := 0
+ for off < len(g.keystream) {
+ n := len(g.keystream) - off
+ if n > size {
+ n = size
+ }
+ desc := fmt.Sprintf("#%d@[%d:%d]", gi, off, off+n)
+ testEncrypt(t, desc, c, data[off:off+n], expect[off:off+n])
+ off += n
}
}
}
}
+
+func TestBlock(t *testing.T) {
+ c1a, _ := NewCipher(golden[0].key)
+ c1b, _ := NewCipher(golden[1].key)
+ data1 := make([]byte, 1<<20)
+ for i := range data1 {
+ c1a.XORKeyStream(data1[i:i+1], data1[i:i+1])
+ c1b.XORKeyStream(data1[i:i+1], data1[i:i+1])
+ }
+
+ c2a, _ := NewCipher(golden[0].key)
+ c2b, _ := NewCipher(golden[1].key)
+ data2 := make([]byte, 1<<20)
+ c2a.XORKeyStream(data2, data2)
+ c2b.XORKeyStream(data2, data2)
+
+ if !bytes.Equal(data1, data2) {
+ t.Fatalf("bad block")
+ }
+}
+
+func benchmark(b *testing.B, size int64) {
+ buf := make([]byte, size)
+ c, err := NewCipher(golden[0].key)
+ if err != nil {
+ panic(err)
+ }
+ b.SetBytes(size)
+
+ for i := 0; i < b.N; i++ {
+ c.XORKeyStream(buf, buf)
+ }
+}
+
+func BenchmarkRC4_128(b *testing.B) {
+ benchmark(b, 128)
+}
+
+func BenchmarkRC4_1K(b *testing.B) {
+ benchmark(b, 1024)
+}
+
+func BenchmarkRC4_8K(b *testing.B) {
+ benchmark(b, 8096)
+}
diff --git a/libgo/go/crypto/rsa/rsa.go b/libgo/go/crypto/rsa/rsa.go
index 543070f90fb..f56fb37ee54 100644
--- a/libgo/go/crypto/rsa/rsa.go
+++ b/libgo/go/crypto/rsa/rsa.go
@@ -150,6 +150,20 @@ func GenerateMultiPrimeKey(random io.Reader, nprimes int, bits int) (priv *Priva
NextSetOfPrimes:
for {
todo := bits
+ // crypto/rand should set the top two bits in each prime.
+ // Thus each prime has the form
+ // p_i = 2^bitlen(p_i) × 0.11... (in base 2).
+ // And the product is:
+ // P = 2^todo × α
+ // where α is the product of nprimes numbers of the form 0.11...
+ //
+ // If α < 1/2 (which can happen for nprimes > 2), we need to
+ // shift todo to compensate for lost bits: the mean value of 0.11...
+ // is 7/8, so todo + shift - nprimes * log2(7/8) ~= bits - 1/2
+ // will give good results.
+ if nprimes >= 7 {
+ todo += (nprimes - 2) / 5
+ }
for i := 0; i < nprimes; i++ {
primes[i], err = rand.Prime(random, todo/(nprimes-i))
if err != nil {
@@ -176,8 +190,9 @@ NextSetOfPrimes:
totient.Mul(totient, pminus1)
}
if n.BitLen() != bits {
- // This should never happen because crypto/rand should
- // set the top two bits in each prime.
+ // This should never happen for nprimes == 2 because
+ // crypto/rand should set the top two bits in each prime.
+ // For nprimes > 2 we hope it does not happen often.
continue NextSetOfPrimes
}
@@ -188,7 +203,9 @@ NextSetOfPrimes:
g.GCD(priv.D, y, e, totient)
if g.Cmp(bigOne) == 0 {
- priv.D.Add(priv.D, totient)
+ if priv.D.Sign() < 0 {
+ priv.D.Add(priv.D, totient)
+ }
priv.Primes = primes
priv.N = n
diff --git a/libgo/go/crypto/rsa/rsa_test.go b/libgo/go/crypto/rsa/rsa_test.go
index 9be22a8f0bf..ffd96e62f64 100644
--- a/libgo/go/crypto/rsa/rsa_test.go
+++ b/libgo/go/crypto/rsa/rsa_test.go
@@ -28,11 +28,11 @@ func TestKeyGeneration(t *testing.T) {
}
func Test3PrimeKeyGeneration(t *testing.T) {
+ size := 768
if testing.Short() {
- return
+ size = 256
}
- size := 768
priv, err := GenerateMultiPrimeKey(rand.Reader, 3, size)
if err != nil {
t.Errorf("failed to generate key")
@@ -41,11 +41,11 @@ func Test3PrimeKeyGeneration(t *testing.T) {
}
func Test4PrimeKeyGeneration(t *testing.T) {
+ size := 768
if testing.Short() {
- return
+ size = 256
}
- size := 768
priv, err := GenerateMultiPrimeKey(rand.Reader, 4, size)
if err != nil {
t.Errorf("failed to generate key")
@@ -53,6 +53,24 @@ func Test4PrimeKeyGeneration(t *testing.T) {
testKeyBasics(t, priv)
}
+func TestNPrimeKeyGeneration(t *testing.T) {
+ primeSize := 64
+ maxN := 24
+ if testing.Short() {
+ primeSize = 16
+ maxN = 16
+ }
+ // Test that generation of N-prime keys works for N > 4.
+ for n := 5; n < maxN; n++ {
+ priv, err := GenerateMultiPrimeKey(rand.Reader, n, 64+n*primeSize)
+ if err == nil {
+ testKeyBasics(t, priv)
+ } else {
+ t.Errorf("failed to generate %d-prime key", n)
+ }
+ }
+}
+
func TestGnuTLSKey(t *testing.T) {
// This is a key generated by `certtool --generate-privkey --bits 128`.
// It's such that de ≢ 1 mod φ(n), but is congruent mod the order of
@@ -75,6 +93,9 @@ func testKeyBasics(t *testing.T, priv *PrivateKey) {
if err := priv.Validate(); err != nil {
t.Errorf("Validate() failed: %s", err)
}
+ if priv.D.Cmp(priv.N) > 0 {
+ t.Errorf("private exponent too large")
+ }
pub := &priv.PublicKey
m := big.NewInt(42)
diff --git a/libgo/go/crypto/sha1/sha1_test.go b/libgo/go/crypto/sha1/sha1_test.go
index 58541127784..57cd4313eb2 100644
--- a/libgo/go/crypto/sha1/sha1_test.go
+++ b/libgo/go/crypto/sha1/sha1_test.go
@@ -4,10 +4,9 @@
// SHA1 hash algorithm. See RFC 3174.
-package sha1_test
+package sha1
import (
- "crypto/sha1"
"fmt"
"io"
"testing"
@@ -55,7 +54,7 @@ var golden = []sha1Test{
func TestGolden(t *testing.T) {
for i := 0; i < len(golden); i++ {
g := golden[i]
- c := sha1.New()
+ c := New()
for j := 0; j < 3; j++ {
if j < 2 {
io.WriteString(c, g.in)
@@ -74,13 +73,13 @@ func TestGolden(t *testing.T) {
}
func ExampleNew() {
- h := sha1.New()
+ h := New()
io.WriteString(h, "His money is twice tainted: 'taint yours and 'taint mine.")
fmt.Printf("% x", h.Sum(nil))
// Output: 59 7f 6a 54 00 10 f9 4c 15 d7 18 06 a9 9a 2c 87 10 e7 47 bd
}
-var bench = sha1.New()
+var bench = New()
var buf = make([]byte, 8192)
func benchmarkSize(b *testing.B, size int) {
diff --git a/libgo/go/crypto/sha1/sha1block.go b/libgo/go/crypto/sha1/sha1block.go
index 1c9507c68e5..92224fc0ef8 100644
--- a/libgo/go/crypto/sha1/sha1block.go
+++ b/libgo/go/crypto/sha1/sha1block.go
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build !amd64,!386
+
// SHA1 block step.
// In its own file so that a faster assembly or C version
// can be substituted easily.
diff --git a/libgo/go/crypto/sha1/sha1block_decl.go b/libgo/go/crypto/sha1/sha1block_decl.go
new file mode 100644
index 00000000000..3512a582991
--- /dev/null
+++ b/libgo/go/crypto/sha1/sha1block_decl.go
@@ -0,0 +1,9 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build amd64 386
+
+package sha1
+
+func block(dig *digest, p []byte)
diff --git a/libgo/go/crypto/tls/common.go b/libgo/go/crypto/tls/common.go
index a888df762db..f86c90de74d 100644
--- a/libgo/go/crypto/tls/common.go
+++ b/libgo/go/crypto/tls/common.go
@@ -204,7 +204,24 @@ type Config struct {
// connections using that key are compromised.
SessionTicketKey [32]byte
- serverInitOnce sync.Once
+ serverInitOnce sync.Once // guards calling (*Config).serverInit
+}
+
+func (c *Config) serverInit() {
+ if c.SessionTicketsDisabled {
+ return
+ }
+
+ // If the key has already been set then we have nothing to do.
+ for _, b := range c.SessionTicketKey {
+ if b != 0 {
+ return
+ }
+ }
+
+ if _, err := io.ReadFull(c.rand(), c.SessionTicketKey[:]); err != nil {
+ c.SessionTicketsDisabled = true
+ }
}
func (c *Config) rand() io.Reader {
diff --git a/libgo/go/crypto/tls/generate_cert.go b/libgo/go/crypto/tls/generate_cert.go
index 84be5bfd856..215644d2435 100644
--- a/libgo/go/crypto/tls/generate_cert.go
+++ b/libgo/go/crypto/tls/generate_cert.go
@@ -16,36 +16,80 @@ import (
"crypto/x509/pkix"
"encoding/pem"
"flag"
+ "fmt"
"log"
"math/big"
+ "net"
"os"
+ "strings"
"time"
)
-var hostName *string = flag.String("host", "127.0.0.1", "Hostname to generate a certificate for")
+var (
+ host = flag.String("host", "", "Comma-separated hostnames and IPs to generate a certificate for")
+ validFrom = flag.String("start-date", "", "Creation date formatted as Jan 1 15:04:05 2011")
+ validFor = flag.Duration("duration", 365*24*time.Hour, "Duration that certificate is valid for")
+ isCA = flag.Bool("ca", false, "whether this cert should be its own Certificate Authority")
+ rsaBits = flag.Int("rsa-bits", 1024, "Size of RSA key to generate")
+)
func main() {
flag.Parse()
- priv, err := rsa.GenerateKey(rand.Reader, 1024)
+ if len(*host) == 0 {
+ log.Fatalf("Missing required --host parameter")
+ }
+
+ priv, err := rsa.GenerateKey(rand.Reader, *rsaBits)
if err != nil {
log.Fatalf("failed to generate private key: %s", err)
return
}
- now := time.Now()
+ var notBefore time.Time
+ if len(*validFrom) == 0 {
+ notBefore = time.Now()
+ } else {
+ notBefore, err = time.Parse("Jan 2 15:04:05 2006", *validFrom)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to parse creation date: %s\n", err)
+ os.Exit(1)
+ }
+ }
+
+ notAfter := notBefore.Add(*validFor)
+
+ // end of ASN.1 time
+ endOfTime := time.Date(2049, 12, 31, 23, 59, 59, 0, time.UTC)
+ if notAfter.After(endOfTime) {
+ notAfter = endOfTime
+ }
template := x509.Certificate{
SerialNumber: new(big.Int).SetInt64(0),
Subject: pkix.Name{
- CommonName: *hostName,
Organization: []string{"Acme Co"},
},
- NotBefore: now.Add(-5 * time.Minute).UTC(),
- NotAfter: now.AddDate(1, 0, 0).UTC(), // valid for 1 year.
+ NotBefore: notBefore,
+ NotAfter: notAfter,
- SubjectKeyId: []byte{1, 2, 3, 4},
- KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
+ KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
+ ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
+ BasicConstraintsValid: true,
+ }
+
+ hosts := strings.Split(*host, ",")
+ for _, h := range hosts {
+ if ip := net.ParseIP(h); ip != nil {
+ template.IPAddresses = append(template.IPAddresses, ip)
+ } else {
+ template.DNSNames = append(template.DNSNames, h)
+ }
+ }
+
+ if *isCA {
+ template.IsCA = true
+ template.KeyUsage |= x509.KeyUsageCertSign
}
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
diff --git a/libgo/go/crypto/tls/handshake_server.go b/libgo/go/crypto/tls/handshake_server.go
index 730991016aa..823730c605c 100644
--- a/libgo/go/crypto/tls/handshake_server.go
+++ b/libgo/go/crypto/tls/handshake_server.go
@@ -33,22 +33,7 @@ func (c *Conn) serverHandshake() error {
// If this is the first server handshake, we generate a random key to
// encrypt the tickets with.
- config.serverInitOnce.Do(func() {
- if config.SessionTicketsDisabled {
- return
- }
-
- // If the key has already been set then we have nothing to do.
- for _, b := range config.SessionTicketKey {
- if b != 0 {
- return
- }
- }
-
- if _, err := io.ReadFull(config.rand(), config.SessionTicketKey[:]); err != nil {
- config.SessionTicketsDisabled = true
- }
- })
+ config.serverInitOnce.Do(config.serverInit)
hs := serverHandshakeState{
c: c,
diff --git a/libgo/go/crypto/x509/pkcs8.go b/libgo/go/crypto/x509/pkcs8.go
index 30caacb3c54..8e1585e15cc 100644
--- a/libgo/go/crypto/x509/pkcs8.go
+++ b/libgo/go/crypto/x509/pkcs8.go
@@ -51,6 +51,4 @@ func ParsePKCS8PrivateKey(der []byte) (key interface{}, err error) {
default:
return nil, fmt.Errorf("crypto/x509: PKCS#8 wrapping contained private key with unknown algorithm: %v", privKey.Algo.Algorithm)
}
-
- panic("unreachable")
}
diff --git a/libgo/go/crypto/x509/verify.go b/libgo/go/crypto/x509/verify.go
index 51be5feb063..b29ddbc80f0 100644
--- a/libgo/go/crypto/x509/verify.go
+++ b/libgo/go/crypto/x509/verify.go
@@ -5,6 +5,7 @@
package x509
import (
+ "net"
"runtime"
"strings"
"time"
@@ -63,14 +64,28 @@ type HostnameError struct {
}
func (h HostnameError) Error() string {
- var valid string
c := h.Certificate
- if len(c.DNSNames) > 0 {
- valid = strings.Join(c.DNSNames, ", ")
+
+ var valid string
+ if ip := net.ParseIP(h.Host); ip != nil {
+ // Trying to validate an IP
+ if len(c.IPAddresses) == 0 {
+ return "x509: cannot validate certificate for " + h.Host + " because it doesn't contain any IP SANs"
+ }
+ for _, san := range c.IPAddresses {
+ if len(valid) > 0 {
+ valid += ", "
+ }
+ valid += san.String()
+ }
} else {
- valid = c.Subject.CommonName
+ if len(c.DNSNames) > 0 {
+ valid = strings.Join(c.DNSNames, ", ")
+ } else {
+ valid = c.Subject.CommonName
+ }
}
- return "certificate is valid for " + valid + ", not " + h.Host
+ return "x509: certificate is valid for " + valid + ", not " + h.Host
}
// UnknownAuthorityError results when the certificate issuer is unknown
@@ -334,6 +349,22 @@ func toLowerCaseASCII(in string) string {
// VerifyHostname returns nil if c is a valid certificate for the named host.
// Otherwise it returns an error describing the mismatch.
func (c *Certificate) VerifyHostname(h string) error {
+ // IP addresses may be written in [ ].
+ candidateIP := h
+ if len(h) >= 3 && h[0] == '[' && h[len(h)-1] == ']' {
+ candidateIP = h[1 : len(h)-1]
+ }
+ if ip := net.ParseIP(candidateIP); ip != nil {
+ // We only match IP addresses against IP SANs.
+ // https://tools.ietf.org/html/rfc6125#appendix-B.2
+ for _, candidate := range c.IPAddresses {
+ if ip.Equal(candidate) {
+ return nil
+ }
+ }
+ return HostnameError{c, candidateIP}
+ }
+
lowered := toLowerCaseASCII(h)
if len(c.DNSNames) > 0 {
@@ -389,6 +420,14 @@ func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool {
for _, usage := range cert.ExtKeyUsage {
if requestedUsage == usage {
continue NextRequestedUsage
+ } else if requestedUsage == ExtKeyUsageServerAuth &&
+ (usage == ExtKeyUsageNetscapeServerGatedCrypto ||
+ usage == ExtKeyUsageMicrosoftServerGatedCrypto) {
+ // In order to support COMODO
+ // certificate chains, we have to
+ // accept Netscape or Microsoft SGC
+ // usages as equal to ServerAuth.
+ continue NextRequestedUsage
}
}
diff --git a/libgo/go/crypto/x509/verify_test.go b/libgo/go/crypto/x509/verify_test.go
index 631a0f84981..5103ed814aa 100644
--- a/libgo/go/crypto/x509/verify_test.go
+++ b/libgo/go/crypto/x509/verify_test.go
@@ -158,6 +158,19 @@ var verifyTests = []verifyTest{
{"Ryan Hurst", "GlobalSign PersonalSign 2 CA - G2"},
},
},
+ {
+ leaf: megaLeaf,
+ intermediates: []string{comodoIntermediate1},
+ roots: []string{comodoRoot},
+ currentTime: 1360431182,
+
+ // CryptoAPI can find alternative validation paths so we don't
+ // perform this test with system validation.
+ systemSkip: true,
+ expectedChains: [][]string{
+ {"mega.co.nz", "EssentialSSL CA", "COMODO Certification Authority"},
+ },
+ },
}
func expectHostnameError(t *testing.T, i int, err error) (ok bool) {
@@ -563,3 +576,90 @@ YEvTWbWwGdPytDFPYIl3/6OqNSXSnZ7DxPcdLJq2uyiga8PB/TTIIHYkdM2+1DE0
7y3rH/7TjwDVD7SLu5/SdOfKskuMPTjOEvz3K161mymW06klVhubCIWOro/Gx1Q2
2FQOZ7/2k4uYoOdBTSlb8kTAuzZNgIE0rB2BIYCTz/P6zZIKW0ogbRSH
-----END CERTIFICATE-----`
+
+var megaLeaf = `-----BEGIN CERTIFICATE-----
+MIIFOjCCBCKgAwIBAgIQWYE8Dup170kZ+k11Lg51OjANBgkqhkiG9w0BAQUFADBy
+MQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD
+VQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01PRE8gQ0EgTGltaXRlZDEYMBYGA1UE
+AxMPRXNzZW50aWFsU1NMIENBMB4XDTEyMTIxNDAwMDAwMFoXDTE0MTIxNDIzNTk1
+OVowfzEhMB8GA1UECxMYRG9tYWluIENvbnRyb2wgVmFsaWRhdGVkMS4wLAYDVQQL
+EyVIb3N0ZWQgYnkgSW5zdHJhIENvcnBvcmF0aW9uIFB0eS4gTFREMRUwEwYDVQQL
+EwxFc3NlbnRpYWxTU0wxEzARBgNVBAMTCm1lZ2EuY28ubnowggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQDcxMCClae8BQIaJHBUIVttlLvhbK4XhXPk3RQ3
+G5XA6tLZMBQ33l3F9knYJ0YErXtr8IdfYoulRQFmKFMJl9GtWyg4cGQi2Rcr5VN5
+S5dA1vu4oyJBxE9fPELcK6Yz1vqaf+n6za+mYTiQYKggVdS8/s8hmNuXP9Zk1pIn
++q0pGsf8NAcSHMJgLqPQrTDw+zae4V03DvcYfNKjuno88d2226ld7MAmQZ7uRNsI
+/CnkdelVs+akZsXf0szefSqMJlf08SY32t2jj4Ra7RApVYxOftD9nij/aLfuqOU6
+ow6IgIcIG2ZvXLZwK87c5fxL7UAsTTV+M1sVv8jA33V2oKLhAgMBAAGjggG9MIIB
+uTAfBgNVHSMEGDAWgBTay+qtWwhdzP/8JlTOSeVVxjj0+DAdBgNVHQ4EFgQUmP9l
+6zhyrZ06Qj4zogt+6LKFk4AwDgYDVR0PAQH/BAQDAgWgMAwGA1UdEwEB/wQCMAAw
+NAYDVR0lBC0wKwYIKwYBBQUHAwEGCCsGAQUFBwMCBgorBgEEAYI3CgMDBglghkgB
+hvhCBAEwTwYDVR0gBEgwRjA6BgsrBgEEAbIxAQICBzArMCkGCCsGAQUFBwIBFh1o
+dHRwczovL3NlY3VyZS5jb21vZG8uY29tL0NQUzAIBgZngQwBAgEwOwYDVR0fBDQw
+MjAwoC6gLIYqaHR0cDovL2NybC5jb21vZG9jYS5jb20vRXNzZW50aWFsU1NMQ0Eu
+Y3JsMG4GCCsGAQUFBwEBBGIwYDA4BggrBgEFBQcwAoYsaHR0cDovL2NydC5jb21v
+ZG9jYS5jb20vRXNzZW50aWFsU1NMQ0FfMi5jcnQwJAYIKwYBBQUHMAGGGGh0dHA6
+Ly9vY3NwLmNvbW9kb2NhLmNvbTAlBgNVHREEHjAcggptZWdhLmNvLm56gg53d3cu
+bWVnYS5jby5uejANBgkqhkiG9w0BAQUFAAOCAQEAcYhrsPSvDuwihMOh0ZmRpbOE
+Gw6LqKgLNTmaYUPQhzi2cyIjhUhNvugXQQlP5f0lp5j8cixmArafg1dTn4kQGgD3
+ivtuhBTgKO1VYB/VRoAt6Lmswg3YqyiS7JiLDZxjoV7KoS5xdiaINfHDUaBBY4ZH
+j2BUlPniNBjCqXe/HndUTVUewlxbVps9FyCmH+C4o9DWzdGBzDpCkcmo5nM+cp7q
+ZhTIFTvZfo3zGuBoyu8BzuopCJcFRm3cRiXkpI7iOMUIixO1szkJS6WpL1sKdT73
+UXp08U0LBqoqG130FbzEJBBV3ixbvY6BWMHoCWuaoF12KJnC5kHt2RoWAAgMXA==
+-----END CERTIFICATE-----`
+
+var comodoIntermediate1 = `-----BEGIN CERTIFICATE-----
+MIIFAzCCA+ugAwIBAgIQGLLLuqME8aAPwfLzJkYqSjANBgkqhkiG9w0BAQUFADCB
+gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
+A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV
+BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw
+MDBaFw0xOTEyMzEyMzU5NTlaMHIxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVh
+dGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9E
+TyBDQSBMaW1pdGVkMRgwFgYDVQQDEw9Fc3NlbnRpYWxTU0wgQ0EwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCt8AiwcsargxIxF3CJhakgEtSYau2A1NHf
+5I5ZLdOWIY120j8YC0YZYwvHIPPlC92AGvFaoL0dds23Izp0XmEbdaqb1IX04XiR
+0y3hr/yYLgbSeT1awB8hLRyuIVPGOqchfr7tZ291HRqfalsGs2rjsQuqag7nbWzD
+ypWMN84hHzWQfdvaGlyoiBSyD8gSIF/F03/o4Tjg27z5H6Gq1huQByH6RSRQXScq
+oChBRVt9vKCiL6qbfltTxfEFFld+Edc7tNkBdtzffRDPUanlOPJ7FAB1WfnwWdsX
+Pvev5gItpHnBXaIcw5rIp6gLSApqLn8tl2X2xQScRMiZln5+pN0vAgMBAAGjggGD
+MIIBfzAfBgNVHSMEGDAWgBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAdBgNVHQ4EFgQU
+2svqrVsIXcz//CZUzknlVcY49PgwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQI
+MAYBAf8CAQAwIAYDVR0lBBkwFwYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMD4GA1Ud
+IAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwczovL3NlY3VyZS5jb21v
+ZG8uY29tL0NQUzBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9kb2Nh
+LmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBsBggrBgEFBQcB
+AQRgMF4wNgYIKwYBBQUHMAKGKmh0dHA6Ly9jcnQuY29tb2RvY2EuY29tL0NvbW9k
+b1VUTlNHQ0NBLmNydDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2Eu
+Y29tMA0GCSqGSIb3DQEBBQUAA4IBAQAtlzR6QDLqcJcvgTtLeRJ3rvuq1xqo2l/z
+odueTZbLN3qo6u6bldudu+Ennv1F7Q5Slqz0J790qpL0pcRDAB8OtXj5isWMcL2a
+ejGjKdBZa0wztSz4iw+SY1dWrCRnilsvKcKxudokxeRiDn55w/65g+onO7wdQ7Vu
+F6r7yJiIatnyfKH2cboZT7g440LX8NqxwCPf3dfxp+0Jj1agq8MLy6SSgIGSH6lv
++Wwz3D5XxqfyH8wqfOQsTEZf6/Nh9yvENZ+NWPU6g0QO2JOsTGvMd/QDzczc4BxL
+XSXaPV7Od4rhPsbXlM1wSTz/Dr0ISKvlUhQVnQ6cGodWaK2cCQBk
+-----END CERTIFICATE-----`
+
+var comodoRoot = `-----BEGIN CERTIFICATE-----
+MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB
+gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
+A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV
+BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw
+MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl
+YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P
+RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0
+aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3
+UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI
+2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8
+Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp
++2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+
+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O
+nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW
+/zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g
+PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u
+QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY
+SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv
+IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/
+RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4
+zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd
+BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB
+ZQ==
+-----END CERTIFICATE-----`
diff --git a/libgo/go/crypto/x509/x509.go b/libgo/go/crypto/x509/x509.go
index 7983217696e..4dfea2c9499 100644
--- a/libgo/go/crypto/x509/x509.go
+++ b/libgo/go/crypto/x509/x509.go
@@ -19,6 +19,8 @@ import (
"errors"
"io"
"math/big"
+ "net"
+ "strconv"
"time"
)
@@ -360,16 +362,18 @@ const (
// id-kp-timeStamping OBJECT IDENTIFIER ::= { id-kp 8 }
// id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 }
var (
- oidExtKeyUsageAny = asn1.ObjectIdentifier{2, 5, 29, 37, 0}
- oidExtKeyUsageServerAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 1}
- oidExtKeyUsageClientAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 2}
- oidExtKeyUsageCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 3}
- oidExtKeyUsageEmailProtection = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 4}
- oidExtKeyUsageIPSECEndSystem = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 5}
- oidExtKeyUsageIPSECTunnel = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 6}
- oidExtKeyUsageIPSECUser = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 7}
- oidExtKeyUsageTimeStamping = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 8}
- oidExtKeyUsageOCSPSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 9}
+ oidExtKeyUsageAny = asn1.ObjectIdentifier{2, 5, 29, 37, 0}
+ oidExtKeyUsageServerAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 1}
+ oidExtKeyUsageClientAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 2}
+ oidExtKeyUsageCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 3}
+ oidExtKeyUsageEmailProtection = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 4}
+ oidExtKeyUsageIPSECEndSystem = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 5}
+ oidExtKeyUsageIPSECTunnel = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 6}
+ oidExtKeyUsageIPSECUser = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 7}
+ oidExtKeyUsageTimeStamping = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 8}
+ oidExtKeyUsageOCSPSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 9}
+ oidExtKeyUsageMicrosoftServerGatedCrypto = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 3, 3}
+ oidExtKeyUsageNetscapeServerGatedCrypto = asn1.ObjectIdentifier{2, 16, 840, 1, 113730, 4, 1}
)
// ExtKeyUsage represents an extended set of actions that are valid for a given key.
@@ -387,6 +391,8 @@ const (
ExtKeyUsageIPSECUser
ExtKeyUsageTimeStamping
ExtKeyUsageOCSPSigning
+ ExtKeyUsageMicrosoftServerGatedCrypto
+ ExtKeyUsageNetscapeServerGatedCrypto
)
// extKeyUsageOIDs contains the mapping between an ExtKeyUsage and its OID.
@@ -404,6 +410,8 @@ var extKeyUsageOIDs = []struct {
{ExtKeyUsageIPSECUser, oidExtKeyUsageIPSECUser},
{ExtKeyUsageTimeStamping, oidExtKeyUsageTimeStamping},
{ExtKeyUsageOCSPSigning, oidExtKeyUsageOCSPSigning},
+ {ExtKeyUsageMicrosoftServerGatedCrypto, oidExtKeyUsageMicrosoftServerGatedCrypto},
+ {ExtKeyUsageNetscapeServerGatedCrypto, oidExtKeyUsageNetscapeServerGatedCrypto},
}
func extKeyUsageFromOID(oid asn1.ObjectIdentifier) (eku ExtKeyUsage, ok bool) {
@@ -458,6 +466,7 @@ type Certificate struct {
// Subject Alternate Name values
DNSNames []string
EmailAddresses []string
+ IPAddresses []net.IP
// Name constraints
PermittedDNSDomainsCritical bool // if true then the name constraints are marked critical.
@@ -660,6 +669,13 @@ func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{
return nil, err
}
+ if p.N.Sign() <= 0 {
+ return nil, errors.New("x509: RSA modulus is not a positive number")
+ }
+ if p.E <= 0 {
+ return nil, errors.New("x509: RSA public exponent is not a positive number")
+ }
+
pub := &rsa.PublicKey{
E: p.E,
N: p.N,
@@ -713,7 +729,6 @@ func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{
default:
return nil, nil
}
- panic("unreachable")
}
func parseCertificate(in *certificate) (*Certificate, error) {
@@ -828,6 +843,13 @@ func parseCertificate(in *certificate) (*Certificate, error) {
case 2:
out.DNSNames = append(out.DNSNames, string(v.Bytes))
parsedName = true
+ case 7:
+ switch len(v.Bytes) {
+ case net.IPv4len, net.IPv6len:
+ out.IPAddresses = append(out.IPAddresses, v.Bytes)
+ default:
+ return nil, errors.New("x509: certificate contained IP address of length " + strconv.Itoa(len(v.Bytes)))
+ }
}
}
@@ -1072,11 +1094,22 @@ func buildExtensions(template *Certificate) (ret []pkix.Extension, err error) {
n++
}
- if len(template.DNSNames) > 0 {
+ if len(template.DNSNames) > 0 || len(template.EmailAddresses) > 0 || len(template.IPAddresses) > 0 {
ret[n].Id = oidExtensionSubjectAltName
- rawValues := make([]asn1.RawValue, len(template.DNSNames))
- for i, name := range template.DNSNames {
- rawValues[i] = asn1.RawValue{Tag: 2, Class: 2, Bytes: []byte(name)}
+ var rawValues []asn1.RawValue
+ for _, name := range template.DNSNames {
+ rawValues = append(rawValues, asn1.RawValue{Tag: 2, Class: 2, Bytes: []byte(name)})
+ }
+ for _, email := range template.EmailAddresses {
+ rawValues = append(rawValues, asn1.RawValue{Tag: 1, Class: 2, Bytes: []byte(email)})
+ }
+ for _, rawIP := range template.IPAddresses {
+ // If possible, we always want to encode IPv4 addresses in 4 bytes.
+ ip := rawIP.To4()
+ if ip == nil {
+ ip = rawIP
+ }
+ rawValues = append(rawValues, asn1.RawValue{Tag: 7, Class: 2, Bytes: ip})
}
ret[n].Value, err = asn1.Marshal(rawValues)
if err != nil {
diff --git a/libgo/go/crypto/x509/x509_test.go b/libgo/go/crypto/x509/x509_test.go
index b2d6fe3d552..abd4fe84d7e 100644
--- a/libgo/go/crypto/x509/x509_test.go
+++ b/libgo/go/crypto/x509/x509_test.go
@@ -19,6 +19,7 @@ import (
"encoding/hex"
"encoding/pem"
"math/big"
+ "net"
"reflect"
"testing"
"time"
@@ -174,6 +175,49 @@ func TestMatchHostnames(t *testing.T) {
}
}
+func TestMatchIP(t *testing.T) {
+ // Check that pattern matching is working.
+ c := &Certificate{
+ DNSNames: []string{"*.foo.bar.baz"},
+ Subject: pkix.Name{
+ CommonName: "*.foo.bar.baz",
+ },
+ }
+ err := c.VerifyHostname("quux.foo.bar.baz")
+ if err != nil {
+ t.Fatalf("VerifyHostname(quux.foo.bar.baz): %v", err)
+ }
+
+ // But check that if we change it to be matching against an IP address,
+ // it is rejected.
+ c = &Certificate{
+ DNSNames: []string{"*.2.3.4"},
+ Subject: pkix.Name{
+ CommonName: "*.2.3.4",
+ },
+ }
+ err = c.VerifyHostname("1.2.3.4")
+ if err == nil {
+ t.Fatalf("VerifyHostname(1.2.3.4) should have failed, did not")
+ }
+
+ c = &Certificate{
+ IPAddresses: []net.IP{net.ParseIP("127.0.0.1"), net.ParseIP("::1")},
+ }
+ err = c.VerifyHostname("127.0.0.1")
+ if err != nil {
+ t.Fatalf("VerifyHostname(127.0.0.1): %v", err)
+ }
+ err = c.VerifyHostname("::1")
+ if err != nil {
+ t.Fatalf("VerifyHostname(::1): %v", err)
+ }
+ err = c.VerifyHostname("[::1]")
+ if err != nil {
+ t.Fatalf("VerifyHostname([::1]): %v", err)
+ }
+}
+
func TestCertificateParse(t *testing.T) {
s, _ := hex.DecodeString(certBytes)
certs, err := ParseCertificates(s)
@@ -284,8 +328,11 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
UnknownExtKeyUsage: testUnknownExtKeyUsage,
BasicConstraintsValid: true,
- IsCA: true,
- DNSNames: []string{"test.example.com"},
+ IsCA: true,
+
+ DNSNames: []string{"test.example.com"},
+ EmailAddresses: []string{"gopher@golang.org"},
+ IPAddresses: []net.IP{net.IPv4(127, 0, 0, 1).To4(), net.ParseIP("2001:4860:0:2001::68")},
PolicyIdentifiers: []asn1.ObjectIdentifier{[]int{1, 2, 3}},
PermittedDNSDomains: []string{".example.com", "example.com"},
@@ -327,6 +374,18 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
t.Errorf("%s: unknown extkeyusage wasn't correctly copied from the template. Got %v, want %v", test.name, cert.UnknownExtKeyUsage, testUnknownExtKeyUsage)
}
+ if !reflect.DeepEqual(cert.DNSNames, template.DNSNames) {
+ t.Errorf("%s: SAN DNS names differ from template. Got %v, want %v", test.name, cert.DNSNames, template.DNSNames)
+ }
+
+ if !reflect.DeepEqual(cert.EmailAddresses, template.EmailAddresses) {
+ t.Errorf("%s: SAN emails differ from template. Got %v, want %v", test.name, cert.EmailAddresses, template.EmailAddresses)
+ }
+
+ if !reflect.DeepEqual(cert.IPAddresses, template.IPAddresses) {
+ t.Errorf("%s: SAN IPs differ from template. Got %v, want %v", test.name, cert.IPAddresses, template.IPAddresses)
+ }
+
if test.checkSig {
err = cert.CheckSignatureFrom(cert)
if err != nil {
diff --git a/libgo/go/database/sql/convert.go b/libgo/go/database/sql/convert.go
index 964dc184850..c04adde1fc1 100644
--- a/libgo/go/database/sql/convert.go
+++ b/libgo/go/database/sql/convert.go
@@ -14,12 +14,18 @@ import (
"strconv"
)
+var errNilPtr = errors.New("destination pointer is nil") // embedded in descriptive error
+
// driverArgs converts arguments from callers of Stmt.Exec and
// Stmt.Query into driver Values.
//
-// The statement si may be nil, if no statement is available.
-func driverArgs(si driver.Stmt, args []interface{}) ([]driver.Value, error) {
+// The statement ds may be nil, if no statement is available.
+func driverArgs(ds *driverStmt, args []interface{}) ([]driver.Value, error) {
dargs := make([]driver.Value, len(args))
+ var si driver.Stmt
+ if ds != nil {
+ si = ds.si
+ }
cc, ok := si.(driver.ColumnConverter)
// Normal path, for a driver.Stmt that is not a ColumnConverter.
@@ -58,7 +64,9 @@ func driverArgs(si driver.Stmt, args []interface{}) ([]driver.Value, error) {
// column before going across the network to get the
// same error.
var err error
+ ds.Lock()
dargs[n], err = cc.ColumnConverter(n).ConvertValue(arg)
+ ds.Unlock()
if err != nil {
return nil, fmt.Errorf("sql: converting argument #%d's type: %v", n, err)
}
@@ -75,34 +83,68 @@ func driverArgs(si driver.Stmt, args []interface{}) ([]driver.Value, error) {
// An error is returned if the copy would result in loss of information.
// dest should be a pointer type.
func convertAssign(dest, src interface{}) error {
- // Common cases, without reflect. Fall through.
+ // Common cases, without reflect.
switch s := src.(type) {
case string:
switch d := dest.(type) {
case *string:
+ if d == nil {
+ return errNilPtr
+ }
*d = s
return nil
case *[]byte:
+ if d == nil {
+ return errNilPtr
+ }
*d = []byte(s)
return nil
}
case []byte:
switch d := dest.(type) {
case *string:
+ if d == nil {
+ return errNilPtr
+ }
*d = string(s)
return nil
case *interface{}:
- bcopy := make([]byte, len(s))
- copy(bcopy, s)
- *d = bcopy
+ if d == nil {
+ return errNilPtr
+ }
+ *d = cloneBytes(s)
return nil
case *[]byte:
+ if d == nil {
+ return errNilPtr
+ }
+ *d = cloneBytes(s)
+ return nil
+ case *RawBytes:
+ if d == nil {
+ return errNilPtr
+ }
*d = s
return nil
}
case nil:
switch d := dest.(type) {
+ case *interface{}:
+ if d == nil {
+ return errNilPtr
+ }
+ *d = nil
+ return nil
case *[]byte:
+ if d == nil {
+ return errNilPtr
+ }
+ *d = nil
+ return nil
+ case *RawBytes:
+ if d == nil {
+ return errNilPtr
+ }
*d = nil
return nil
}
@@ -121,6 +163,26 @@ func convertAssign(dest, src interface{}) error {
*d = fmt.Sprintf("%v", src)
return nil
}
+ case *[]byte:
+ sv = reflect.ValueOf(src)
+ switch sv.Kind() {
+ case reflect.Bool,
+ reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
+ reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
+ reflect.Float32, reflect.Float64:
+ *d = []byte(fmt.Sprintf("%v", src))
+ return nil
+ }
+ case *RawBytes:
+ sv = reflect.ValueOf(src)
+ switch sv.Kind() {
+ case reflect.Bool,
+ reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
+ reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
+ reflect.Float32, reflect.Float64:
+ *d = RawBytes(fmt.Sprintf("%v", src))
+ return nil
+ }
case *bool:
bv, err := driver.Bool.ConvertValue(src)
if err == nil {
@@ -140,6 +202,9 @@ func convertAssign(dest, src interface{}) error {
if dpv.Kind() != reflect.Ptr {
return errors.New("destination not a pointer")
}
+ if dpv.IsNil() {
+ return errNilPtr
+ }
if !sv.IsValid() {
sv = reflect.ValueOf(src)
@@ -189,6 +254,16 @@ func convertAssign(dest, src interface{}) error {
return fmt.Errorf("unsupported driver -> Scan pair: %T -> %T", src, dest)
}
+func cloneBytes(b []byte) []byte {
+ if b == nil {
+ return nil
+ } else {
+ c := make([]byte, len(b))
+ copy(c, b)
+ return c
+ }
+}
+
func asString(src interface{}) string {
switch v := src.(type) {
case string:
diff --git a/libgo/go/database/sql/convert_test.go b/libgo/go/database/sql/convert_test.go
index 9c362d7320a..950e24fc3a8 100644
--- a/libgo/go/database/sql/convert_test.go
+++ b/libgo/go/database/sql/convert_test.go
@@ -22,6 +22,8 @@ type conversionTest struct {
wantint int64
wantuint uint64
wantstr string
+ wantbytes []byte
+ wantraw RawBytes
wantf32 float32
wantf64 float64
wanttime time.Time
@@ -35,6 +37,8 @@ type conversionTest struct {
// Target variables for scanning into.
var (
scanstr string
+ scanbytes []byte
+ scanraw RawBytes
scanint int
scanint8 int8
scanint16 int16
@@ -56,6 +60,7 @@ var conversionTests = []conversionTest{
{s: someTime, d: &scantime, wanttime: someTime},
// To strings
+ {s: "string", d: &scanstr, wantstr: "string"},
{s: []byte("byteslice"), d: &scanstr, wantstr: "byteslice"},
{s: 123, d: &scanstr, wantstr: "123"},
{s: int8(123), d: &scanstr, wantstr: "123"},
@@ -66,6 +71,31 @@ var conversionTests = []conversionTest{
{s: uint64(123), d: &scanstr, wantstr: "123"},
{s: 1.5, d: &scanstr, wantstr: "1.5"},
+ // To []byte
+ {s: nil, d: &scanbytes, wantbytes: nil},
+ {s: "string", d: &scanbytes, wantbytes: []byte("string")},
+ {s: []byte("byteslice"), d: &scanbytes, wantbytes: []byte("byteslice")},
+ {s: 123, d: &scanbytes, wantbytes: []byte("123")},
+ {s: int8(123), d: &scanbytes, wantbytes: []byte("123")},
+ {s: int64(123), d: &scanbytes, wantbytes: []byte("123")},
+ {s: uint8(123), d: &scanbytes, wantbytes: []byte("123")},
+ {s: uint16(123), d: &scanbytes, wantbytes: []byte("123")},
+ {s: uint32(123), d: &scanbytes, wantbytes: []byte("123")},
+ {s: uint64(123), d: &scanbytes, wantbytes: []byte("123")},
+ {s: 1.5, d: &scanbytes, wantbytes: []byte("1.5")},
+
+ // To RawBytes
+ {s: nil, d: &scanraw, wantraw: nil},
+ {s: []byte("byteslice"), d: &scanraw, wantraw: RawBytes("byteslice")},
+ {s: 123, d: &scanraw, wantraw: RawBytes("123")},
+ {s: int8(123), d: &scanraw, wantraw: RawBytes("123")},
+ {s: int64(123), d: &scanraw, wantraw: RawBytes("123")},
+ {s: uint8(123), d: &scanraw, wantraw: RawBytes("123")},
+ {s: uint16(123), d: &scanraw, wantraw: RawBytes("123")},
+ {s: uint32(123), d: &scanraw, wantraw: RawBytes("123")},
+ {s: uint64(123), d: &scanraw, wantraw: RawBytes("123")},
+ {s: 1.5, d: &scanraw, wantraw: RawBytes("1.5")},
+
// Strings to integers
{s: "255", d: &scanuint8, wantuint: 255},
{s: "256", d: &scanuint8, wanterr: `converting string "256" to a uint8: strconv.ParseUint: parsing "256": value out of range`},
@@ -113,6 +143,7 @@ var conversionTests = []conversionTest{
{s: []byte("byteslice"), d: &scaniface, wantiface: []byte("byteslice")},
{s: true, d: &scaniface, wantiface: true},
{s: nil, d: &scaniface},
+ {s: []byte(nil), d: &scaniface, wantiface: []byte(nil)},
}
func intPtrValue(intptr interface{}) interface{} {
@@ -191,7 +222,7 @@ func TestConversions(t *testing.T) {
}
if srcBytes, ok := ct.s.([]byte); ok {
dstBytes := (*ifptr).([]byte)
- if &dstBytes[0] == &srcBytes[0] {
+ if len(srcBytes) > 0 && &dstBytes[0] == &srcBytes[0] {
errf("copy into interface{} didn't copy []byte data")
}
}
diff --git a/libgo/go/database/sql/driver/driver.go b/libgo/go/database/sql/driver/driver.go
index 2f5280db810..d7ca94f7809 100644
--- a/libgo/go/database/sql/driver/driver.go
+++ b/libgo/go/database/sql/driver/driver.go
@@ -10,8 +10,8 @@ package driver
import "errors"
-// A driver Value is a value that drivers must be able to handle.
-// A Value is either nil or an instance of one of these types:
+// Value is a value that drivers must be able to handle.
+// It is either nil or an instance of one of these types:
//
// int64
// float64
@@ -56,7 +56,7 @@ var ErrBadConn = errors.New("driver: bad connection")
// Execer is an optional interface that may be implemented by a Conn.
//
-// If a Conn does not implement Execer, the db package's DB.Exec will
+// If a Conn does not implement Execer, the sql package's DB.Exec will
// first prepare a query, execute the statement, and then close the
// statement.
//
@@ -65,6 +65,17 @@ type Execer interface {
Exec(query string, args []Value) (Result, error)
}
+// Queryer is an optional interface that may be implemented by a Conn.
+//
+// If a Conn does not implement Queryer, the sql package's DB.Query will
+// first prepare a query, execute the statement, and then close the
+// statement.
+//
+// Query may return ErrSkip.
+type Queryer interface {
+ Query(query string, args []Value) (Rows, error)
+}
+
// Conn is a connection to a database. It is not used concurrently
// by multiple goroutines.
//
@@ -104,23 +115,8 @@ type Result interface {
type Stmt interface {
// Close closes the statement.
//
- // Closing a statement should not interrupt any outstanding
- // query created from that statement. That is, the following
- // order of operations is valid:
- //
- // * create a driver statement
- // * call Query on statement, returning Rows
- // * close the statement
- // * read from Rows
- //
- // If closing a statement invalidates currently-running
- // queries, the final step above will incorrectly fail.
- //
- // TODO(bradfitz): possibly remove the restriction above, if
- // enough driver authors object and find it complicates their
- // code too much. The sql package could be smarter about
- // refcounting the statement and closing it at the appropriate
- // time.
+ // As of Go 1.1, a Stmt will not be closed if it's in use
+ // by any queries.
Close() error
// NumInput returns the number of placeholder parameters.
diff --git a/libgo/go/database/sql/fakedb_test.go b/libgo/go/database/sql/fakedb_test.go
index c38ba7c8492..d900e2cebe8 100644
--- a/libgo/go/database/sql/fakedb_test.go
+++ b/libgo/go/database/sql/fakedb_test.go
@@ -13,6 +13,7 @@ import (
"strconv"
"strings"
"sync"
+ "testing"
"time"
)
@@ -34,9 +35,10 @@ var _ = log.Printf
// When opening a fakeDriver's database, it starts empty with no
// tables. All tables and data are stored in memory only.
type fakeDriver struct {
- mu sync.Mutex
- openCount int
- dbs map[string]*fakeDB
+ mu sync.Mutex // guards 3 following fields
+ openCount int // conn opens
+ closeCount int // conn closes
+ dbs map[string]*fakeDB
}
type fakeDB struct {
@@ -229,7 +231,43 @@ func (c *fakeConn) Begin() (driver.Tx, error) {
return c.currTx, nil
}
-func (c *fakeConn) Close() error {
+var hookPostCloseConn struct {
+ sync.Mutex
+ fn func(*fakeConn, error)
+}
+
+func setHookpostCloseConn(fn func(*fakeConn, error)) {
+ hookPostCloseConn.Lock()
+ defer hookPostCloseConn.Unlock()
+ hookPostCloseConn.fn = fn
+}
+
+var testStrictClose *testing.T
+
+// setStrictFakeConnClose sets the t to Errorf on when fakeConn.Close
+// fails to close. If nil, the check is disabled.
+func setStrictFakeConnClose(t *testing.T) {
+ testStrictClose = t
+}
+
+func (c *fakeConn) Close() (err error) {
+ drv := fdriver.(*fakeDriver)
+ defer func() {
+ if err != nil && testStrictClose != nil {
+ testStrictClose.Errorf("failed to close a test fakeConn: %v", err)
+ }
+ hookPostCloseConn.Lock()
+ fn := hookPostCloseConn.fn
+ hookPostCloseConn.Unlock()
+ if fn != nil {
+ fn(c, err)
+ }
+ if err == nil {
+ drv.mu.Lock()
+ drv.closeCount++
+ drv.mu.Unlock()
+ }
+ }()
if c.currTx != nil {
return errors.New("can't close fakeConn; in a Transaction")
}
@@ -266,6 +304,18 @@ func (c *fakeConn) Exec(query string, args []driver.Value) (driver.Result, error
return nil, driver.ErrSkip
}
+func (c *fakeConn) Query(query string, args []driver.Value) (driver.Rows, error) {
+ // This is an optional interface, but it's implemented here
+ // just to check that all the args are of the proper types.
+ // ErrSkip is returned so the caller acts as if we didn't
+ // implement this at all.
+ err := checkSubsetTypes(args)
+ if err != nil {
+ return nil, err
+ }
+ return nil, driver.ErrSkip
+}
+
func errf(msg string, args ...interface{}) error {
return errors.New("fakedb: " + fmt.Sprintf(msg, args...))
}
@@ -412,6 +462,12 @@ func (s *fakeStmt) ColumnConverter(idx int) driver.ValueConverter {
}
func (s *fakeStmt) Close() error {
+ if s.c == nil {
+ panic("nil conn in fakeStmt.Close")
+ }
+ if s.c.db == nil {
+ panic("in fakeStmt.Close, conn's db is nil (already closed)")
+ }
if !s.closed {
s.c.incrStat(&s.c.stmtsClosed)
s.closed = true
@@ -503,6 +559,15 @@ func (s *fakeStmt) Query(args []driver.Value) (driver.Rows, error) {
if !ok {
return nil, fmt.Errorf("fakedb: table %q doesn't exist", s.table)
}
+
+ if s.table == "magicquery" {
+ if len(s.whereCol) == 2 && s.whereCol[0] == "op" && s.whereCol[1] == "millis" {
+ if args[0] == "sleep" {
+ time.Sleep(time.Duration(args[1].(int64)) * time.Millisecond)
+ }
+ }
+ }
+
t.mu.Lock()
defer t.mu.Unlock()
diff --git a/libgo/go/database/sql/sql.go b/libgo/go/database/sql/sql.go
index 29aef78b240..a80782bfedc 100644
--- a/libgo/go/database/sql/sql.go
+++ b/libgo/go/database/sql/sql.go
@@ -4,6 +4,9 @@
// Package sql provides a generic interface around SQL (or SQL-like)
// databases.
+//
+// The sql package must be used in conjunction with a database driver.
+// See http://golang.org/s/sqldrivers for a list of drivers.
package sql
import (
@@ -11,6 +14,7 @@ import (
"errors"
"fmt"
"io"
+ "runtime"
"sync"
)
@@ -176,22 +180,197 @@ var ErrNoRows = errors.New("sql: no rows in result set")
// DB is a database handle. It's safe for concurrent use by multiple
// goroutines.
//
-// If the underlying database driver has the concept of a connection
-// and per-connection session state, the sql package manages creating
-// and freeing connections automatically, including maintaining a free
-// pool of idle connections. If observing session state is required,
-// either do not share a *DB between multiple concurrent goroutines or
-// create and observe all state only within a transaction. Once
-// DB.Open is called, the returned Tx is bound to a single isolated
-// connection. Once Tx.Commit or Tx.Rollback is called, that
-// connection is returned to DB's idle connection pool.
+// The sql package creates and frees connections automatically; it
+// also maintains a free pool of idle connections. If the database has
+// a concept of per-connection state, such state can only be reliably
+// observed within a transaction. Once DB.Begin is called, the
+// returned Tx is bound to a single connection. Once Commit or
+// Rollback is called on the transaction, that transaction's
+// connection is returned to DB's idle connection pool. The pool size
+// can be controlled with SetMaxIdleConns.
type DB struct {
driver driver.Driver
dsn string
- mu sync.Mutex // protects freeConn and closed
- freeConn []driver.Conn
+ mu sync.Mutex // protects following fields
+ freeConn []*driverConn
closed bool
+ dep map[finalCloser]depSet
+ lastPut map[*driverConn]string // stacktrace of last conn's put; debug only
+ maxIdle int // zero means defaultMaxIdleConns; negative means 0
+}
+
+// driverConn wraps a driver.Conn with a mutex, to
+// be held during all calls into the Conn. (including any calls onto
+// interfaces returned via that Conn, such as calls on Tx, Stmt,
+// Result, Rows)
+type driverConn struct {
+ db *DB
+
+ sync.Mutex // guards following
+ ci driver.Conn
+ closed bool
+ finalClosed bool // ci.Close has been called
+ openStmt map[driver.Stmt]bool
+
+ // guarded by db.mu
+ inUse bool
+ onPut []func() // code (with db.mu held) run when conn is next returned
+ dbmuClosed bool // same as closed, but guarded by db.mu, for connIfFree
+}
+
+func (dc *driverConn) removeOpenStmt(si driver.Stmt) {
+ dc.Lock()
+ defer dc.Unlock()
+ delete(dc.openStmt, si)
+}
+
+func (dc *driverConn) prepareLocked(query string) (driver.Stmt, error) {
+ si, err := dc.ci.Prepare(query)
+ if err == nil {
+ // Track each driverConn's open statements, so we can close them
+ // before closing the conn.
+ //
+ // TODO(bradfitz): let drivers opt out of caring about
+ // stmt closes if the conn is about to close anyway? For now
+ // do the safe thing, in case stmts need to be closed.
+ //
+ // TODO(bradfitz): after Go 1.1, closing driver.Stmts
+ // should be moved to driverStmt, using unique
+ // *driverStmts everywhere (including from
+ // *Stmt.connStmt, instead of returning a
+ // driver.Stmt), using driverStmt as a pointer
+ // everywhere, and making it a finalCloser.
+ if dc.openStmt == nil {
+ dc.openStmt = make(map[driver.Stmt]bool)
+ }
+ dc.openStmt[si] = true
+ }
+ return si, err
+}
+
+// the dc.db's Mutex is held.
+func (dc *driverConn) closeDBLocked() error {
+ dc.Lock()
+ if dc.closed {
+ dc.Unlock()
+ return errors.New("sql: duplicate driverConn close")
+ }
+ dc.closed = true
+ dc.Unlock() // not defer; removeDep finalClose calls may need to lock
+ return dc.db.removeDepLocked(dc, dc)()
+}
+
+func (dc *driverConn) Close() error {
+ dc.Lock()
+ if dc.closed {
+ dc.Unlock()
+ return errors.New("sql: duplicate driverConn close")
+ }
+ dc.closed = true
+ dc.Unlock() // not defer; removeDep finalClose calls may need to lock
+
+ // And now updates that require holding dc.mu.Lock.
+ dc.db.mu.Lock()
+ dc.dbmuClosed = true
+ fn := dc.db.removeDepLocked(dc, dc)
+ dc.db.mu.Unlock()
+ return fn()
+}
+
+func (dc *driverConn) finalClose() error {
+ dc.Lock()
+
+ for si := range dc.openStmt {
+ si.Close()
+ }
+ dc.openStmt = nil
+
+ err := dc.ci.Close()
+ dc.ci = nil
+ dc.finalClosed = true
+
+ dc.Unlock()
+ return err
+}
+
+// driverStmt associates a driver.Stmt with the
+// *driverConn from which it came, so the driverConn's lock can be
+// held during calls.
+type driverStmt struct {
+ sync.Locker // the *driverConn
+ si driver.Stmt
+}
+
+func (ds *driverStmt) Close() error {
+ ds.Lock()
+ defer ds.Unlock()
+ return ds.si.Close()
+}
+
+// depSet is a finalCloser's outstanding dependencies
+type depSet map[interface{}]bool // set of true bools
+
+// The finalCloser interface is used by (*DB).addDep and related
+// dependency reference counting.
+type finalCloser interface {
+ // finalClose is called when the reference count of an object
+ // goes to zero. (*DB).mu is not held while calling it.
+ finalClose() error
+}
+
+// addDep notes that x now depends on dep, and x's finalClose won't be
+// called until all of x's dependencies are removed with removeDep.
+func (db *DB) addDep(x finalCloser, dep interface{}) {
+ //println(fmt.Sprintf("addDep(%T %p, %T %p)", x, x, dep, dep))
+ db.mu.Lock()
+ defer db.mu.Unlock()
+ db.addDepLocked(x, dep)
+}
+
+func (db *DB) addDepLocked(x finalCloser, dep interface{}) {
+ if db.dep == nil {
+ db.dep = make(map[finalCloser]depSet)
+ }
+ xdep := db.dep[x]
+ if xdep == nil {
+ xdep = make(depSet)
+ db.dep[x] = xdep
+ }
+ xdep[dep] = true
+}
+
+// removeDep notes that x no longer depends on dep.
+// If x still has dependencies, nil is returned.
+// If x no longer has any dependencies, its finalClose method will be
+// called and its error value will be returned.
+func (db *DB) removeDep(x finalCloser, dep interface{}) error {
+ db.mu.Lock()
+ fn := db.removeDepLocked(x, dep)
+ db.mu.Unlock()
+ return fn()
+}
+
+func (db *DB) removeDepLocked(x finalCloser, dep interface{}) func() error {
+ //println(fmt.Sprintf("removeDep(%T %p, %T %p)", x, x, dep, dep))
+ done := false
+
+ xdep := db.dep[x]
+ if xdep != nil {
+ delete(xdep, dep)
+ if len(xdep) == 0 {
+ delete(db.dep, x)
+ done = true
+ }
+ }
+
+ if !done {
+ return func() error { return nil }
+ }
+ return func() error {
+ //println(fmt.Sprintf("calling final close on %T %v (%#v)", x, x, x))
+ return x.finalClose()
+ }
}
// Open opens a database specified by its database driver name and a
@@ -199,13 +378,38 @@ type DB struct {
// database name and connection information.
//
// Most users will open a database via a driver-specific connection
-// helper function that returns a *DB.
+// helper function that returns a *DB. No database drivers are included
+// in the Go standard library. See http://golang.org/s/sqldrivers for
+// a list of third-party drivers.
+//
+// Open may just validate its arguments without creating a connection
+// to the database. To verify that the data source name is valid, call
+// Ping.
func Open(driverName, dataSourceName string) (*DB, error) {
- driver, ok := drivers[driverName]
+ driveri, ok := drivers[driverName]
if !ok {
return nil, fmt.Errorf("sql: unknown driver %q (forgotten import?)", driverName)
}
- return &DB{driver: driver, dsn: dataSourceName}, nil
+ db := &DB{
+ driver: driveri,
+ dsn: dataSourceName,
+ lastPut: make(map[*driverConn]string),
+ }
+ return db, nil
+}
+
+// Ping verifies a connection to the database is still alive,
+// establishing a connection if necessary.
+func (db *DB) Ping() error {
+ // TODO(bradfitz): give drivers an optional hook to implement
+ // this in a more efficient or more reliable way, if they
+ // have one.
+ dc, err := db.conn()
+ if err != nil {
+ return err
+ }
+ db.putConn(dc, nil)
+ return nil
}
// Close closes the database, releasing any open resources.
@@ -213,8 +417,8 @@ func (db *DB) Close() error {
db.mu.Lock()
defer db.mu.Unlock()
var err error
- for _, c := range db.freeConn {
- err1 := c.Close()
+ for _, dc := range db.freeConn {
+ err1 := dc.closeDBLocked()
if err1 != nil {
err = err1
}
@@ -224,15 +428,45 @@ func (db *DB) Close() error {
return err
}
-func (db *DB) maxIdleConns() int {
- const defaultMaxIdleConns = 2
- // TODO(bradfitz): ask driver, if supported, for its default preference
- // TODO(bradfitz): let users override?
- return defaultMaxIdleConns
+const defaultMaxIdleConns = 2
+
+func (db *DB) maxIdleConnsLocked() int {
+ n := db.maxIdle
+ switch {
+ case n == 0:
+ // TODO(bradfitz): ask driver, if supported, for its default preference
+ return defaultMaxIdleConns
+ case n < 0:
+ return 0
+ default:
+ return n
+ }
}
-// conn returns a newly-opened or cached driver.Conn
-func (db *DB) conn() (driver.Conn, error) {
+// SetMaxIdleConns sets the maximum number of connections in the idle
+// connection pool.
+//
+// If n <= 0, no idle connections are retained.
+func (db *DB) SetMaxIdleConns(n int) {
+ db.mu.Lock()
+ defer db.mu.Unlock()
+ if n > 0 {
+ db.maxIdle = n
+ } else {
+ // No idle connections.
+ db.maxIdle = -1
+ }
+ for len(db.freeConn) > 0 && len(db.freeConn) > n {
+ nfree := len(db.freeConn)
+ dc := db.freeConn[nfree-1]
+ db.freeConn[nfree-1] = nil
+ db.freeConn = db.freeConn[:nfree-1]
+ go dc.Close()
+ }
+}
+
+// conn returns a newly-opened or cached *driverConn
+func (db *DB) conn() (*driverConn, error) {
db.mu.Lock()
if db.closed {
db.mu.Unlock()
@@ -241,53 +475,132 @@ func (db *DB) conn() (driver.Conn, error) {
if n := len(db.freeConn); n > 0 {
conn := db.freeConn[n-1]
db.freeConn = db.freeConn[:n-1]
+ conn.inUse = true
db.mu.Unlock()
return conn, nil
}
db.mu.Unlock()
- return db.driver.Open(db.dsn)
+
+ ci, err := db.driver.Open(db.dsn)
+ if err != nil {
+ return nil, err
+ }
+ dc := &driverConn{
+ db: db,
+ ci: ci,
+ }
+ db.mu.Lock()
+ db.addDepLocked(dc, dc)
+ dc.inUse = true
+ db.mu.Unlock()
+ return dc, nil
}
-func (db *DB) connIfFree(wanted driver.Conn) (conn driver.Conn, ok bool) {
+var (
+ errConnClosed = errors.New("database/sql: internal sentinel error: conn is closed")
+ errConnBusy = errors.New("database/sql: internal sentinel error: conn is busy")
+)
+
+// connIfFree returns (wanted, nil) if wanted is still a valid conn and
+// isn't in use.
+//
+// The error is errConnClosed if the connection if the requested connection
+// is invalid because it's been closed.
+//
+// The error is errConnBusy if the connection is in use.
+func (db *DB) connIfFree(wanted *driverConn) (*driverConn, error) {
db.mu.Lock()
defer db.mu.Unlock()
+ if wanted.inUse {
+ return nil, errConnBusy
+ }
+ if wanted.dbmuClosed {
+ return nil, errConnClosed
+ }
for i, conn := range db.freeConn {
if conn != wanted {
continue
}
db.freeConn[i] = db.freeConn[len(db.freeConn)-1]
db.freeConn = db.freeConn[:len(db.freeConn)-1]
- return wanted, true
+ wanted.inUse = true
+ return wanted, nil
}
- return nil, false
+ // TODO(bradfitz): shouldn't get here. After Go 1.1, change this to:
+ // panic("connIfFree call requested a non-closed, non-busy, non-free conn")
+ // Which passes all the tests, but I'm too paranoid to include this
+ // late in Go 1.1.
+ // Instead, treat it like a busy connection:
+ return nil, errConnBusy
}
// putConnHook is a hook for testing.
-var putConnHook func(*DB, driver.Conn)
+var putConnHook func(*DB, *driverConn)
+
+// noteUnusedDriverStatement notes that si is no longer used and should
+// be closed whenever possible (when c is next not in use), unless c is
+// already closed.
+func (db *DB) noteUnusedDriverStatement(c *driverConn, si driver.Stmt) {
+ db.mu.Lock()
+ defer db.mu.Unlock()
+ if c.inUse {
+ c.onPut = append(c.onPut, func() {
+ si.Close()
+ })
+ } else {
+ c.Lock()
+ defer c.Unlock()
+ if !c.finalClosed {
+ si.Close()
+ }
+ }
+}
+
+// debugGetPut determines whether getConn & putConn calls' stack traces
+// are returned for more verbose crashes.
+const debugGetPut = false
// putConn adds a connection to the db's free pool.
// err is optionally the last error that occurred on this connection.
-func (db *DB) putConn(c driver.Conn, err error) {
+func (db *DB) putConn(dc *driverConn, err error) {
+ db.mu.Lock()
+ if !dc.inUse {
+ if debugGetPut {
+ fmt.Printf("putConn(%v) DUPLICATE was: %s\n\nPREVIOUS was: %s", dc, stack(), db.lastPut[dc])
+ }
+ panic("sql: connection returned that was never out")
+ }
+ if debugGetPut {
+ db.lastPut[dc] = stack()
+ }
+ dc.inUse = false
+
+ for _, fn := range dc.onPut {
+ fn()
+ }
+ dc.onPut = nil
+
if err == driver.ErrBadConn {
// Don't reuse bad connections.
- return
- }
- db.mu.Lock()
- if putConnHook != nil {
- putConnHook(db, c)
- }
- if n := len(db.freeConn); !db.closed && n < db.maxIdleConns() {
- db.freeConn = append(db.freeConn, c)
db.mu.Unlock()
return
}
- // TODO: check to see if we need this Conn for any prepared
- // statements which are still active?
+ if putConnHook != nil {
+ putConnHook(db, dc)
+ }
+ if n := len(db.freeConn); !db.closed && n < db.maxIdleConnsLocked() {
+ db.freeConn = append(db.freeConn, dc)
+ db.mu.Unlock()
+ return
+ }
db.mu.Unlock()
- c.Close()
+
+ dc.Close()
}
-// Prepare creates a prepared statement for later execution.
+// Prepare creates a prepared statement for later queries or executions.
+// Multiple queries or executions may be run concurrently from the
+// returned statement.
func (db *DB) Prepare(query string) (*Stmt, error) {
var stmt *Stmt
var err error
@@ -300,34 +613,36 @@ func (db *DB) Prepare(query string) (*Stmt, error) {
return stmt, err
}
-func (db *DB) prepare(query string) (stmt *Stmt, err error) {
+func (db *DB) prepare(query string) (*Stmt, error) {
// TODO: check if db.driver supports an optional
// driver.Preparer interface and call that instead, if so,
// otherwise we make a prepared statement that's bound
// to a connection, and to execute this prepared statement
// we either need to use this connection (if it's free), else
// get a new connection + re-prepare + execute on that one.
- ci, err := db.conn()
+ dc, err := db.conn()
if err != nil {
return nil, err
}
- defer func() {
- db.putConn(ci, err)
- }()
-
- si, err := ci.Prepare(query)
+ dc.Lock()
+ si, err := dc.prepareLocked(query)
+ dc.Unlock()
if err != nil {
+ db.putConn(dc, err)
return nil, err
}
- stmt = &Stmt{
+ stmt := &Stmt{
db: db,
query: query,
- css: []connStmt{{ci, si}},
+ css: []connStmt{{dc, si}},
}
+ db.addDep(stmt, stmt)
+ db.putConn(dc, nil)
return stmt, nil
}
// Exec executes a query without returning any rows.
+// The args are for any placeholder parameters in the query.
func (db *DB) Exec(query string, args ...interface{}) (Result, error) {
var res Result
var err error
@@ -341,50 +656,119 @@ func (db *DB) Exec(query string, args ...interface{}) (Result, error) {
}
func (db *DB) exec(query string, args []interface{}) (res Result, err error) {
- ci, err := db.conn()
+ dc, err := db.conn()
if err != nil {
return nil, err
}
defer func() {
- db.putConn(ci, err)
+ db.putConn(dc, err)
}()
- if execer, ok := ci.(driver.Execer); ok {
+ if execer, ok := dc.ci.(driver.Execer); ok {
dargs, err := driverArgs(nil, args)
if err != nil {
return nil, err
}
+ dc.Lock()
resi, err := execer.Exec(query, dargs)
+ dc.Unlock()
if err != driver.ErrSkip {
if err != nil {
return nil, err
}
- return result{resi}, nil
+ return driverResult{dc, resi}, nil
}
}
- sti, err := ci.Prepare(query)
+ dc.Lock()
+ si, err := dc.ci.Prepare(query)
+ dc.Unlock()
if err != nil {
return nil, err
}
- defer sti.Close()
-
- return resultFromStatement(sti, args...)
+ defer withLock(dc, func() { si.Close() })
+ return resultFromStatement(driverStmt{dc, si}, args...)
}
// Query executes a query that returns rows, typically a SELECT.
// The args are for any placeholder parameters in the query.
func (db *DB) Query(query string, args ...interface{}) (*Rows, error) {
- stmt, err := db.Prepare(query)
+ var rows *Rows
+ var err error
+ for i := 0; i < 10; i++ {
+ rows, err = db.query(query, args)
+ if err != driver.ErrBadConn {
+ break
+ }
+ }
+ return rows, err
+}
+
+func (db *DB) query(query string, args []interface{}) (*Rows, error) {
+ ci, err := db.conn()
if err != nil {
return nil, err
}
- rows, err := stmt.Query(args...)
+
+ releaseConn := func(err error) { db.putConn(ci, err) }
+
+ return db.queryConn(ci, releaseConn, query, args)
+}
+
+// queryConn executes a query on the given connection.
+// The connection gets released by the releaseConn function.
+func (db *DB) queryConn(dc *driverConn, releaseConn func(error), query string, args []interface{}) (*Rows, error) {
+ if queryer, ok := dc.ci.(driver.Queryer); ok {
+ dargs, err := driverArgs(nil, args)
+ if err != nil {
+ releaseConn(err)
+ return nil, err
+ }
+ dc.Lock()
+ rowsi, err := queryer.Query(query, dargs)
+ dc.Unlock()
+ if err != driver.ErrSkip {
+ if err != nil {
+ releaseConn(err)
+ return nil, err
+ }
+ // Note: ownership of dc passes to the *Rows, to be freed
+ // with releaseConn.
+ rows := &Rows{
+ dc: dc,
+ releaseConn: releaseConn,
+ rowsi: rowsi,
+ }
+ return rows, nil
+ }
+ }
+
+ dc.Lock()
+ si, err := dc.ci.Prepare(query)
+ dc.Unlock()
if err != nil {
- stmt.Close()
+ releaseConn(err)
return nil, err
}
- rows.closeStmt = stmt
+
+ ds := driverStmt{dc, si}
+ rowsi, err := rowsiFromStatement(ds, args...)
+ if err != nil {
+ releaseConn(err)
+ dc.Lock()
+ si.Close()
+ dc.Unlock()
+ return nil, err
+ }
+
+ // Note: ownership of ci passes to the *Rows, to be freed
+ // with releaseConn.
+ rows := &Rows{
+ dc: dc,
+ releaseConn: releaseConn,
+ rowsi: rowsi,
+ closeStmt: si,
+ }
return rows, nil
}
@@ -411,18 +795,20 @@ func (db *DB) Begin() (*Tx, error) {
}
func (db *DB) begin() (tx *Tx, err error) {
- ci, err := db.conn()
+ dc, err := db.conn()
if err != nil {
return nil, err
}
- txi, err := ci.Begin()
+ dc.Lock()
+ txi, err := dc.ci.Begin()
+ dc.Unlock()
if err != nil {
- db.putConn(ci, err)
+ db.putConn(dc, err)
return nil, err
}
return &Tx{
db: db,
- ci: ci,
+ dc: dc,
txi: txi,
}, nil
}
@@ -441,15 +827,11 @@ func (db *DB) Driver() driver.Driver {
type Tx struct {
db *DB
- // ci is owned exclusively until Commit or Rollback, at which point
+ // dc is owned exclusively until Commit or Rollback, at which point
// it's returned with putConn.
- ci driver.Conn
+ dc *driverConn
txi driver.Tx
- // cimu is held while somebody is using ci (between grabConn
- // and releaseConn)
- cimu sync.Mutex
-
// done transitions from false to true exactly once, on Commit
// or Rollback. once done, all operations fail with
// ErrTxDone.
@@ -463,21 +845,16 @@ func (tx *Tx) close() {
panic("double close") // internal error
}
tx.done = true
- tx.db.putConn(tx.ci, nil)
- tx.ci = nil
+ tx.db.putConn(tx.dc, nil)
+ tx.dc = nil
tx.txi = nil
}
-func (tx *Tx) grabConn() (driver.Conn, error) {
+func (tx *Tx) grabConn() (*driverConn, error) {
if tx.done {
return nil, ErrTxDone
}
- tx.cimu.Lock()
- return tx.ci, nil
-}
-
-func (tx *Tx) releaseConn() {
- tx.cimu.Unlock()
+ return tx.dc, nil
}
// Commit commits the transaction.
@@ -486,6 +863,8 @@ func (tx *Tx) Commit() error {
return ErrTxDone
}
defer tx.close()
+ tx.dc.Lock()
+ defer tx.dc.Unlock()
return tx.txi.Commit()
}
@@ -495,6 +874,8 @@ func (tx *Tx) Rollback() error {
return ErrTxDone
}
defer tx.close()
+ tx.dc.Lock()
+ defer tx.dc.Unlock()
return tx.txi.Rollback()
}
@@ -518,21 +899,25 @@ func (tx *Tx) Prepare(query string) (*Stmt, error) {
// Perhaps just looking at the reference count (by noting
// Stmt.Close) would be enough. We might also want a finalizer
// on Stmt to drop the reference count.
- ci, err := tx.grabConn()
+ dc, err := tx.grabConn()
if err != nil {
return nil, err
}
- defer tx.releaseConn()
- si, err := ci.Prepare(query)
+ dc.Lock()
+ si, err := dc.ci.Prepare(query)
+ dc.Unlock()
if err != nil {
return nil, err
}
stmt := &Stmt{
- db: tx.db,
- tx: tx,
- txsi: si,
+ db: tx.db,
+ tx: tx,
+ txsi: &driverStmt{
+ Locker: dc,
+ si: si,
+ },
query: query,
}
return stmt, nil
@@ -556,16 +941,20 @@ func (tx *Tx) Stmt(stmt *Stmt) *Stmt {
if tx.db != stmt.db {
return &Stmt{stickyErr: errors.New("sql: Tx.Stmt: statement from different database used")}
}
- ci, err := tx.grabConn()
+ dc, err := tx.grabConn()
if err != nil {
return &Stmt{stickyErr: err}
}
- defer tx.releaseConn()
- si, err := ci.Prepare(stmt.query)
+ dc.Lock()
+ si, err := dc.ci.Prepare(stmt.query)
+ dc.Unlock()
return &Stmt{
- db: tx.db,
- tx: tx,
- txsi: si,
+ db: tx.db,
+ tx: tx,
+ txsi: &driverStmt{
+ Locker: dc,
+ si: si,
+ },
query: stmt.query,
stickyErr: err,
}
@@ -574,51 +963,46 @@ func (tx *Tx) Stmt(stmt *Stmt) *Stmt {
// Exec executes a query that doesn't return rows.
// For example: an INSERT and UPDATE.
func (tx *Tx) Exec(query string, args ...interface{}) (Result, error) {
- ci, err := tx.grabConn()
+ dc, err := tx.grabConn()
if err != nil {
return nil, err
}
- defer tx.releaseConn()
- if execer, ok := ci.(driver.Execer); ok {
+ if execer, ok := dc.ci.(driver.Execer); ok {
dargs, err := driverArgs(nil, args)
if err != nil {
return nil, err
}
+ dc.Lock()
resi, err := execer.Exec(query, dargs)
+ dc.Unlock()
if err == nil {
- return result{resi}, nil
+ return driverResult{dc, resi}, nil
}
if err != driver.ErrSkip {
return nil, err
}
}
- sti, err := ci.Prepare(query)
+ dc.Lock()
+ si, err := dc.ci.Prepare(query)
+ dc.Unlock()
if err != nil {
return nil, err
}
- defer sti.Close()
+ defer withLock(dc, func() { si.Close() })
- return resultFromStatement(sti, args...)
+ return resultFromStatement(driverStmt{dc, si}, args...)
}
// Query executes a query that returns rows, typically a SELECT.
func (tx *Tx) Query(query string, args ...interface{}) (*Rows, error) {
- if tx.done {
- return nil, ErrTxDone
- }
- stmt, err := tx.Prepare(query)
+ dc, err := tx.grabConn()
if err != nil {
return nil, err
}
- rows, err := stmt.Query(args...)
- if err != nil {
- stmt.Close()
- return nil, err
- }
- rows.closeStmt = stmt
- return rows, err
+ releaseConn := func(error) {}
+ return tx.db.queryConn(dc, releaseConn, query, args)
}
// QueryRow executes a query that is expected to return at most one row.
@@ -631,7 +1015,7 @@ func (tx *Tx) QueryRow(query string, args ...interface{}) *Row {
// connStmt is a prepared statement on a particular connection.
type connStmt struct {
- ci driver.Conn
+ dc *driverConn
si driver.Stmt
}
@@ -642,9 +1026,11 @@ type Stmt struct {
query string // that created the Stmt
stickyErr error // if non-nil, this error is returned for all operations
+ closemu sync.RWMutex // held exclusively during close, for read otherwise.
+
// If in a transaction, else both nil:
tx *Tx
- txsi driver.Stmt
+ txsi *driverStmt
mu sync.Mutex // protects the rest of the fields
closed bool
@@ -659,39 +1045,47 @@ type Stmt struct {
// Exec executes a prepared statement with the given arguments and
// returns a Result summarizing the effect of the statement.
func (s *Stmt) Exec(args ...interface{}) (Result, error) {
- _, releaseConn, si, err := s.connStmt()
+ s.closemu.RLock()
+ defer s.closemu.RUnlock()
+ dc, releaseConn, si, err := s.connStmt()
if err != nil {
return nil, err
}
defer releaseConn(nil)
- return resultFromStatement(si, args...)
+ return resultFromStatement(driverStmt{dc, si}, args...)
}
-func resultFromStatement(si driver.Stmt, args ...interface{}) (Result, error) {
+func resultFromStatement(ds driverStmt, args ...interface{}) (Result, error) {
+ ds.Lock()
+ want := ds.si.NumInput()
+ ds.Unlock()
+
// -1 means the driver doesn't know how to count the number of
// placeholders, so we won't sanity check input here and instead let the
// driver deal with errors.
- if want := si.NumInput(); want != -1 && len(args) != want {
+ if want != -1 && len(args) != want {
return nil, fmt.Errorf("sql: expected %d arguments, got %d", want, len(args))
}
- dargs, err := driverArgs(si, args)
+ dargs, err := driverArgs(&ds, args)
if err != nil {
return nil, err
}
- resi, err := si.Exec(dargs)
+ ds.Lock()
+ resi, err := ds.si.Exec(dargs)
+ ds.Unlock()
if err != nil {
return nil, err
}
- return result{resi}, nil
+ return driverResult{ds.Locker, resi}, nil
}
// connStmt returns a free driver connection on which to execute the
// statement, a function to call to release the connection, and a
// statement bound to that connection.
-func (s *Stmt) connStmt() (ci driver.Conn, releaseConn func(error), si driver.Stmt, err error) {
+func (s *Stmt) connStmt() (ci *driverConn, releaseConn func(error), si driver.Stmt, err error) {
if err = s.stickyErr; err != nil {
return
}
@@ -710,19 +1104,27 @@ func (s *Stmt) connStmt() (ci driver.Conn, releaseConn func(error), si driver.St
if err != nil {
return
}
- releaseConn = func(error) { s.tx.releaseConn() }
- return ci, releaseConn, s.txsi, nil
+ releaseConn = func(error) {}
+ return ci, releaseConn, s.txsi.si, nil
}
var cs connStmt
match := false
- for _, v := range s.css {
- // TODO(bradfitz): lazily clean up entries in this
- // list with dead conns while enumerating
- if _, match = s.db.connIfFree(v.ci); match {
+ for i := 0; i < len(s.css); i++ {
+ v := s.css[i]
+ _, err := s.db.connIfFree(v.dc)
+ if err == nil {
+ match = true
cs = v
break
}
+ if err == errConnClosed {
+ // Lazily remove dead conn from our freelist.
+ s.css[i] = s.css[len(s.css)-1]
+ s.css = s.css[:len(s.css)-1]
+ i--
+ }
+
}
s.mu.Unlock()
@@ -730,11 +1132,13 @@ func (s *Stmt) connStmt() (ci driver.Conn, releaseConn func(error), si driver.St
// TODO(bradfitz): or wait for one? make configurable later?
if !match {
for i := 0; ; i++ {
- ci, err := s.db.conn()
+ dc, err := s.db.conn()
if err != nil {
return nil, nil, nil, err
}
- si, err := ci.Prepare(s.query)
+ dc.Lock()
+ si, err := dc.prepareLocked(s.query)
+ dc.Unlock()
if err == driver.ErrBadConn && i < 10 {
continue
}
@@ -742,14 +1146,14 @@ func (s *Stmt) connStmt() (ci driver.Conn, releaseConn func(error), si driver.St
return nil, nil, nil, err
}
s.mu.Lock()
- cs = connStmt{ci, si}
+ cs = connStmt{dc, si}
s.css = append(s.css, cs)
s.mu.Unlock()
break
}
}
- conn := cs.ci
+ conn := cs.dc
releaseConn = func(err error) { s.db.putConn(conn, err) }
return conn, releaseConn, cs.si, nil
}
@@ -757,39 +1161,62 @@ func (s *Stmt) connStmt() (ci driver.Conn, releaseConn func(error), si driver.St
// Query executes a prepared query statement with the given arguments
// and returns the query results as a *Rows.
func (s *Stmt) Query(args ...interface{}) (*Rows, error) {
- ci, releaseConn, si, err := s.connStmt()
+ s.closemu.RLock()
+ defer s.closemu.RUnlock()
+
+ dc, releaseConn, si, err := s.connStmt()
if err != nil {
return nil, err
}
- // -1 means the driver doesn't know how to count the number of
- // placeholders, so we won't sanity check input here and instead let the
- // driver deal with errors.
- if want := si.NumInput(); want != -1 && len(args) != want {
- return nil, fmt.Errorf("sql: statement expects %d inputs; got %d", si.NumInput(), len(args))
- }
-
- dargs, err := driverArgs(si, args)
- if err != nil {
- return nil, err
- }
-
- rowsi, err := si.Query(dargs)
+ ds := driverStmt{dc, si}
+ rowsi, err := rowsiFromStatement(ds, args...)
if err != nil {
releaseConn(err)
return nil, err
}
+
// Note: ownership of ci passes to the *Rows, to be freed
// with releaseConn.
rows := &Rows{
- db: s.db,
- ci: ci,
- releaseConn: releaseConn,
- rowsi: rowsi,
+ dc: dc,
+ rowsi: rowsi,
+ // releaseConn set below
+ }
+ s.db.addDep(s, rows)
+ rows.releaseConn = func(err error) {
+ releaseConn(err)
+ s.db.removeDep(s, rows)
}
return rows, nil
}
+func rowsiFromStatement(ds driverStmt, args ...interface{}) (driver.Rows, error) {
+ ds.Lock()
+ want := ds.si.NumInput()
+ ds.Unlock()
+
+ // -1 means the driver doesn't know how to count the number of
+ // placeholders, so we won't sanity check input here and instead let the
+ // driver deal with errors.
+ if want != -1 && len(args) != want {
+ return nil, fmt.Errorf("sql: statement expects %d inputs; got %d", want, len(args))
+ }
+
+ dargs, err := driverArgs(&ds, args)
+ if err != nil {
+ return nil, err
+ }
+
+ ds.Lock()
+ rowsi, err := ds.si.Query(dargs)
+ ds.Unlock()
+ if err != nil {
+ return nil, err
+ }
+ return rowsi, nil
+}
+
// QueryRow executes a prepared query statement with the given arguments.
// If an error occurs during the execution of the statement, that error will
// be returned by a call to Scan on the returned *Row, which is always non-nil.
@@ -811,6 +1238,9 @@ func (s *Stmt) QueryRow(args ...interface{}) *Row {
// Close closes the statement.
func (s *Stmt) Close() error {
+ s.closemu.Lock()
+ defer s.closemu.Unlock()
+
if s.stickyErr != nil {
return s.stickyErr
}
@@ -823,18 +1253,19 @@ func (s *Stmt) Close() error {
if s.tx != nil {
s.txsi.Close()
- } else {
- for _, v := range s.css {
- if ci, match := s.db.connIfFree(v.ci); match {
- v.si.Close()
- s.db.putConn(ci, nil)
- } else {
- // TODO(bradfitz): care that we can't close
- // this statement because the statement's
- // connection is in use?
- }
- }
+ return nil
}
+
+ return s.db.removeDep(s, s)
+}
+
+func (s *Stmt) finalClose() error {
+ for _, v := range s.css {
+ s.db.noteUnusedDriverStatement(v.dc, v.si)
+ v.dc.removeOpenStmt(v.si)
+ s.db.removeDep(v.dc, s)
+ }
+ s.css = nil
return nil
}
@@ -852,15 +1283,14 @@ func (s *Stmt) Close() error {
// err = rows.Err() // get any error encountered during iteration
// ...
type Rows struct {
- db *DB
- ci driver.Conn // owned; must call putconn when closed to release
+ dc *driverConn // owned; must call releaseConn when closed to release
releaseConn func(error)
rowsi driver.Rows
closed bool
lastcols []driver.Value
lasterr error
- closeStmt *Stmt // if non-nil, statement to Close on close
+ closeStmt driver.Stmt // if non-nil, statement to Close on close
}
// Next prepares the next result row for reading with the Scan method.
@@ -936,24 +1366,6 @@ func (rs *Rows) Scan(dest ...interface{}) error {
return fmt.Errorf("sql: Scan error on column index %d: %v", i, err)
}
}
- for _, dp := range dest {
- b, ok := dp.(*[]byte)
- if !ok {
- continue
- }
- if *b == nil {
- // If the []byte is now nil (for a NULL value),
- // don't fall through to below which would
- // turn it into a non-nil 0-length byte slice
- continue
- }
- if _, ok = dp.(*RawBytes); ok {
- continue
- }
- clone := make([]byte, len(*b))
- copy(clone, *b)
- *b = clone
- }
return nil
}
@@ -966,10 +1378,10 @@ func (rs *Rows) Close() error {
}
rs.closed = true
err := rs.rowsi.Close()
- rs.releaseConn(err)
if rs.closeStmt != nil {
rs.closeStmt.Close()
}
+ rs.releaseConn(err)
return err
}
@@ -1026,6 +1438,31 @@ type Result interface {
RowsAffected() (int64, error)
}
-type result struct {
- driver.Result
+type driverResult struct {
+ sync.Locker // the *driverConn
+ resi driver.Result
+}
+
+func (dr driverResult) LastInsertId() (int64, error) {
+ dr.Lock()
+ defer dr.Unlock()
+ return dr.resi.LastInsertId()
+}
+
+func (dr driverResult) RowsAffected() (int64, error) {
+ dr.Lock()
+ defer dr.Unlock()
+ return dr.resi.RowsAffected()
+}
+
+func stack() string {
+ var buf [2 << 10]byte
+ return string(buf[:runtime.Stack(buf[:], false)])
+}
+
+// withLock runs while holding lk.
+func withLock(lk sync.Locker, fn func()) {
+ lk.Lock()
+ fn()
+ lk.Unlock()
}
diff --git a/libgo/go/database/sql/sql_test.go b/libgo/go/database/sql/sql_test.go
index b702b850ec2..e6cc667fa97 100644
--- a/libgo/go/database/sql/sql_test.go
+++ b/libgo/go/database/sql/sql_test.go
@@ -5,11 +5,11 @@
package sql
import (
- "database/sql/driver"
"fmt"
"reflect"
"runtime"
"strings"
+ "sync"
"testing"
"time"
)
@@ -17,10 +17,10 @@ import (
func init() {
type dbConn struct {
db *DB
- c driver.Conn
+ c *driverConn
}
freedFrom := make(map[dbConn]string)
- putConnHook = func(db *DB, c driver.Conn) {
+ putConnHook = func(db *DB, c *driverConn) {
for _, oc := range db.freeConn {
if oc == c {
// print before panic, as panic may get lost due to conflicting panic
@@ -38,7 +38,15 @@ const fakeDBName = "foo"
var chrisBirthday = time.Unix(123456789, 0)
-func newTestDB(t *testing.T, name string) *DB {
+type testOrBench interface {
+ Fatalf(string, ...interface{})
+ Errorf(string, ...interface{})
+ Fatal(...interface{})
+ Error(...interface{})
+ Logf(string, ...interface{})
+}
+
+func newTestDB(t testOrBench, name string) *DB {
db, err := Open("test", fakeDBName)
if err != nil {
t.Fatalf("Open: %v", err)
@@ -52,17 +60,42 @@ func newTestDB(t *testing.T, name string) *DB {
exec(t, db, "INSERT|people|name=Bob,age=?,photo=BPHOTO", 2)
exec(t, db, "INSERT|people|name=Chris,age=?,photo=CPHOTO,bdate=?", 3, chrisBirthday)
}
+ if name == "magicquery" {
+ // Magic table name and column, known by fakedb_test.go.
+ exec(t, db, "CREATE|magicquery|op=string,millis=int32")
+ exec(t, db, "INSERT|magicquery|op=sleep,millis=10")
+ }
return db
}
-func exec(t *testing.T, db *DB, query string, args ...interface{}) {
+func exec(t testOrBench, db *DB, query string, args ...interface{}) {
_, err := db.Exec(query, args...)
if err != nil {
t.Fatalf("Exec of %q: %v", query, err)
}
}
-func closeDB(t *testing.T, db *DB) {
+func closeDB(t testOrBench, db *DB) {
+ if e := recover(); e != nil {
+ fmt.Printf("Panic: %v\n", e)
+ panic(e)
+ }
+ defer setHookpostCloseConn(nil)
+ setHookpostCloseConn(func(_ *fakeConn, err error) {
+ if err != nil {
+ t.Errorf("Error closing fakeConn: %v", err)
+ }
+ })
+ for i, dc := range db.freeConn {
+ if n := len(dc.openStmt); n > 0 {
+ // Just a sanity check. This is legal in
+ // general, but if we make the tests clean up
+ // their statements first, then we can safely
+ // verify this is always zero here, and any
+ // other value is a leak.
+ t.Errorf("while closing db, freeConn %d/%d had %d open stmts; want 0", i, len(db.freeConn), n)
+ }
+ }
err := db.Close()
if err != nil {
t.Fatalf("error closing DB: %v", err)
@@ -75,7 +108,52 @@ func numPrepares(t *testing.T, db *DB) int {
if n := len(db.freeConn); n != 1 {
t.Fatalf("free conns = %d; want 1", n)
}
- return db.freeConn[0].(*fakeConn).numPrepare
+ return db.freeConn[0].ci.(*fakeConn).numPrepare
+}
+
+func (db *DB) numDeps() int {
+ db.mu.Lock()
+ defer db.mu.Unlock()
+ return len(db.dep)
+}
+
+// Dependencies are closed via a goroutine, so this polls waiting for
+// numDeps to fall to want, waiting up to d.
+func (db *DB) numDepsPollUntil(want int, d time.Duration) int {
+ deadline := time.Now().Add(d)
+ for {
+ n := db.numDeps()
+ if n <= want || time.Now().After(deadline) {
+ return n
+ }
+ time.Sleep(50 * time.Millisecond)
+ }
+}
+
+func (db *DB) numFreeConns() int {
+ db.mu.Lock()
+ defer db.mu.Unlock()
+ return len(db.freeConn)
+}
+
+func (db *DB) dumpDeps(t *testing.T) {
+ for fc := range db.dep {
+ db.dumpDep(t, 0, fc, map[finalCloser]bool{})
+ }
+}
+
+func (db *DB) dumpDep(t *testing.T, depth int, dep finalCloser, seen map[finalCloser]bool) {
+ seen[dep] = true
+ indent := strings.Repeat(" ", depth)
+ ds := db.dep[dep]
+ for k := range ds {
+ t.Logf("%s%T (%p) waiting for -> %T (%p)", indent, dep, dep, k, k)
+ if fc, ok := k.(finalCloser); ok {
+ if !seen[fc] {
+ db.dumpDep(t, depth+1, fc, seen)
+ }
+ }
+ }
}
func TestQuery(t *testing.T) {
@@ -114,7 +192,7 @@ func TestQuery(t *testing.T) {
// And verify that the final rows.Next() call, which hit EOF,
// also closed the rows connection.
- if n := len(db.freeConn); n != 1 {
+ if n := db.numFreeConns(); n != 1 {
t.Fatalf("free conns after query hitting EOF = %d; want 1", n)
}
if prepares := numPrepares(t, db) - prepares0; prepares != 1 {
@@ -270,6 +348,35 @@ func TestStatementQueryRow(t *testing.T) {
}
+// golang.org/issue/3734
+func TestStatementQueryRowConcurrent(t *testing.T) {
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+ stmt, err := db.Prepare("SELECT|people|age|name=?")
+ if err != nil {
+ t.Fatalf("Prepare: %v", err)
+ }
+ defer stmt.Close()
+
+ const n = 10
+ ch := make(chan error, n)
+ for i := 0; i < n; i++ {
+ go func() {
+ var age int
+ err := stmt.QueryRow("Alice").Scan(&age)
+ if err == nil && age != 1 {
+ err = fmt.Errorf("unexpected age %d", age)
+ }
+ ch <- err
+ }()
+ }
+ for i := 0; i < n; i++ {
+ if err := <-ch; err != nil {
+ t.Error(err)
+ }
+ }
+}
+
// just a test of fakedb itself
func TestBogusPreboundParameters(t *testing.T) {
db := newTestDB(t, "foo")
@@ -448,6 +555,30 @@ func TestIssue2542Deadlock(t *testing.T) {
}
}
+// From golang.org/issue/3865
+func TestCloseStmtBeforeRows(t *testing.T) {
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+
+ s, err := db.Prepare("SELECT|people|name|")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ r, err := s.Query()
+ if err != nil {
+ s.Close()
+ t.Fatal(err)
+ }
+
+ err = s.Close()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ r.Close()
+}
+
// Tests fix for issue 2788, that we bind nil to a []byte if the
// value in the column is sql null
func TestNullByteSlice(t *testing.T) {
@@ -520,7 +651,7 @@ func TestQueryRowClosingStmt(t *testing.T) {
if len(db.freeConn) != 1 {
t.Fatalf("expected 1 free conn")
}
- fakeConn := db.freeConn[0].(*fakeConn)
+ fakeConn := db.freeConn[0].ci.(*fakeConn)
if made, closed := fakeConn.stmtsMade, fakeConn.stmtsClosed; made != closed {
t.Errorf("statement close mismatch: made %d, closed %d", made, closed)
}
@@ -641,7 +772,337 @@ func nullTestRun(t *testing.T, spec nullTestSpec) {
}
}
-func stack() string {
- buf := make([]byte, 1024)
- return string(buf[:runtime.Stack(buf, false)])
+// golang.org/issue/4859
+func TestQueryRowNilScanDest(t *testing.T) {
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+ var name *string // nil pointer
+ err := db.QueryRow("SELECT|people|name|").Scan(name)
+ want := "sql: Scan error on column index 0: destination pointer is nil"
+ if err == nil || err.Error() != want {
+ t.Errorf("error = %q; want %q", err.Error(), want)
+ }
+}
+
+func TestIssue4902(t *testing.T) {
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+
+ driver := db.driver.(*fakeDriver)
+ opens0 := driver.openCount
+
+ var stmt *Stmt
+ var err error
+ for i := 0; i < 10; i++ {
+ stmt, err = db.Prepare("SELECT|people|name|")
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = stmt.Close()
+ if err != nil {
+ t.Fatal(err)
+ }
+ }
+
+ opens := driver.openCount - opens0
+ if opens > 1 {
+ t.Errorf("opens = %d; want <= 1", opens)
+ t.Logf("db = %#v", db)
+ t.Logf("driver = %#v", driver)
+ t.Logf("stmt = %#v", stmt)
+ }
+}
+
+// Issue 3857
+// This used to deadlock.
+func TestSimultaneousQueries(t *testing.T) {
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+
+ tx, err := db.Begin()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer tx.Rollback()
+
+ r1, err := tx.Query("SELECT|people|name|")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer r1.Close()
+
+ r2, err := tx.Query("SELECT|people|name|")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer r2.Close()
+}
+
+func TestMaxIdleConns(t *testing.T) {
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+
+ tx, err := db.Begin()
+ if err != nil {
+ t.Fatal(err)
+ }
+ tx.Commit()
+ if got := len(db.freeConn); got != 1 {
+ t.Errorf("freeConns = %d; want 1", got)
+ }
+
+ db.SetMaxIdleConns(0)
+
+ if got := len(db.freeConn); got != 0 {
+ t.Errorf("freeConns after set to zero = %d; want 0", got)
+ }
+
+ tx, err = db.Begin()
+ if err != nil {
+ t.Fatal(err)
+ }
+ tx.Commit()
+ if got := len(db.freeConn); got != 0 {
+ t.Errorf("freeConns = %d; want 0", got)
+ }
+}
+
+// golang.org/issue/5323
+func TestStmtCloseDeps(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping in short mode")
+ }
+ defer setHookpostCloseConn(nil)
+ setHookpostCloseConn(func(_ *fakeConn, err error) {
+ if err != nil {
+ t.Errorf("Error closing fakeConn: %v", err)
+ }
+ })
+
+ db := newTestDB(t, "magicquery")
+ defer closeDB(t, db)
+
+ driver := db.driver.(*fakeDriver)
+
+ driver.mu.Lock()
+ opens0 := driver.openCount
+ closes0 := driver.closeCount
+ driver.mu.Unlock()
+ openDelta0 := opens0 - closes0
+
+ stmt, err := db.Prepare("SELECT|magicquery|op|op=?,millis=?")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Start 50 parallel slow queries.
+ const (
+ nquery = 50
+ sleepMillis = 25
+ nbatch = 2
+ )
+ var wg sync.WaitGroup
+ for batch := 0; batch < nbatch; batch++ {
+ for i := 0; i < nquery; i++ {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ var op string
+ if err := stmt.QueryRow("sleep", sleepMillis).Scan(&op); err != nil && err != ErrNoRows {
+ t.Error(err)
+ }
+ }()
+ }
+ // Sleep for twice the expected length of time for the
+ // batch of 50 queries above to finish before starting
+ // the next round.
+ time.Sleep(2 * sleepMillis * time.Millisecond)
+ }
+ wg.Wait()
+
+ if g, w := db.numFreeConns(), 2; g != w {
+ t.Errorf("free conns = %d; want %d", g, w)
+ }
+
+ if n := db.numDepsPollUntil(4, time.Second); n > 4 {
+ t.Errorf("number of dependencies = %d; expected <= 4", n)
+ db.dumpDeps(t)
+ }
+
+ driver.mu.Lock()
+ opens := driver.openCount - opens0
+ closes := driver.closeCount - closes0
+ driver.mu.Unlock()
+ openDelta := (driver.openCount - driver.closeCount) - openDelta0
+
+ if openDelta > 2 {
+ t.Logf("open calls = %d", opens)
+ t.Logf("close calls = %d", closes)
+ t.Logf("open delta = %d", openDelta)
+ t.Errorf("db connections opened = %d; want <= 2", openDelta)
+ db.dumpDeps(t)
+ }
+
+ if len(stmt.css) > nquery {
+ t.Errorf("len(stmt.css) = %d; want <= %d", len(stmt.css), nquery)
+ }
+
+ if err := stmt.Close(); err != nil {
+ t.Fatal(err)
+ }
+
+ if g, w := db.numFreeConns(), 2; g != w {
+ t.Errorf("free conns = %d; want %d", g, w)
+ }
+
+ if n := db.numDepsPollUntil(2, time.Second); n > 2 {
+ t.Errorf("number of dependencies = %d; expected <= 2", n)
+ db.dumpDeps(t)
+ }
+
+ db.SetMaxIdleConns(0)
+
+ if g, w := db.numFreeConns(), 0; g != w {
+ t.Errorf("free conns = %d; want %d", g, w)
+ }
+
+ if n := db.numDepsPollUntil(0, time.Second); n > 0 {
+ t.Errorf("number of dependencies = %d; expected 0", n)
+ db.dumpDeps(t)
+ }
+}
+
+// golang.org/issue/5046
+func TestCloseConnBeforeStmts(t *testing.T) {
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+
+ defer setHookpostCloseConn(nil)
+ setHookpostCloseConn(func(_ *fakeConn, err error) {
+ if err != nil {
+ t.Errorf("Error closing fakeConn: %v; from %s", err, stack())
+ db.dumpDeps(t)
+ t.Errorf("DB = %#v", db)
+ }
+ })
+
+ stmt, err := db.Prepare("SELECT|people|name|")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if len(db.freeConn) != 1 {
+ t.Fatalf("expected 1 freeConn; got %d", len(db.freeConn))
+ }
+ dc := db.freeConn[0]
+ if dc.closed {
+ t.Errorf("conn shouldn't be closed")
+ }
+
+ if n := len(dc.openStmt); n != 1 {
+ t.Errorf("driverConn num openStmt = %d; want 1", n)
+ }
+ err = db.Close()
+ if err != nil {
+ t.Errorf("db Close = %v", err)
+ }
+ if !dc.closed {
+ t.Errorf("after db.Close, driverConn should be closed")
+ }
+ if n := len(dc.openStmt); n != 0 {
+ t.Errorf("driverConn num openStmt = %d; want 0", n)
+ }
+
+ err = stmt.Close()
+ if err != nil {
+ t.Errorf("Stmt close = %v", err)
+ }
+
+ if !dc.closed {
+ t.Errorf("conn should be closed")
+ }
+ if dc.ci != nil {
+ t.Errorf("after Stmt Close, driverConn's Conn interface should be nil")
+ }
+}
+
+// golang.org/issue/5283: don't release the Rows' connection in Close
+// before calling Stmt.Close.
+func TestRowsCloseOrder(t *testing.T) {
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+
+ db.SetMaxIdleConns(0)
+ setStrictFakeConnClose(t)
+ defer setStrictFakeConnClose(nil)
+
+ rows, err := db.Query("SELECT|people|age,name|")
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = rows.Close()
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+func manyConcurrentQueries(t testOrBench) {
+ maxProcs, numReqs := 16, 500
+ if testing.Short() {
+ maxProcs, numReqs = 4, 50
+ }
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(maxProcs))
+
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+
+ stmt, err := db.Prepare("SELECT|people|name|")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer stmt.Close()
+
+ var wg sync.WaitGroup
+ wg.Add(numReqs)
+
+ reqs := make(chan bool)
+ defer close(reqs)
+
+ for i := 0; i < maxProcs*2; i++ {
+ go func() {
+ for _ = range reqs {
+ rows, err := stmt.Query()
+ if err != nil {
+ t.Errorf("error on query: %v", err)
+ wg.Done()
+ continue
+ }
+
+ var name string
+ for rows.Next() {
+ rows.Scan(&name)
+ }
+ rows.Close()
+
+ wg.Done()
+ }
+ }()
+ }
+
+ for i := 0; i < numReqs; i++ {
+ reqs <- true
+ }
+
+ wg.Wait()
+}
+
+func TestConcurrency(t *testing.T) {
+ manyConcurrentQueries(t)
+}
+
+func BenchmarkConcurrency(b *testing.B) {
+ b.ReportAllocs()
+ for i := 0; i < b.N; i++ {
+ manyConcurrentQueries(b)
+ }
}
diff --git a/libgo/go/debug/dwarf/buf.go b/libgo/go/debug/dwarf/buf.go
index 08e37be4b38..53c46eb4b81 100644
--- a/libgo/go/debug/dwarf/buf.go
+++ b/libgo/go/debug/dwarf/buf.go
@@ -13,17 +13,45 @@ import (
// Data buffer being decoded.
type buf struct {
- dwarf *Data
- u *unit
- order binary.ByteOrder
- name string
- off Offset
- data []byte
- err error
+ dwarf *Data
+ order binary.ByteOrder
+ format dataFormat
+ name string
+ off Offset
+ data []byte
+ err error
}
-func makeBuf(d *Data, u *unit, name string, off Offset, data []byte) buf {
- return buf{d, u, d.order, name, off, data, nil}
+// Data format, other than byte order. This affects the handling of
+// certain field formats.
+type dataFormat interface {
+ // DWARF version number. Zero means unknown.
+ version() int
+
+ // 64-bit DWARF format?
+ dwarf64() (dwarf64 bool, isKnown bool)
+
+ // Size of an address, in bytes. Zero means unknown.
+ addrsize() int
+}
+
+// Some parts of DWARF have no data format, e.g., abbrevs.
+type unknownFormat struct{}
+
+func (u unknownFormat) version() int {
+ return 0
+}
+
+func (u unknownFormat) dwarf64() (bool, bool) {
+ return false, false
+}
+
+func (u unknownFormat) addrsize() int {
+ return 0
+}
+
+func makeBuf(d *Data, format dataFormat, name string, off Offset, data []byte) buf {
+ return buf{d, d.order, format, name, off, data, nil}
}
func (b *buf) uint8() uint8 {
@@ -121,17 +149,15 @@ func (b *buf) int() int64 {
// Address-sized uint.
func (b *buf) addr() uint64 {
- if b.u != nil {
- switch b.u.addrsize {
- case 1:
- return uint64(b.uint8())
- case 2:
- return uint64(b.uint16())
- case 4:
- return uint64(b.uint32())
- case 8:
- return uint64(b.uint64())
- }
+ switch b.format.addrsize() {
+ case 1:
+ return uint64(b.uint8())
+ case 2:
+ return uint64(b.uint16())
+ case 4:
+ return uint64(b.uint32())
+ case 8:
+ return uint64(b.uint64())
}
b.error("unknown address size")
return 0
diff --git a/libgo/go/debug/dwarf/entry.go b/libgo/go/debug/dwarf/entry.go
index 4761d74cd79..ada723163a4 100644
--- a/libgo/go/debug/dwarf/entry.go
+++ b/libgo/go/debug/dwarf/entry.go
@@ -40,7 +40,7 @@ func (d *Data) parseAbbrev(off uint32) (abbrevTable, error) {
} else {
data = data[off:]
}
- b := makeBuf(d, nil, "abbrev", 0, data)
+ b := makeBuf(d, unknownFormat{}, "abbrev", 0, data)
// Error handling is simplified by the buf getters
// returning an endless stream of 0s after an error.
@@ -190,13 +190,16 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
case formFlag:
val = b.uint8() == 1
case formFlagPresent:
+ // The attribute is implicitly indicated as present, and no value is
+ // encoded in the debugging information entry itself.
val = true
// lineptr, loclistptr, macptr, rangelistptr
case formSecOffset:
- if b.u == nil {
+ is64, known := b.format.dwarf64()
+ if !known {
b.error("unknown size for DW_FORM_sec_offset")
- } else if b.u.dwarf64 {
+ } else if is64 {
val = Offset(b.uint64())
} else {
val = Offset(b.uint32())
@@ -204,14 +207,20 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
// reference to other entry
case formRefAddr:
- if b.u == nil {
+ vers := b.format.version()
+ if vers == 0 {
b.error("unknown version for DW_FORM_ref_addr")
- } else if b.u.version == 2 {
+ } else if vers == 2 {
val = Offset(b.addr())
- } else if b.u.dwarf64 {
- val = Offset(b.uint64())
} else {
- val = Offset(b.uint32())
+ is64, known := b.format.dwarf64()
+ if !known {
+ b.error("unknown size for DW_FORM_ref_addr")
+ } else if is64 {
+ val = Offset(b.uint64())
+ } else {
+ val = Offset(b.uint32())
+ }
}
case formRef1:
val = Offset(b.uint8()) + ubase
@@ -234,7 +243,7 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
if b.err != nil {
return nil
}
- b1 := makeBuf(b.dwarf, b.u, "str", 0, b.dwarf.str)
+ b1 := makeBuf(b.dwarf, unknownFormat{}, "str", 0, b.dwarf.str)
b1.skip(int(off))
val = b1.string()
if b1.err != nil {
diff --git a/libgo/go/debug/dwarf/line.go b/libgo/go/debug/dwarf/line.go
index 3ab2f2b30cb..c463c3b0d8f 100644
--- a/libgo/go/debug/dwarf/line.go
+++ b/libgo/go/debug/dwarf/line.go
@@ -112,7 +112,7 @@ func (d *Data) readUnitLine(i int, u *unit) error {
func (d *Data) readAddressRanges(off Offset, base uint64, u *unit) error {
b := makeBuf(d, u, "ranges", off, d.ranges[off:])
var highest uint64
- switch u.addrsize {
+ switch u.addrsize() {
case 1:
highest = 0xff
case 2:
diff --git a/libgo/go/debug/dwarf/type.go b/libgo/go/debug/dwarf/type.go
index 2ef8ca01bf8..54000fbd75e 100644
--- a/libgo/go/debug/dwarf/type.go
+++ b/libgo/go/debug/dwarf/type.go
@@ -435,7 +435,9 @@ func (d *Data) Type(off Offset) (Type, error) {
goto Error
}
if loc, ok := kid.Val(AttrDataMemberLoc).([]byte); ok {
- b := makeBuf(d, nil, "location", 0, loc)
+ // TODO: Should have original compilation
+ // unit here, not unknownFormat.
+ b := makeBuf(d, unknownFormat{}, "location", 0, loc)
if b.uint8() != opPlusUconst {
err = DecodeError{"info", kid.Offset, "unexpected opcode"}
goto Error
diff --git a/libgo/go/debug/dwarf/unit.go b/libgo/go/debug/dwarf/unit.go
index b1903208715..8e09298a8b4 100644
--- a/libgo/go/debug/dwarf/unit.go
+++ b/libgo/go/debug/dwarf/unit.go
@@ -10,17 +10,31 @@ import "strconv"
// Each unit has its own abbreviation table and address size.
type unit struct {
- base Offset // byte offset of header within the aggregate info
- off Offset // byte offset of data within the aggregate info
- lineoff Offset // byte offset of data within the line info
- data []byte
- atable abbrevTable
- addrsize int
- version int
- dwarf64 bool // True for 64-bit DWARF format
- dir string
- pc []addrRange // PC ranges in this compilation unit
- lines []mapLineInfo // PC -> line mapping
+ base Offset // byte offset of header within the aggregate info
+ off Offset // byte offset of data within the aggregate info
+ lineoff Offset // byte offset of data within the line info
+ data []byte
+ atable abbrevTable
+ asize int
+ vers int
+ is64 bool // True for 64-bit DWARF format
+ dir string
+ pc []addrRange // PC ranges in this compilation unit
+ lines []mapLineInfo // PC -> line mapping
+}
+
+// Implement the dataFormat interface.
+
+func (u *unit) version() int {
+ return u.vers
+}
+
+func (u *unit) dwarf64() (bool, bool) {
+ return u.is64, true
+}
+
+func (u *unit) addrsize() int {
+ return u.asize
}
// A range is an address range.
@@ -32,12 +46,12 @@ type addrRange struct {
func (d *Data) parseUnits() ([]unit, error) {
// Count units.
nunit := 0
- b := makeBuf(d, nil, "info", 0, d.info)
+ b := makeBuf(d, unknownFormat{}, "info", 0, d.info)
for len(b.data) > 0 {
len := b.uint32()
if len == 0xffffffff {
len64 := b.uint64()
- if len64 != uint64(int(len64)) {
+ if len64 != uint64(uint32(len64)) {
b.error("unit length overflow")
break
}
@@ -51,14 +65,14 @@ func (d *Data) parseUnits() ([]unit, error) {
}
// Again, this time writing them down.
- b = makeBuf(d, nil, "info", 0, d.info)
+ b = makeBuf(d, unknownFormat{}, "info", 0, d.info)
units := make([]unit, nunit)
for i := range units {
u := &units[i]
u.base = b.off
n := b.uint32()
if n == 0xffffffff {
- u.dwarf64 = true
+ u.is64 = true
n = uint32(b.uint64())
}
vers := b.uint16()
@@ -66,6 +80,7 @@ func (d *Data) parseUnits() ([]unit, error) {
b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
break
}
+ u.vers = int(vers)
atable, err := d.parseAbbrev(b.uint32())
if err != nil {
if b.err == nil {
@@ -73,9 +88,8 @@ func (d *Data) parseUnits() ([]unit, error) {
}
break
}
- u.version = int(vers)
u.atable = atable
- u.addrsize = int(b.uint8())
+ u.asize = int(b.uint8())
u.off = b.off
u.data = b.bytes(int(n - (2 + 4 + 1)))
}
diff --git a/libgo/go/debug/elf/file.go b/libgo/go/debug/elf/file.go
index eb3d72f7126..8023eb0a0b7 100644
--- a/libgo/go/debug/elf/file.go
+++ b/libgo/go/debug/elf/file.go
@@ -422,6 +422,10 @@ func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) {
return nil, nil, errors.New("cannot load string table section")
}
+ // The first entry is all zeros.
+ var skip [Sym32Size]byte
+ symtab.Read(skip[:])
+
symbols := make([]Symbol, symtab.Len()/Sym32Size)
i := 0
@@ -461,6 +465,10 @@ func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) {
return nil, nil, errors.New("cannot load string table section")
}
+ // The first entry is all zeros.
+ var skip [Sym64Size]byte
+ symtab.Read(skip[:])
+
symbols := make([]Symbol, symtab.Len()/Sym64Size)
i := 0
@@ -533,10 +541,10 @@ func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error {
symNo := rela.Info >> 32
t := R_X86_64(rela.Info & 0xffff)
- if symNo >= uint64(len(symbols)) {
+ if symNo == 0 || symNo > uint64(len(symbols)) {
continue
}
- sym := &symbols[symNo]
+ sym := &symbols[symNo-1]
if SymType(sym.Info&0xf) != STT_SECTION {
// We don't handle non-section relocations for now.
continue
@@ -597,6 +605,10 @@ func (f *File) DWARF() (*dwarf.Data, error) {
}
// Symbols returns the symbol table for f.
+//
+// For compatibility with Go 1.0, Symbols omits the null symbol at index 0.
+// After retrieving the symbols as symtab, an externally supplied index x
+// corresponds to symtab[x-1], not symtab[x].
func (f *File) Symbols() ([]Symbol, error) {
sym, _, err := f.getSymbols(SHT_SYMTAB)
return sym, err
@@ -706,7 +718,7 @@ func (f *File) gnuVersionInit(str []byte) {
// which came from offset i of the symbol table.
func (f *File) gnuVersion(i int, sym *ImportedSymbol) {
// Each entry is two bytes.
- i = i * 2
+ i = (i + 1) * 2
if i >= len(f.gnuVersym) {
return
}
diff --git a/libgo/go/debug/gosym/symtab.go b/libgo/go/debug/gosym/symtab.go
index cc01e0b9d69..81ed4fb27dc 100644
--- a/libgo/go/debug/gosym/symtab.go
+++ b/libgo/go/debug/gosym/symtab.go
@@ -99,31 +99,116 @@ type Table struct {
}
type sym struct {
- value uint32
- gotype uint32
+ value uint64
+ gotype uint64
typ byte
name []byte
}
-var littleEndianSymtab = []byte{0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00}
+var littleEndianSymtab = []byte{0xFD, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00}
+var bigEndianSymtab = []byte{0xFF, 0xFF, 0xFF, 0xFD, 0x00, 0x00, 0x00}
+
+var oldLittleEndianSymtab = []byte{0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00}
func walksymtab(data []byte, fn func(sym) error) error {
var order binary.ByteOrder = binary.BigEndian
- if bytes.HasPrefix(data, littleEndianSymtab) {
+ newTable := false
+ switch {
+ case bytes.HasPrefix(data, oldLittleEndianSymtab):
+ // Same as Go 1.0, but little endian.
+ // Format was used during interim development between Go 1.0 and Go 1.1.
+ // Should not be widespread, but easy to support.
data = data[6:]
order = binary.LittleEndian
+ case bytes.HasPrefix(data, bigEndianSymtab):
+ newTable = true
+ case bytes.HasPrefix(data, littleEndianSymtab):
+ newTable = true
+ order = binary.LittleEndian
+ }
+ var ptrsz int
+ if newTable {
+ if len(data) < 8 {
+ return &DecodingError{len(data), "unexpected EOF", nil}
+ }
+ ptrsz = int(data[7])
+ if ptrsz != 4 && ptrsz != 8 {
+ return &DecodingError{7, "invalid pointer size", ptrsz}
+ }
+ data = data[8:]
}
var s sym
p := data
- for len(p) >= 6 {
- s.value = order.Uint32(p[0:4])
- typ := p[4]
- if typ&0x80 == 0 {
- return &DecodingError{len(data) - len(p) + 4, "bad symbol type", typ}
+ for len(p) >= 4 {
+ var typ byte
+ if newTable {
+ // Symbol type, value, Go type.
+ typ = p[0] & 0x3F
+ wideValue := p[0]&0x40 != 0
+ goType := p[0]&0x80 != 0
+ if typ < 26 {
+ typ += 'A'
+ } else {
+ typ += 'a' - 26
+ }
+ s.typ = typ
+ p = p[1:]
+ if wideValue {
+ if len(p) < ptrsz {
+ return &DecodingError{len(data), "unexpected EOF", nil}
+ }
+ // fixed-width value
+ if ptrsz == 8 {
+ s.value = order.Uint64(p[0:8])
+ p = p[8:]
+ } else {
+ s.value = uint64(order.Uint32(p[0:4]))
+ p = p[4:]
+ }
+ } else {
+ // varint value
+ s.value = 0
+ shift := uint(0)
+ for len(p) > 0 && p[0]&0x80 != 0 {
+ s.value |= uint64(p[0]&0x7F) << shift
+ shift += 7
+ p = p[1:]
+ }
+ if len(p) == 0 {
+ return &DecodingError{len(data), "unexpected EOF", nil}
+ }
+ s.value |= uint64(p[0]) << shift
+ p = p[1:]
+ }
+ if goType {
+ if len(p) < ptrsz {
+ return &DecodingError{len(data), "unexpected EOF", nil}
+ }
+ // fixed-width go type
+ if ptrsz == 8 {
+ s.gotype = order.Uint64(p[0:8])
+ p = p[8:]
+ } else {
+ s.gotype = uint64(order.Uint32(p[0:4]))
+ p = p[4:]
+ }
+ }
+ } else {
+ // Value, symbol type.
+ s.value = uint64(order.Uint32(p[0:4]))
+ if len(p) < 5 {
+ return &DecodingError{len(data), "unexpected EOF", nil}
+ }
+ typ = p[4]
+ if typ&0x80 == 0 {
+ return &DecodingError{len(data) - len(p) + 4, "bad symbol type", typ}
+ }
+ typ &^= 0x80
+ s.typ = typ
+ p = p[5:]
}
- typ &^= 0x80
- s.typ = typ
- p = p[5:]
+
+ // Name.
var i int
var nnul int
for i = 0; i < len(p); i++ {
@@ -142,13 +227,21 @@ func walksymtab(data []byte, fn func(sym) error) error {
}
}
}
- if i+nnul+4 > len(p) {
+ if len(p) < i+nnul {
return &DecodingError{len(data), "unexpected EOF", nil}
}
s.name = p[0:i]
i += nnul
- s.gotype = order.Uint32(p[i : i+4])
- p = p[i+4:]
+ p = p[i:]
+
+ if !newTable {
+ if len(p) < 4 {
+ return &DecodingError{len(data), "unexpected EOF", nil}
+ }
+ // Go type.
+ s.gotype = uint64(order.Uint32(p[:4]))
+ p = p[4:]
+ }
fn(s)
}
return nil
diff --git a/libgo/go/debug/macho/file.go b/libgo/go/debug/macho/file.go
index 6577803a075..9d912e7a087 100644
--- a/libgo/go/debug/macho/file.go
+++ b/libgo/go/debug/macho/file.go
@@ -142,6 +142,8 @@ type Dysymtab struct {
* Mach-O reader
*/
+// FormatError is returned by some operations if the data does
+// not have the correct format for an object file.
type FormatError struct {
off int64
msg string
diff --git a/libgo/go/encoding/ascii85/ascii85.go b/libgo/go/encoding/ascii85/ascii85.go
index 705022792a8..e2afc587140 100644
--- a/libgo/go/encoding/ascii85/ascii85.go
+++ b/libgo/go/encoding/ascii85/ascii85.go
@@ -296,5 +296,4 @@ func (d *decoder) Read(p []byte) (n int, err error) {
nn, d.readErr = d.r.Read(d.buf[d.nbuf:])
d.nbuf += nn
}
- panic("unreachable")
}
diff --git a/libgo/go/encoding/asn1/marshal.go b/libgo/go/encoding/asn1/marshal.go
index 0c216fdb3cd..adaf80dcdb0 100644
--- a/libgo/go/encoding/asn1/marshal.go
+++ b/libgo/go/encoding/asn1/marshal.go
@@ -460,7 +460,6 @@ func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameter
default:
return marshalUTF8String(out, v.String())
}
- return
}
return StructuralError{"unknown Go type"}
diff --git a/libgo/go/encoding/base32/base32.go b/libgo/go/encoding/base32/base32.go
index dbefc48fa37..fe17b732207 100644
--- a/libgo/go/encoding/base32/base32.go
+++ b/libgo/go/encoding/base32/base32.go
@@ -6,8 +6,10 @@
package base32
import (
+ "bytes"
"io"
"strconv"
+ "strings"
)
/*
@@ -48,6 +50,13 @@ var StdEncoding = NewEncoding(encodeStd)
// It is typically used in DNS.
var HexEncoding = NewEncoding(encodeHex)
+var removeNewlinesMapper = func(r rune) rune {
+ if r == '\r' || r == '\n' {
+ return -1
+ }
+ return r
+}
+
/*
* Encoder
*/
@@ -228,40 +237,47 @@ func (e CorruptInputError) Error() string {
// decode is like Decode but returns an additional 'end' value, which
// indicates if end-of-message padding was encountered and thus any
-// additional data is an error.
+// additional data is an error. This method assumes that src has been
+// stripped of all supported whitespace ('\r' and '\n').
func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
- osrc := src
+ olen := len(src)
for len(src) > 0 && !end {
// Decode quantum using the base32 alphabet
var dbuf [8]byte
dlen := 8
- // do the top bytes contain any data?
for j := 0; j < 8; {
if len(src) == 0 {
- return n, false, CorruptInputError(len(osrc) - len(src) - j)
+ return n, false, CorruptInputError(olen - len(src) - j)
}
in := src[0]
src = src[1:]
- if in == '\r' || in == '\n' {
- // Ignore this character.
- continue
- }
if in == '=' && j >= 2 && len(src) < 8 {
- // We've reached the end and there's
- // padding, the rest should be padded
- for k := 0; k < 8-j-1; k++ {
+ // We've reached the end and there's padding
+ if len(src)+j < 8-1 {
+ // not enough padding
+ return n, false, CorruptInputError(olen)
+ }
+ for k := 0; k < 8-1-j; k++ {
if len(src) > k && src[k] != '=' {
- return n, false, CorruptInputError(len(osrc) - len(src) + k - 1)
+ // incorrect padding
+ return n, false, CorruptInputError(olen - len(src) + k - 1)
}
}
- dlen = j
- end = true
+ dlen, end = j, true
+ // 7, 5 and 2 are not valid padding lengths, and so 1, 3 and 6 are not
+ // valid dlen values. See RFC 4648 Section 6 "Base 32 Encoding" listing
+ // the five valid padding lengths, and Section 9 "Illustrations and
+ // Examples" for an illustration for how the the 1st, 3rd and 6th base32
+ // src bytes do not yield enough information to decode a dst byte.
+ if dlen == 1 || dlen == 3 || dlen == 6 {
+ return n, false, CorruptInputError(olen - len(src) - 1)
+ }
break
}
dbuf[j] = enc.decodeMap[in]
if dbuf[j] == 0xFF {
- return n, false, CorruptInputError(len(osrc) - len(src) - 1)
+ return n, false, CorruptInputError(olen - len(src) - 1)
}
j++
}
@@ -269,16 +285,16 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
// Pack 8x 5-bit source blocks into 5 byte destination
// quantum
switch dlen {
- case 7, 8:
+ case 8:
dst[4] = dbuf[6]<<5 | dbuf[7]
fallthrough
- case 6, 5:
+ case 7:
dst[3] = dbuf[4]<<7 | dbuf[5]<<2 | dbuf[6]>>3
fallthrough
- case 4:
+ case 5:
dst[2] = dbuf[3]<<4 | dbuf[4]>>1
fallthrough
- case 3:
+ case 4:
dst[1] = dbuf[1]<<6 | dbuf[2]<<1 | dbuf[3]>>4
fallthrough
case 2:
@@ -288,11 +304,11 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
switch dlen {
case 2:
n += 1
- case 3, 4:
+ case 4:
n += 2
case 5:
n += 3
- case 6, 7:
+ case 7:
n += 4
case 8:
n += 5
@@ -307,12 +323,14 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
// number of bytes successfully written and CorruptInputError.
// New line characters (\r and \n) are ignored.
func (enc *Encoding) Decode(dst, src []byte) (n int, err error) {
+ src = bytes.Map(removeNewlinesMapper, src)
n, _, err = enc.decode(dst, src)
return
}
// DecodeString returns the bytes represented by the base32 string s.
func (enc *Encoding) DecodeString(s string) ([]byte, error) {
+ s = strings.Map(removeNewlinesMapper, s)
dbuf := make([]byte, enc.DecodedLen(len(s)))
n, err := enc.Decode(dbuf, []byte(s))
return dbuf[:n], err
@@ -377,9 +395,34 @@ func (d *decoder) Read(p []byte) (n int, err error) {
return n, d.err
}
+type newlineFilteringReader struct {
+ wrapped io.Reader
+}
+
+func (r *newlineFilteringReader) Read(p []byte) (int, error) {
+ n, err := r.wrapped.Read(p)
+ for n > 0 {
+ offset := 0
+ for i, b := range p[0:n] {
+ if b != '\r' && b != '\n' {
+ if i != offset {
+ p[offset] = b
+ }
+ offset++
+ }
+ }
+ if offset > 0 {
+ return offset, err
+ }
+ // Previous buffer entirely whitespace, read again
+ n, err = r.wrapped.Read(p)
+ }
+ return n, err
+}
+
// NewDecoder constructs a new base32 stream decoder.
func NewDecoder(enc *Encoding, r io.Reader) io.Reader {
- return &decoder{enc: enc, r: r}
+ return &decoder{enc: enc, r: &newlineFilteringReader{r}}
}
// DecodedLen returns the maximum length in bytes of the decoded data
diff --git a/libgo/go/encoding/base32/base32_test.go b/libgo/go/encoding/base32/base32_test.go
index 98365e18cfc..63298d1c94c 100644
--- a/libgo/go/encoding/base32/base32_test.go
+++ b/libgo/go/encoding/base32/base32_test.go
@@ -8,6 +8,7 @@ import (
"bytes"
"io"
"io/ioutil"
+ "strings"
"testing"
)
@@ -137,27 +138,48 @@ func TestDecoderBuffering(t *testing.T) {
}
func TestDecodeCorrupt(t *testing.T) {
- type corrupt struct {
- e string
- p int
- }
- examples := []corrupt{
+ testCases := []struct {
+ input string
+ offset int // -1 means no corruption.
+ }{
+ {"", -1},
{"!!!!", 0},
{"x===", 0},
{"AA=A====", 2},
{"AAA=AAAA", 3},
{"MMMMMMMMM", 8},
{"MMMMMM", 0},
+ {"A=", 1},
+ {"AA=", 3},
+ {"AA==", 4},
+ {"AA===", 5},
+ {"AAAA=", 5},
+ {"AAAA==", 6},
+ {"AAAAA=", 6},
+ {"AAAAA==", 7},
+ {"A=======", 1},
+ {"AA======", -1},
+ {"AAA=====", 3},
+ {"AAAA====", -1},
+ {"AAAAA===", -1},
+ {"AAAAAA==", 6},
+ {"AAAAAAA=", -1},
+ {"AAAAAAAA", -1},
}
-
- for _, e := range examples {
- dbuf := make([]byte, StdEncoding.DecodedLen(len(e.e)))
- _, err := StdEncoding.Decode(dbuf, []byte(e.e))
+ for _, tc := range testCases {
+ dbuf := make([]byte, StdEncoding.DecodedLen(len(tc.input)))
+ _, err := StdEncoding.Decode(dbuf, []byte(tc.input))
+ if tc.offset == -1 {
+ if err != nil {
+ t.Error("Decoder wrongly detected coruption in", tc.input)
+ }
+ continue
+ }
switch err := err.(type) {
case CorruptInputError:
- testEqual(t, "Corruption in %q at offset %v, want %v", e.e, int(err), e.p)
+ testEqual(t, "Corruption in %q at offset %v, want %v", tc.input, int(err), tc.offset)
default:
- t.Error("Decoder failed to detect corruption in", e)
+ t.Error("Decoder failed to detect corruption in", tc)
}
}
}
@@ -195,20 +217,7 @@ func TestBig(t *testing.T) {
}
}
-func TestNewLineCharacters(t *testing.T) {
- // Each of these should decode to the string "sure", without errors.
- const expected = "sure"
- examples := []string{
- "ON2XEZI=",
- "ON2XEZI=\r",
- "ON2XEZI=\n",
- "ON2XEZI=\r\n",
- "ON2XEZ\r\nI=",
- "ON2X\rEZ\nI=",
- "ON2X\nEZ\rI=",
- "ON2XEZ\nI=",
- "ON2XEZI\n=",
- }
+func testStringEncoding(t *testing.T, expected string, examples []string) {
for _, e := range examples {
buf, err := StdEncoding.DecodeString(e)
if err != nil {
@@ -220,3 +229,58 @@ func TestNewLineCharacters(t *testing.T) {
}
}
}
+
+func TestNewLineCharacters(t *testing.T) {
+ // Each of these should decode to the string "sure", without errors.
+ examples := []string{
+ "ON2XEZI=",
+ "ON2XEZI=\r",
+ "ON2XEZI=\n",
+ "ON2XEZI=\r\n",
+ "ON2XEZ\r\nI=",
+ "ON2X\rEZ\nI=",
+ "ON2X\nEZ\rI=",
+ "ON2XEZ\nI=",
+ "ON2XEZI\n=",
+ }
+ testStringEncoding(t, "sure", examples)
+
+ // Each of these should decode to the string "foobar", without errors.
+ examples = []string{
+ "MZXW6YTBOI======",
+ "MZXW6YTBOI=\r\n=====",
+ }
+ testStringEncoding(t, "foobar", examples)
+}
+
+func TestDecoderIssue4779(t *testing.T) {
+ encoded := `JRXXEZLNEBUXA43VNUQGI33MN5ZCA43JOQQGC3LFOQWCAY3PNZZWKY3UMV2HK4
+RAMFSGS4DJONUWG2LOM4QGK3DJOQWCA43FMQQGI3YKMVUXK43NN5SCA5DFNVYG64RANFXGG2LENFSH
+K3TUEB2XIIDMMFRG64TFEBSXIIDEN5WG64TFEBWWCZ3OMEQGC3DJOF2WCLRAKV2CAZLONFWQUYLEEB
+WWS3TJNUQHMZLONFQW2LBAOF2WS4ZANZXXG5DSOVSCAZLYMVZGG2LUMF2GS33OEB2WY3DBNVRW6IDM
+MFRG64TJOMQG42LTNEQHK5AKMFWGS4LVNFYCAZLYEBSWCIDDN5WW233EN4QGG33OONSXC5LBOQXCAR
+DVNFZSAYLVORSSA2LSOVZGKIDEN5WG64RANFXAU4TFOBZGK2DFNZSGK4TJOQQGS3RAOZXWY5LQORQX
+IZJAOZSWY2LUEBSXG43FEBRWS3DMOVWSAZDPNRXXEZJAMV2SAZTVM5UWC5BANZ2WY3DBBJYGC4TJMF
+2HK4ROEBCXQY3FOB2GK5LSEBZWS3TUEBXWGY3BMVRWC5BAMN2XA2LEMF2GC5BANZXW4IDQOJXWSZDF
+NZ2CYIDTOVXHIIDJNYFGG5LMOBQSA4LVNEQG6ZTGNFRWSYJAMRSXGZLSOVXHIIDNN5WGY2LUEBQW42
+LNEBUWIIDFON2CA3DBMJXXE5LNFY==
+====`
+ encodedShort := strings.Replace(encoded, "\n", "", -1)
+
+ dec := NewDecoder(StdEncoding, bytes.NewBufferString(encoded))
+ res1, err := ioutil.ReadAll(dec)
+ if err != nil {
+ t.Errorf("ReadAll failed: %v", err)
+ }
+
+ dec = NewDecoder(StdEncoding, bytes.NewBufferString(encodedShort))
+ var res2 []byte
+ res2, err = ioutil.ReadAll(dec)
+ if err != nil {
+ t.Errorf("ReadAll failed: %v", err)
+ }
+
+ if !bytes.Equal(res1, res2) {
+ t.Error("Decoded results not equal")
+ }
+}
diff --git a/libgo/go/encoding/base64/base64.go b/libgo/go/encoding/base64/base64.go
index e66672a1c93..85e398fd0b7 100644
--- a/libgo/go/encoding/base64/base64.go
+++ b/libgo/go/encoding/base64/base64.go
@@ -6,8 +6,10 @@
package base64
import (
+ "bytes"
"io"
"strconv"
+ "strings"
)
/*
@@ -49,6 +51,13 @@ var StdEncoding = NewEncoding(encodeStd)
// It is typically used in URLs and file names.
var URLEncoding = NewEncoding(encodeURL)
+var removeNewlinesMapper = func(r rune) rune {
+ if r == '\r' || r == '\n' {
+ return -1
+ }
+ return r
+}
+
/*
* Encoder
*/
@@ -208,9 +217,10 @@ func (e CorruptInputError) Error() string {
// decode is like Decode but returns an additional 'end' value, which
// indicates if end-of-message padding was encountered and thus any
-// additional data is an error.
+// additional data is an error. This method assumes that src has been
+// stripped of all supported whitespace ('\r' and '\n').
func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
- osrc := src
+ olen := len(src)
for len(src) > 0 && !end {
// Decode quantum using the base64 alphabet
var dbuf [4]byte
@@ -218,32 +228,26 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
for j := 0; j < 4; {
if len(src) == 0 {
- return n, false, CorruptInputError(len(osrc) - len(src) - j)
+ return n, false, CorruptInputError(olen - len(src) - j)
}
in := src[0]
src = src[1:]
- if in == '\r' || in == '\n' {
- // Ignore this character.
- continue
- }
if in == '=' && j >= 2 && len(src) < 4 {
- // We've reached the end and there's
- // padding
- if len(src) == 0 && j == 2 {
+ // We've reached the end and there's padding
+ if len(src)+j < 4-1 {
// not enough padding
- return n, false, CorruptInputError(len(osrc))
+ return n, false, CorruptInputError(olen)
}
if len(src) > 0 && src[0] != '=' {
// incorrect padding
- return n, false, CorruptInputError(len(osrc) - len(src) - 1)
+ return n, false, CorruptInputError(olen - len(src) - 1)
}
- dlen = j
- end = true
+ dlen, end = j, true
break
}
dbuf[j] = enc.decodeMap[in]
if dbuf[j] == 0xFF {
- return n, false, CorruptInputError(len(osrc) - len(src) - 1)
+ return n, false, CorruptInputError(olen - len(src) - 1)
}
j++
}
@@ -273,12 +277,14 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
// number of bytes successfully written and CorruptInputError.
// New line characters (\r and \n) are ignored.
func (enc *Encoding) Decode(dst, src []byte) (n int, err error) {
+ src = bytes.Map(removeNewlinesMapper, src)
n, _, err = enc.decode(dst, src)
return
}
// DecodeString returns the bytes represented by the base64 string s.
func (enc *Encoding) DecodeString(s string) ([]byte, error) {
+ s = strings.Map(removeNewlinesMapper, s)
dbuf := make([]byte, enc.DecodedLen(len(s)))
n, err := enc.Decode(dbuf, []byte(s))
return dbuf[:n], err
@@ -343,9 +349,34 @@ func (d *decoder) Read(p []byte) (n int, err error) {
return n, d.err
}
+type newlineFilteringReader struct {
+ wrapped io.Reader
+}
+
+func (r *newlineFilteringReader) Read(p []byte) (int, error) {
+ n, err := r.wrapped.Read(p)
+ for n > 0 {
+ offset := 0
+ for i, b := range p[0:n] {
+ if b != '\r' && b != '\n' {
+ if i != offset {
+ p[offset] = b
+ }
+ offset++
+ }
+ }
+ if offset > 0 {
+ return offset, err
+ }
+ // Previous buffer entirely whitespace, read again
+ n, err = r.wrapped.Read(p)
+ }
+ return n, err
+}
+
// NewDecoder constructs a new base64 stream decoder.
func NewDecoder(enc *Encoding, r io.Reader) io.Reader {
- return &decoder{enc: enc, r: r}
+ return &decoder{enc: enc, r: &newlineFilteringReader{r}}
}
// DecodedLen returns the maximum length in bytes of the decoded data
diff --git a/libgo/go/encoding/base64/base64_test.go b/libgo/go/encoding/base64/base64_test.go
index f9b863c364c..579591a88d7 100644
--- a/libgo/go/encoding/base64/base64_test.go
+++ b/libgo/go/encoding/base64/base64_test.go
@@ -9,6 +9,7 @@ import (
"errors"
"io"
"io/ioutil"
+ "strings"
"testing"
"time"
)
@@ -142,11 +143,11 @@ func TestDecoderBuffering(t *testing.T) {
}
func TestDecodeCorrupt(t *testing.T) {
- type corrupt struct {
- e string
- p int
- }
- examples := []corrupt{
+ testCases := []struct {
+ input string
+ offset int // -1 means no corruption.
+ }{
+ {"", -1},
{"!!!!", 0},
{"x===", 1},
{"AA=A", 2},
@@ -154,18 +155,27 @@ func TestDecodeCorrupt(t *testing.T) {
{"AAAAA", 4},
{"AAAAAA", 4},
{"A=", 1},
+ {"A==", 1},
{"AA=", 3},
+ {"AA==", -1},
+ {"AAA=", -1},
+ {"AAAA", -1},
{"AAAAAA=", 7},
}
-
- for _, e := range examples {
- dbuf := make([]byte, StdEncoding.DecodedLen(len(e.e)))
- _, err := StdEncoding.Decode(dbuf, []byte(e.e))
+ for _, tc := range testCases {
+ dbuf := make([]byte, StdEncoding.DecodedLen(len(tc.input)))
+ _, err := StdEncoding.Decode(dbuf, []byte(tc.input))
+ if tc.offset == -1 {
+ if err != nil {
+ t.Error("Decoder wrongly detected coruption in", tc.input)
+ }
+ continue
+ }
switch err := err.(type) {
case CorruptInputError:
- testEqual(t, "Corruption in %q at offset %v, want %v", e.e, int(err), e.p)
+ testEqual(t, "Corruption in %q at offset %v, want %v", tc.input, int(err), tc.offset)
default:
- t.Error("Decoder failed to detect corruption in", e)
+ t.Error("Decoder failed to detect corruption in", tc)
}
}
}
@@ -216,6 +226,8 @@ func TestNewLineCharacters(t *testing.T) {
"c3V\nyZ\rQ==",
"c3VyZ\nQ==",
"c3VyZQ\n==",
+ "c3VyZQ=\n=",
+ "c3VyZQ=\r\n\r\n=",
}
for _, e := range examples {
buf, err := StdEncoding.DecodeString(e)
@@ -257,6 +269,7 @@ func TestDecoderIssue3577(t *testing.T) {
wantErr := errors.New("my error")
next <- nextRead{5, nil}
next <- nextRead{10, wantErr}
+ next <- nextRead{0, wantErr}
d := NewDecoder(StdEncoding, &faultInjectReader{
source: "VHdhcyBicmlsbGlnLCBhbmQgdGhlIHNsaXRoeSB0b3Zlcw==", // twas brillig...
nextc: next,
@@ -275,3 +288,40 @@ func TestDecoderIssue3577(t *testing.T) {
t.Errorf("timeout; Decoder blocked without returning an error")
}
}
+
+func TestDecoderIssue4779(t *testing.T) {
+ encoded := `CP/EAT8AAAEF
+AQEBAQEBAAAAAAAAAAMAAQIEBQYHCAkKCwEAAQUBAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAAB
+BAEDAgQCBQcGCAUDDDMBAAIRAwQhEjEFQVFhEyJxgTIGFJGhsUIjJBVSwWIzNHKC0UMHJZJT8OHx
+Y3M1FqKygyZEk1RkRcKjdDYX0lXiZfKzhMPTdePzRieUpIW0lcTU5PSltcXV5fVWZnaGlqa2xtbm
+9jdHV2d3h5ent8fX5/cRAAICAQIEBAMEBQYHBwYFNQEAAhEDITESBEFRYXEiEwUygZEUobFCI8FS
+0fAzJGLhcoKSQ1MVY3M08SUGFqKygwcmNcLSRJNUoxdkRVU2dGXi8rOEw9N14/NGlKSFtJXE1OT0
+pbXF1eX1VmZ2hpamtsbW5vYnN0dXZ3eHl6e3x//aAAwDAQACEQMRAD8A9VSSSSUpJJJJSkkkJ+Tj
+1kiy1jCJJDnAcCTykpKkuQ6p/jN6FgmxlNduXawwAzaGH+V6jn/R/wCt71zdn+N/qL3kVYFNYB4N
+ji6PDVjWpKp9TSXnvTf8bFNjg3qOEa2n6VlLpj/rT/pf567DpX1i6L1hs9Py67X8mqdtg/rUWbbf
++gkp0kkkklKSSSSUpJJJJT//0PVUkkklKVLq3WMDpGI7KzrNjADtYNXvI/Mqr/Pd/q9W3vaxjnvM
+NaCXE9gNSvGPrf8AWS3qmba5jjsJhoB0DAf0NDf6sevf+/lf8Hj0JJATfWT6/dV6oXU1uOLQeKKn
+EQP+Hubtfe/+R7Mf/g7f5xcocp++Z11JMCJPgFBxOg7/AOuqDx8I/ikpkXkmSdU8mJIJA/O8EMAy
+j+mSARB/17pKVXYWHXjsj7yIex0PadzXMO1zT5KHoNA3HT8ietoGhgjsfA+CSnvvqh/jJtqsrwOv
+2b6NGNzXfTYexzJ+nU7/ALkf4P8Awv6P9KvTQQ4AgyDqCF85Pho3CTB7eHwXoH+LT65uZbX9X+o2
+bqbPb06551Y4
+`
+ encodedShort := strings.Replace(encoded, "\n", "", -1)
+
+ dec := NewDecoder(StdEncoding, bytes.NewBufferString(encoded))
+ res1, err := ioutil.ReadAll(dec)
+ if err != nil {
+ t.Errorf("ReadAll failed: %v", err)
+ }
+
+ dec = NewDecoder(StdEncoding, bytes.NewBufferString(encodedShort))
+ var res2 []byte
+ res2, err = ioutil.ReadAll(dec)
+ if err != nil {
+ t.Errorf("ReadAll failed: %v", err)
+ }
+
+ if !bytes.Equal(res1, res2) {
+ t.Error("Decoded results not equal")
+ }
+}
diff --git a/libgo/go/encoding/binary/binary.go b/libgo/go/encoding/binary/binary.go
index 04d5723c1e2..edbac197d64 100644
--- a/libgo/go/encoding/binary/binary.go
+++ b/libgo/go/encoding/binary/binary.go
@@ -167,9 +167,9 @@ func Read(r io.Reader, order ByteOrder, data interface{}) error {
default:
return errors.New("binary.Read: invalid type " + d.Type().String())
}
- size := dataSize(v)
- if size < 0 {
- return errors.New("binary.Read: invalid type " + v.Type().String())
+ size, err := dataSize(v)
+ if err != nil {
+ return errors.New("binary.Read: " + err.Error())
}
d := &decoder{order: order, buf: make([]byte, size)}
if _, err := io.ReadFull(r, d.buf); err != nil {
@@ -247,64 +247,68 @@ func Write(w io.Writer, order ByteOrder, data interface{}) error {
// Fallback to reflect-based encoding.
v := reflect.Indirect(reflect.ValueOf(data))
- size := dataSize(v)
- if size < 0 {
- return errors.New("binary.Write: invalid type " + v.Type().String())
+ size, err := dataSize(v)
+ if err != nil {
+ return errors.New("binary.Write: " + err.Error())
}
buf := make([]byte, size)
e := &encoder{order: order, buf: buf}
e.value(v)
- _, err := w.Write(buf)
+ _, err = w.Write(buf)
return err
}
// Size returns how many bytes Write would generate to encode the value v, which
// must be a fixed-size value or a slice of fixed-size values, or a pointer to such data.
func Size(v interface{}) int {
- return dataSize(reflect.Indirect(reflect.ValueOf(v)))
+ n, err := dataSize(reflect.Indirect(reflect.ValueOf(v)))
+ if err != nil {
+ return -1
+ }
+ return n
}
// dataSize returns the number of bytes the actual data represented by v occupies in memory.
// For compound structures, it sums the sizes of the elements. Thus, for instance, for a slice
// it returns the length of the slice times the element size and does not count the memory
// occupied by the header.
-func dataSize(v reflect.Value) int {
+func dataSize(v reflect.Value) (int, error) {
if v.Kind() == reflect.Slice {
- elem := sizeof(v.Type().Elem())
- if elem < 0 {
- return -1
+ elem, err := sizeof(v.Type().Elem())
+ if err != nil {
+ return 0, err
}
- return v.Len() * elem
+ return v.Len() * elem, nil
}
return sizeof(v.Type())
}
-func sizeof(t reflect.Type) int {
+func sizeof(t reflect.Type) (int, error) {
switch t.Kind() {
case reflect.Array:
- n := sizeof(t.Elem())
- if n < 0 {
- return -1
+ n, err := sizeof(t.Elem())
+ if err != nil {
+ return 0, err
}
- return t.Len() * n
+ return t.Len() * n, nil
case reflect.Struct:
sum := 0
for i, n := 0, t.NumField(); i < n; i++ {
- s := sizeof(t.Field(i).Type)
- if s < 0 {
- return -1
+ s, err := sizeof(t.Field(i).Type)
+ if err != nil {
+ return 0, err
}
sum += s
}
- return sum
+ return sum, nil
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
- return int(t.Size())
+ return int(t.Size()), nil
}
- return -1
+ return 0, errors.New("invalid type " + t.String())
}
type coder struct {
@@ -514,11 +518,12 @@ func (e *encoder) value(v reflect.Value) {
}
func (d *decoder) skip(v reflect.Value) {
- d.buf = d.buf[dataSize(v):]
+ n, _ := dataSize(v)
+ d.buf = d.buf[n:]
}
func (e *encoder) skip(v reflect.Value) {
- n := dataSize(v)
+ n, _ := dataSize(v)
for i := range e.buf[0:n] {
e.buf[i] = 0
}
diff --git a/libgo/go/encoding/binary/binary_test.go b/libgo/go/encoding/binary/binary_test.go
index cfad8d36c7b..056f0998f27 100644
--- a/libgo/go/encoding/binary/binary_test.go
+++ b/libgo/go/encoding/binary/binary_test.go
@@ -9,6 +9,7 @@ import (
"io"
"math"
"reflect"
+ "strings"
"testing"
)
@@ -149,8 +150,14 @@ func TestWriteT(t *testing.T) {
tv := reflect.Indirect(reflect.ValueOf(ts))
for i, n := 0, tv.NumField(); i < n; i++ {
+ typ := tv.Field(i).Type().String()
+ if typ == "[4]int" {
+ typ = "int" // the problem is int, not the [4]
+ }
if err := Write(buf, BigEndian, tv.Field(i).Interface()); err == nil {
t.Errorf("WriteT.%v: have err == nil, want non-nil", tv.Field(i).Type())
+ } else if !strings.Contains(err.Error(), typ) {
+ t.Errorf("WriteT: have err == %q, want it to mention %s", err, typ)
}
}
}
@@ -238,7 +245,7 @@ func BenchmarkReadStruct(b *testing.B) {
bsr := &byteSliceReader{}
var buf bytes.Buffer
Write(&buf, BigEndian, &s)
- n := dataSize(reflect.ValueOf(s))
+ n, _ := dataSize(reflect.ValueOf(s))
b.SetBytes(int64(n))
t := s
b.ResetTimer()
diff --git a/libgo/go/encoding/binary/varint.go b/libgo/go/encoding/binary/varint.go
index 7035529f279..3a2dfa3c74e 100644
--- a/libgo/go/encoding/binary/varint.go
+++ b/libgo/go/encoding/binary/varint.go
@@ -120,7 +120,6 @@ func ReadUvarint(r io.ByteReader) (uint64, error) {
x |= uint64(b&0x7f) << s
s += 7
}
- panic("unreachable")
}
// ReadVarint reads an encoded signed integer from r and returns it as an int64.
diff --git a/libgo/go/encoding/csv/reader.go b/libgo/go/encoding/csv/reader.go
index db4d988526f..b099caf60a8 100644
--- a/libgo/go/encoding/csv/reader.go
+++ b/libgo/go/encoding/csv/reader.go
@@ -171,7 +171,6 @@ func (r *Reader) ReadAll() (records [][]string, err error) {
}
records = append(records, record)
}
- panic("unreachable")
}
// readRune reads one rune from r, folding \r\n to \n and keeping track
@@ -213,7 +212,6 @@ func (r *Reader) skip(delim rune) error {
return nil
}
}
- panic("unreachable")
}
// parseRecord reads and parses a single csv record from r.
@@ -250,7 +248,6 @@ func (r *Reader) parseRecord() (fields []string, err error) {
return nil, err
}
}
- panic("unreachable")
}
// parseField parses the next field in the record. The read field is
diff --git a/libgo/go/encoding/gob/codec_test.go b/libgo/go/encoding/gob/codec_test.go
index 482212b7467..9e38e31d5da 100644
--- a/libgo/go/encoding/gob/codec_test.go
+++ b/libgo/go/encoding/gob/codec_test.go
@@ -1191,10 +1191,8 @@ func TestInterface(t *testing.T) {
if v1 != nil || v2 != nil {
t.Errorf("item %d inconsistent nils", i)
}
- continue
- if v1.Square() != v2.Square() {
- t.Errorf("item %d inconsistent values: %v %v", i, v1, v2)
- }
+ } else if v1.Square() != v2.Square() {
+ t.Errorf("item %d inconsistent values: %v %v", i, v1, v2)
}
}
}
diff --git a/libgo/go/encoding/gob/decode.go b/libgo/go/encoding/gob/decode.go
index a80d9f9195f..7cc7565409c 100644
--- a/libgo/go/encoding/gob/decode.go
+++ b/libgo/go/encoding/gob/decode.go
@@ -1066,7 +1066,6 @@ func (dec *Decoder) compatibleType(fr reflect.Type, fw typeId, inProgress map[re
case reflect.Struct:
return true
}
- return true
}
// typeString returns a human-readable description of the type identified by remoteId.
diff --git a/libgo/go/encoding/gob/gobencdec_test.go b/libgo/go/encoding/gob/gobencdec_test.go
index 18f4450da6d..ddcd80b1a7a 100644
--- a/libgo/go/encoding/gob/gobencdec_test.go
+++ b/libgo/go/encoding/gob/gobencdec_test.go
@@ -1,4 +1,4 @@
-// Copyright 20011 The Go Authors. All rights reserved.
+// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -348,7 +348,7 @@ func TestGobEncoderFieldsOfDifferentType(t *testing.T) {
t.Fatal("decode error:", err)
}
if y.G.s != "XYZ" {
- t.Fatalf("expected `XYZ` got %c", y.G.s)
+ t.Fatalf("expected `XYZ` got %q", y.G.s)
}
}
diff --git a/libgo/go/encoding/gob/timing_test.go b/libgo/go/encoding/gob/timing_test.go
index 9a0e51d1fe1..f589675dd98 100644
--- a/libgo/go/encoding/gob/timing_test.go
+++ b/libgo/go/encoding/gob/timing_test.go
@@ -50,49 +50,51 @@ func BenchmarkEndToEndByteBuffer(b *testing.B) {
}
func TestCountEncodeMallocs(t *testing.T) {
- defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
+ if runtime.GOMAXPROCS(0) > 1 {
+ t.Skip("skipping; GOMAXPROCS>1")
+ }
+
+ const N = 1000
+
var buf bytes.Buffer
enc := NewEncoder(&buf)
bench := &Bench{7, 3.2, "now is the time", []byte("for all good men")}
- memstats := new(runtime.MemStats)
- runtime.ReadMemStats(memstats)
- mallocs := 0 - memstats.Mallocs
- const count = 1000
- for i := 0; i < count; i++ {
+
+ allocs := testing.AllocsPerRun(N, func() {
err := enc.Encode(bench)
if err != nil {
t.Fatal("encode:", err)
}
- }
- runtime.ReadMemStats(memstats)
- mallocs += memstats.Mallocs
- fmt.Printf("mallocs per encode of type Bench: %d\n", mallocs/count)
+ })
+ fmt.Printf("mallocs per encode of type Bench: %v\n", allocs)
}
func TestCountDecodeMallocs(t *testing.T) {
- defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
+ if runtime.GOMAXPROCS(0) > 1 {
+ t.Skip("skipping; GOMAXPROCS>1")
+ }
+
+ const N = 1000
+
var buf bytes.Buffer
enc := NewEncoder(&buf)
bench := &Bench{7, 3.2, "now is the time", []byte("for all good men")}
- const count = 1000
- for i := 0; i < count; i++ {
+
+ // Fill the buffer with enough to decode
+ testing.AllocsPerRun(N, func() {
err := enc.Encode(bench)
if err != nil {
t.Fatal("encode:", err)
}
- }
+ })
+
dec := NewDecoder(&buf)
- memstats := new(runtime.MemStats)
- runtime.ReadMemStats(memstats)
- mallocs := 0 - memstats.Mallocs
- for i := 0; i < count; i++ {
+ allocs := testing.AllocsPerRun(N, func() {
*bench = Bench{}
err := dec.Decode(&bench)
if err != nil {
t.Fatal("decode:", err)
}
- }
- runtime.ReadMemStats(memstats)
- mallocs += memstats.Mallocs
- fmt.Printf("mallocs per decode of type Bench: %d\n", mallocs/count)
+ })
+ fmt.Printf("mallocs per decode of type Bench: %v\n", allocs)
}
diff --git a/libgo/go/encoding/gob/type.go b/libgo/go/encoding/gob/type.go
index ea0db4eac45..7fa0b499f02 100644
--- a/libgo/go/encoding/gob/type.go
+++ b/libgo/go/encoding/gob/type.go
@@ -526,7 +526,6 @@ func newTypeObject(name string, ut *userTypeInfo, rt reflect.Type) (gobType, err
default:
return nil, errors.New("gob NewTypeObject can't handle type: " + rt.String())
}
- return nil, nil
}
// isExported reports whether this is an exported - upper case - name.
diff --git a/libgo/go/encoding/json/decode.go b/libgo/go/encoding/json/decode.go
index 95e91209184..62ac294b89f 100644
--- a/libgo/go/encoding/json/decode.go
+++ b/libgo/go/encoding/json/decode.go
@@ -33,6 +33,10 @@ import (
// the value pointed at by the pointer. If the pointer is nil, Unmarshal
// allocates a new value for it to point to.
//
+// To unmarshal JSON into a struct, Unmarshal matches incoming object
+// keys to the keys used by Marshal (either the struct field name or its tag),
+// preferring an exact match but also accepting a case-insensitive match.
+//
// To unmarshal JSON into an interface value, Unmarshal unmarshals
// the JSON into the concrete value contained in the interface value.
// If the interface value is nil, that is, has no concrete value stored in it,
@@ -51,17 +55,22 @@ import (
// If no more serious errors are encountered, Unmarshal returns
// an UnmarshalTypeError describing the earliest such error.
//
+// When unmarshaling quoted strings, invalid UTF-8 or
+// invalid UTF-16 surrogate pairs are not treated as an error.
+// Instead, they are replaced by the Unicode replacement
+// character U+FFFD.
+//
func Unmarshal(data []byte, v interface{}) error {
- d := new(decodeState).init(data)
-
- // Quick check for well-formedness.
+ // Check for well-formedness.
// Avoids filling out half a data structure
// before discovering a JSON syntax error.
+ var d decodeState
err := checkValid(data, &d.scan)
if err != nil {
return err
}
+ d.init(data)
return d.unmarshal(v)
}
@@ -252,6 +261,16 @@ func (d *decodeState) value(v reflect.Value) {
}
d.scan.step(&d.scan, '"')
d.scan.step(&d.scan, '"')
+
+ n := len(d.scan.parseState)
+ if n > 0 && d.scan.parseState[n-1] == parseObjectKey {
+ // d.scan thinks we just read an object key; finish the object
+ d.scan.step(&d.scan, ':')
+ d.scan.step(&d.scan, '"')
+ d.scan.step(&d.scan, '"')
+ d.scan.step(&d.scan, '}')
+ }
+
return
}
@@ -730,6 +749,7 @@ func (d *decodeState) valueInterface() interface{} {
switch d.scanWhile(scanSkipSpace) {
default:
d.error(errPhase)
+ panic("unreachable")
case scanBeginArray:
return d.arrayInterface()
case scanBeginObject:
@@ -737,12 +757,11 @@ func (d *decodeState) valueInterface() interface{} {
case scanBeginLiteral:
return d.literalInterface()
}
- panic("unreachable")
}
// arrayInterface is like array but returns []interface{}.
func (d *decodeState) arrayInterface() []interface{} {
- var v []interface{}
+ var v = make([]interface{}, 0)
for {
// Look ahead for ] - can only happen on first iteration.
op := d.scanWhile(scanSkipSpace)
@@ -849,7 +868,6 @@ func (d *decodeState) literalInterface() interface{} {
}
return n
}
- panic("unreachable")
}
// getu4 decodes \uXXXX from the beginning of s, returning the hex value,
diff --git a/libgo/go/encoding/json/decode_test.go b/libgo/go/encoding/json/decode_test.go
index a91c6da01d3..f845f69ab7f 100644
--- a/libgo/go/encoding/json/decode_test.go
+++ b/libgo/go/encoding/json/decode_test.go
@@ -11,6 +11,7 @@ import (
"reflect"
"strings"
"testing"
+ "time"
)
type T struct {
@@ -29,7 +30,7 @@ type V struct {
F3 Number
}
-// ifaceNumAsFloat64/ifaceNumAsNumber are used to test unmarshalling with and
+// ifaceNumAsFloat64/ifaceNumAsNumber are used to test unmarshaling with and
// without UseNumber
var ifaceNumAsFloat64 = map[string]interface{}{
"k1": float64(1),
@@ -239,6 +240,12 @@ var unmarshalTests = []unmarshalTest{
{in: `[1, 2, 3]`, ptr: new([1]int), out: [1]int{1}},
{in: `[1, 2, 3]`, ptr: new([5]int), out: [5]int{1, 2, 3, 0, 0}},
+ // empty array to interface test
+ {in: `[]`, ptr: new([]interface{}), out: []interface{}{}},
+ {in: `null`, ptr: new([]interface{}), out: []interface{}(nil)},
+ {in: `{"T":[]}`, ptr: new(map[string]interface{}), out: map[string]interface{}{"T": []interface{}{}}},
+ {in: `{"T":null}`, ptr: new(map[string]interface{}), out: map[string]interface{}{"T": interface{}(nil)}},
+
// composite tests
{in: allValueIndent, ptr: new(All), out: allValue},
{in: allValueCompact, ptr: new(All), out: allValue},
@@ -323,6 +330,43 @@ var unmarshalTests = []unmarshalTest{
ptr: new(S10),
out: S10{S13: S13{S8: S8{S9: S9{Y: 2}}}},
},
+
+ // invalid UTF-8 is coerced to valid UTF-8.
+ {
+ in: "\"hello\xffworld\"",
+ ptr: new(string),
+ out: "hello\ufffdworld",
+ },
+ {
+ in: "\"hello\xc2\xc2world\"",
+ ptr: new(string),
+ out: "hello\ufffd\ufffdworld",
+ },
+ {
+ in: "\"hello\xc2\xffworld\"",
+ ptr: new(string),
+ out: "hello\ufffd\ufffdworld",
+ },
+ {
+ in: "\"hello\\ud800world\"",
+ ptr: new(string),
+ out: "hello\ufffdworld",
+ },
+ {
+ in: "\"hello\\ud800\\ud800world\"",
+ ptr: new(string),
+ out: "hello\ufffd\ufffdworld",
+ },
+ {
+ in: "\"hello\\ud800\\ud800world\"",
+ ptr: new(string),
+ out: "hello\ufffd\ufffdworld",
+ },
+ {
+ in: "\"hello\xed\xa0\x80\xed\xb0\x80world\"",
+ ptr: new(string),
+ out: "hello\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdworld",
+ },
}
func TestMarshal(t *testing.T) {
@@ -1107,3 +1151,43 @@ func TestUnmarshalUnexported(t *testing.T) {
t.Errorf("got %q, want %q", out, want)
}
}
+
+// Time3339 is a time.Time which encodes to and from JSON
+// as an RFC 3339 time in UTC.
+type Time3339 time.Time
+
+func (t *Time3339) UnmarshalJSON(b []byte) error {
+ if len(b) < 2 || b[0] != '"' || b[len(b)-1] != '"' {
+ return fmt.Errorf("types: failed to unmarshal non-string value %q as an RFC 3339 time", b)
+ }
+ tm, err := time.Parse(time.RFC3339, string(b[1:len(b)-1]))
+ if err != nil {
+ return err
+ }
+ *t = Time3339(tm)
+ return nil
+}
+
+func TestUnmarshalJSONLiteralError(t *testing.T) {
+ var t3 Time3339
+ err := Unmarshal([]byte(`"0000-00-00T00:00:00Z"`), &t3)
+ if err == nil {
+ t.Fatalf("expected error; got time %v", time.Time(t3))
+ }
+ if !strings.Contains(err.Error(), "range") {
+ t.Errorf("got err = %v; want out of range error", err)
+ }
+}
+
+// Test that extra object elements in an array do not result in a
+// "data changing underfoot" error.
+// Issue 3717
+func TestSkipArrayObjects(t *testing.T) {
+ json := `[{}]`
+ var dest [0]interface{}
+
+ err := Unmarshal([]byte(json), &dest)
+ if err != nil {
+ t.Errorf("got error %q, want nil", err)
+ }
+}
diff --git a/libgo/go/encoding/json/encode.go b/libgo/go/encoding/json/encode.go
index fb57f1d51b2..85727ba61c0 100644
--- a/libgo/go/encoding/json/encode.go
+++ b/libgo/go/encoding/json/encode.go
@@ -3,7 +3,8 @@
// license that can be found in the LICENSE file.
// Package json implements encoding and decoding of JSON objects as defined in
-// RFC 4627.
+// RFC 4627. The mapping between JSON objects and Go values is described
+// in the documentation for the Marshal and Unmarshal functions.
//
// See "JSON and Go" for an introduction to this package:
// http://golang.org/doc/articles/json_and_go.html
@@ -38,8 +39,8 @@ import (
//
// Floating point, integer, and Number values encode as JSON numbers.
//
-// String values encode as JSON strings, with each invalid UTF-8 sequence
-// replaced by the encoding of the Unicode replacement character U+FFFD.
+// String values encode as JSON strings. InvalidUTF8Error will be returned
+// if an invalid UTF-8 sequence is encountered.
// The angle brackets "<" and ">" are escaped to "\u003c" and "\u003e"
// to keep some browsers from misinterpreting JSON output as HTML.
//
@@ -86,9 +87,21 @@ import (
// underscores and slashes.
//
// Anonymous struct fields are usually marshaled as if their inner exported fields
-// were fields in the outer struct, subject to the usual Go visibility rules.
+// were fields in the outer struct, subject to the usual Go visibility rules amended
+// as described in the next paragraph.
// An anonymous struct field with a name given in its JSON tag is treated as
-// having that name instead of as anonymous.
+// having that name, rather than being anonymous.
+//
+// The Go visibility rules for struct fields are amended for JSON when
+// deciding which field to marshal or unmarshal. If there are
+// multiple fields at the same level, and that level is the least
+// nested (and would therefore be the nesting level selected by the
+// usual Go rules), the following extra rules apply:
+//
+// 1) Of those fields, if any are JSON-tagged, only tagged fields are considered,
+// even if there are multiple untagged fields that would otherwise conflict.
+// 2) If there is exactly one field (tagged or not according to the first rule), that is selected.
+// 3) Otherwise there are multiple fields, and all are ignored; no error occurs.
//
// Handling of anonymous struct fields is new in Go 1.1.
// Prior to Go 1.1, anonymous struct fields were ignored. To force ignoring of
@@ -187,8 +200,10 @@ func (e *UnsupportedValueError) Error() string {
return "json: unsupported value: " + e.Str
}
+// An InvalidUTF8Error is returned by Marshal when attempting
+// to encode a string value with invalid UTF-8 sequences.
type InvalidUTF8Error struct {
- S string
+ S string // the whole string value that caused the error
}
func (e *InvalidUTF8Error) Error() string {
@@ -654,27 +669,78 @@ func typeFields(t reflect.Type) []field {
sort.Sort(byName(fields))
- // Remove fields with annihilating name collisions
- // and also fields shadowed by fields with explicit JSON tags.
- name := ""
+ // Delete all fields that are hidden by the Go rules for embedded fields,
+ // except that fields with JSON tags are promoted.
+
+ // The fields are sorted in primary order of name, secondary order
+ // of field index length. Loop over names; for each name, delete
+ // hidden fields by choosing the one dominant field that survives.
out := fields[:0]
- for _, f := range fields {
- if f.name != name {
- name = f.name
- out = append(out, f)
+ for advance, i := 0, 0; i < len(fields); i += advance {
+ // One iteration per name.
+ // Find the sequence of fields with the name of this first field.
+ fi := fields[i]
+ name := fi.name
+ for advance = 1; i+advance < len(fields); advance++ {
+ fj := fields[i+advance]
+ if fj.name != name {
+ break
+ }
+ }
+ if advance == 1 { // Only one field with this name
+ out = append(out, fi)
continue
}
- if n := len(out); n > 0 && out[n-1].name == name && (!out[n-1].tag || f.tag) {
- out = out[:n-1]
+ dominant, ok := dominantField(fields[i : i+advance])
+ if ok {
+ out = append(out, dominant)
}
}
- fields = out
+ fields = out
sort.Sort(byIndex(fields))
return fields
}
+// dominantField looks through the fields, all of which are known to
+// have the same name, to find the single field that dominates the
+// others using Go's embedding rules, modified by the presence of
+// JSON tags. If there are multiple top-level fields, the boolean
+// will be false: This condition is an error in Go and we skip all
+// the fields.
+func dominantField(fields []field) (field, bool) {
+ // The fields are sorted in increasing index-length order. The winner
+ // must therefore be one with the shortest index length. Drop all
+ // longer entries, which is easy: just truncate the slice.
+ length := len(fields[0].index)
+ tagged := -1 // Index of first tagged field.
+ for i, f := range fields {
+ if len(f.index) > length {
+ fields = fields[:i]
+ break
+ }
+ if f.tag {
+ if tagged >= 0 {
+ // Multiple tagged fields at the same level: conflict.
+ // Return no field.
+ return field{}, false
+ }
+ tagged = i
+ }
+ }
+ if tagged >= 0 {
+ return fields[tagged], true
+ }
+ // All remaining fields have the same length. If there's more than one,
+ // we have a conflict (two fields named "X" at the same level) and we
+ // return no field.
+ if len(fields) > 1 {
+ return field{}, false
+ }
+ return fields[0], true
+}
+
var fieldCache struct {
sync.RWMutex
m map[reflect.Type][]field
diff --git a/libgo/go/encoding/json/encode_test.go b/libgo/go/encoding/json/encode_test.go
index be74c997cf8..5be0a992e1c 100644
--- a/libgo/go/encoding/json/encode_test.go
+++ b/libgo/go/encoding/json/encode_test.go
@@ -206,3 +206,107 @@ func TestAnonymousNonstruct(t *testing.T) {
t.Errorf("got %q, want %q", got, want)
}
}
+
+type BugA struct {
+ S string
+}
+
+type BugB struct {
+ BugA
+ S string
+}
+
+type BugC struct {
+ S string
+}
+
+// Legal Go: We never use the repeated embedded field (S).
+type BugX struct {
+ A int
+ BugA
+ BugB
+}
+
+// Issue 5245.
+func TestEmbeddedBug(t *testing.T) {
+ v := BugB{
+ BugA{"A"},
+ "B",
+ }
+ b, err := Marshal(v)
+ if err != nil {
+ t.Fatal("Marshal:", err)
+ }
+ want := `{"S":"B"}`
+ got := string(b)
+ if got != want {
+ t.Fatalf("Marshal: got %s want %s", got, want)
+ }
+ // Now check that the duplicate field, S, does not appear.
+ x := BugX{
+ A: 23,
+ }
+ b, err = Marshal(x)
+ if err != nil {
+ t.Fatal("Marshal:", err)
+ }
+ want = `{"A":23}`
+ got = string(b)
+ if got != want {
+ t.Fatalf("Marshal: got %s want %s", got, want)
+ }
+}
+
+type BugD struct { // Same as BugA after tagging.
+ XXX string `json:"S"`
+}
+
+// BugD's tagged S field should dominate BugA's.
+type BugY struct {
+ BugA
+ BugD
+}
+
+// Test that a field with a tag dominates untagged fields.
+func TestTaggedFieldDominates(t *testing.T) {
+ v := BugY{
+ BugA{"BugA"},
+ BugD{"BugD"},
+ }
+ b, err := Marshal(v)
+ if err != nil {
+ t.Fatal("Marshal:", err)
+ }
+ want := `{"S":"BugD"}`
+ got := string(b)
+ if got != want {
+ t.Fatalf("Marshal: got %s want %s", got, want)
+ }
+}
+
+// There are no tags here, so S should not appear.
+type BugZ struct {
+ BugA
+ BugC
+ BugY // Contains a tagged S field through BugD; should not dominate.
+}
+
+func TestDuplicatedFieldDisappears(t *testing.T) {
+ v := BugZ{
+ BugA{"BugA"},
+ BugC{"BugC"},
+ BugY{
+ BugA{"nested BugA"},
+ BugD{"nested BugD"},
+ },
+ }
+ b, err := Marshal(v)
+ if err != nil {
+ t.Fatal("Marshal:", err)
+ }
+ want := `{}`
+ got := string(b)
+ if got != want {
+ t.Fatalf("Marshal: got %s want %s", got, want)
+ }
+}
diff --git a/libgo/go/encoding/json/scanner_test.go b/libgo/go/encoding/json/scanner_test.go
index adb35715b96..77d3455d307 100644
--- a/libgo/go/encoding/json/scanner_test.go
+++ b/libgo/go/encoding/json/scanner_test.go
@@ -277,9 +277,6 @@ func genArray(n int) []interface{} {
if f > n {
f = n
}
- if n > 0 && f == 0 {
- f = 1
- }
x := make([]interface{}, f)
for i := range x {
x[i] = genValue(((i+1)*n)/f - (i*n)/f)
diff --git a/libgo/go/encoding/xml/marshal.go b/libgo/go/encoding/xml/marshal.go
index aacb50c9cfc..47b00176342 100644
--- a/libgo/go/encoding/xml/marshal.go
+++ b/libgo/go/encoding/xml/marshal.go
@@ -81,8 +81,7 @@ func Marshal(v interface{}) ([]byte, error) {
func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) {
var b bytes.Buffer
enc := NewEncoder(&b)
- enc.prefix = prefix
- enc.indent = indent
+ enc.Indent(prefix, indent)
if err := enc.Encode(v); err != nil {
return nil, err
}
@@ -99,6 +98,14 @@ func NewEncoder(w io.Writer) *Encoder {
return &Encoder{printer{Writer: bufio.NewWriter(w)}}
}
+// Indent sets the encoder to generate XML in which each element
+// begins on a new indented line that starts with prefix and is followed by
+// one or more copies of indent according to the nesting depth.
+func (enc *Encoder) Indent(prefix, indent string) {
+ enc.prefix = prefix
+ enc.indent = indent
+}
+
// Encode writes the XML encoding of v to the stream.
//
// See the documentation for Marshal for details about the conversion
@@ -113,10 +120,76 @@ func (enc *Encoder) Encode(v interface{}) error {
type printer struct {
*bufio.Writer
+ seq int
indent string
prefix string
depth int
indentedIn bool
+ putNewline bool
+ attrNS map[string]string // map prefix -> name space
+ attrPrefix map[string]string // map name space -> prefix
+}
+
+// createAttrPrefix finds the name space prefix attribute to use for the given name space,
+// defining a new prefix if necessary. It returns the prefix and whether it is new.
+func (p *printer) createAttrPrefix(url string) (prefix string, isNew bool) {
+ if prefix = p.attrPrefix[url]; prefix != "" {
+ return prefix, false
+ }
+
+ // The "http://www.w3.org/XML/1998/namespace" name space is predefined as "xml"
+ // and must be referred to that way.
+ // (The "http://www.w3.org/2000/xmlns/" name space is also predefined as "xmlns",
+ // but users should not be trying to use that one directly - that's our job.)
+ if url == xmlURL {
+ return "xml", false
+ }
+
+ // Need to define a new name space.
+ if p.attrPrefix == nil {
+ p.attrPrefix = make(map[string]string)
+ p.attrNS = make(map[string]string)
+ }
+
+ // Pick a name. We try to use the final element of the path
+ // but fall back to _.
+ prefix = strings.TrimRight(url, "/")
+ if i := strings.LastIndex(prefix, "/"); i >= 0 {
+ prefix = prefix[i+1:]
+ }
+ if prefix == "" || !isName([]byte(prefix)) || strings.Contains(prefix, ":") {
+ prefix = "_"
+ }
+ if strings.HasPrefix(prefix, "xml") {
+ // xmlanything is reserved.
+ prefix = "_" + prefix
+ }
+ if p.attrNS[prefix] != "" {
+ // Name is taken. Find a better one.
+ for p.seq++; ; p.seq++ {
+ if id := prefix + "_" + strconv.Itoa(p.seq); p.attrNS[id] == "" {
+ prefix = id
+ break
+ }
+ }
+ }
+
+ p.attrPrefix[url] = prefix
+ p.attrNS[prefix] = url
+
+ p.WriteString(`xmlns:`)
+ p.WriteString(prefix)
+ p.WriteString(`="`)
+ EscapeText(p, []byte(url))
+ p.WriteString(`" `)
+
+ return prefix, true
+}
+
+// deleteAttrPrefix removes an attribute name space prefix.
+func (p *printer) deleteAttrPrefix(prefix string) {
+ delete(p.attrPrefix, p.attrNS[prefix])
+ delete(p.attrNS, prefix)
}
// marshalValue writes one or more XML elements representing val.
@@ -185,7 +258,9 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo) error {
if xmlns != "" {
p.WriteString(` xmlns="`)
// TODO: EscapeString, to avoid the allocation.
- Escape(p, []byte(xmlns))
+ if err := EscapeText(p, []byte(xmlns)); err != nil {
+ return err
+ }
p.WriteByte('"')
}
@@ -200,6 +275,14 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo) error {
continue
}
p.WriteByte(' ')
+ if finfo.xmlns != "" {
+ prefix, created := p.createAttrPrefix(finfo.xmlns)
+ if created {
+ defer p.deleteAttrPrefix(prefix)
+ }
+ p.WriteString(prefix)
+ p.WriteByte(':')
+ }
p.WriteString(finfo.name)
p.WriteString(`="`)
if err := p.marshalSimple(fv.Type(), fv); err != nil {
@@ -244,19 +327,22 @@ func (p *printer) marshalSimple(typ reflect.Type, val reflect.Value) error {
p.WriteString(strconv.FormatFloat(val.Float(), 'g', -1, val.Type().Bits()))
case reflect.String:
// TODO: Add EscapeString.
- Escape(p, []byte(val.String()))
+ EscapeText(p, []byte(val.String()))
case reflect.Bool:
p.WriteString(strconv.FormatBool(val.Bool()))
case reflect.Array:
// will be [...]byte
- bytes := make([]byte, val.Len())
- for i := range bytes {
- bytes[i] = val.Index(i).Interface().(byte)
+ var bytes []byte
+ if val.CanAddr() {
+ bytes = val.Slice(0, val.Len()).Bytes()
+ } else {
+ bytes = make([]byte, val.Len())
+ reflect.Copy(reflect.ValueOf(bytes), val)
}
- Escape(p, bytes)
+ EscapeText(p, bytes)
case reflect.Slice:
// will be []byte
- Escape(p, val.Bytes())
+ EscapeText(p, val.Bytes())
default:
return &UnsupportedTypeError{typ}
}
@@ -273,7 +359,7 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
s := parentStack{printer: p}
for i := range tinfo.fields {
finfo := &tinfo.fields[i]
- if finfo.flags&(fAttr) != 0 {
+ if finfo.flags&fAttr != 0 {
continue
}
vf := finfo.value(val)
@@ -290,10 +376,14 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
case reflect.Bool:
Escape(p, strconv.AppendBool(scratch[:0], vf.Bool()))
case reflect.String:
- Escape(p, []byte(vf.String()))
+ if err := EscapeText(p, []byte(vf.String())); err != nil {
+ return err
+ }
case reflect.Slice:
if elem, ok := vf.Interface().([]byte); ok {
- Escape(p, elem)
+ if err := EscapeText(p, elem); err != nil {
+ return err
+ }
}
case reflect.Struct:
if vf.Type() == timeType {
@@ -387,7 +477,11 @@ func (p *printer) writeIndent(depthDelta int) {
}
p.indentedIn = false
}
- p.WriteByte('\n')
+ if p.putNewline {
+ p.WriteByte('\n')
+ } else {
+ p.putNewline = true
+ }
if len(p.prefix) > 0 {
p.WriteString(p.prefix)
}
diff --git a/libgo/go/encoding/xml/marshal_test.go b/libgo/go/encoding/xml/marshal_test.go
index 67fcfd9ed56..ca14a1e53db 100644
--- a/libgo/go/encoding/xml/marshal_test.go
+++ b/libgo/go/encoding/xml/marshal_test.go
@@ -7,6 +7,7 @@ package xml
import (
"bytes"
"errors"
+ "fmt"
"io"
"reflect"
"strconv"
@@ -265,6 +266,16 @@ type Plain struct {
V interface{}
}
+type MyInt int
+
+type EmbedInt struct {
+ MyInt
+}
+
+type Strings struct {
+ X []string `xml:"A>B,omitempty"`
+}
+
// Unless explicitly stated as such (or *Plain), all of the
// tests below are two-way tests. When introducing new tests,
// please try to make them two-way as well to ensure that
@@ -789,6 +800,17 @@ var marshalTests = []struct {
},
UnmarshalOnly: true,
},
+ {
+ ExpectXML: `42`,
+ Value: &EmbedInt{
+ MyInt: 42,
+ },
+ },
+ // Test omitempty with parent chain; see golang.org/issue/4168.
+ {
+ ExpectXML: ``,
+ Value: &Strings{},
+ },
}
func TestMarshal(t *testing.T) {
@@ -811,6 +833,10 @@ func TestMarshal(t *testing.T) {
}
}
+type AttrParent struct {
+ X string `xml:"X>Y,attr"`
+}
+
var marshalErrorTests = []struct {
Value interface{}
Err string
@@ -838,12 +864,39 @@ var marshalErrorTests = []struct {
Value: &Domain{Comment: []byte("f--bar")},
Err: `xml: comments must not contain "--"`,
},
+ // Reject parent chain with attr, never worked; see golang.org/issue/5033.
+ {
+ Value: &AttrParent{},
+ Err: `xml: X>Y chain not valid with attr flag`,
+ },
+}
+
+var marshalIndentTests = []struct {
+ Value interface{}
+ Prefix string
+ Indent string
+ ExpectXML string
+}{
+ {
+ Value: &SecretAgent{
+ Handle: "007",
+ Identity: "James Bond",
+ Obfuscate: "",
+ },
+ Prefix: "",
+ Indent: "\t",
+ ExpectXML: fmt.Sprintf("\n\tJames Bond\n"),
+ },
}
func TestMarshalErrors(t *testing.T) {
for idx, test := range marshalErrorTests {
- _, err := Marshal(test.Value)
- if err == nil || err.Error() != test.Err {
+ data, err := Marshal(test.Value)
+ if err == nil {
+ t.Errorf("#%d: marshal(%#v) = [success] %q, want error %v", idx, test.Value, data, test.Err)
+ continue
+ }
+ if err.Error() != test.Err {
t.Errorf("#%d: marshal(%#v) = [error] %v, want %v", idx, test.Value, err, test.Err)
}
if test.Kind != reflect.Invalid {
@@ -884,6 +937,19 @@ func TestUnmarshal(t *testing.T) {
}
}
+func TestMarshalIndent(t *testing.T) {
+ for i, test := range marshalIndentTests {
+ data, err := MarshalIndent(test.Value, test.Prefix, test.Indent)
+ if err != nil {
+ t.Errorf("#%d: Error: %s", i, err)
+ continue
+ }
+ if got, want := string(data), test.ExpectXML; got != want {
+ t.Errorf("#%d: MarshalIndent:\nGot:%s\nWant:\n%s", i, got, want)
+ }
+ }
+}
+
type limitedBytesWriter struct {
w io.Writer
remain int // until writes fail
@@ -933,6 +999,16 @@ func TestMarshalWriteErrors(t *testing.T) {
}
}
+func TestMarshalWriteIOErrors(t *testing.T) {
+ enc := NewEncoder(errWriter{})
+
+ expectErr := "unwritable"
+ err := enc.Encode(&Passenger{})
+ if err == nil || err.Error() != expectErr {
+ t.Errorf("EscapeTest = [error] %v, want %v", err, expectErr)
+ }
+}
+
func BenchmarkMarshal(b *testing.B) {
for i := 0; i < b.N; i++ {
Marshal(atomValue)
diff --git a/libgo/go/encoding/xml/read.go b/libgo/go/encoding/xml/read.go
index 344ab514e37..a7a2a9655bb 100644
--- a/libgo/go/encoding/xml/read.go
+++ b/libgo/go/encoding/xml/read.go
@@ -263,7 +263,7 @@ func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error {
strv := finfo.value(sv)
// Look for attribute.
for _, a := range start.Attr {
- if a.Name.Local == finfo.name {
+ if a.Name.Local == finfo.name && (finfo.xmlns == "" || finfo.xmlns == a.Name.Space) {
copyValue(strv, []byte(a.Value))
break
}
@@ -441,7 +441,7 @@ func (p *Decoder) unmarshalPath(tinfo *typeInfo, sv reflect.Value, parents []str
Loop:
for i := range tinfo.fields {
finfo := &tinfo.fields[i]
- if finfo.flags&fElement == 0 || len(finfo.parents) < len(parents) {
+ if finfo.flags&fElement == 0 || len(finfo.parents) < len(parents) || finfo.xmlns != "" && finfo.xmlns != start.Name.Space {
continue
}
for j := range parents {
@@ -493,7 +493,6 @@ Loop:
return true, nil
}
}
- panic("unreachable")
}
// Skip reads tokens until it has consumed the end element
@@ -517,5 +516,4 @@ func (d *Decoder) Skip() error {
return nil
}
}
- panic("unreachable")
}
diff --git a/libgo/go/encoding/xml/read_test.go b/libgo/go/encoding/xml/read_test.go
index b45e2f0e61e..7d28c5d7d6c 100644
--- a/libgo/go/encoding/xml/read_test.go
+++ b/libgo/go/encoding/xml/read_test.go
@@ -6,6 +6,7 @@ package xml
import (
"reflect"
+ "strings"
"testing"
"time"
)
@@ -399,3 +400,224 @@ func TestUnmarshalAttr(t *testing.T) {
t.Fatalf("Unmarshal with %s failed:\nhave %#v,\n want %#v", x, p3.Int, 1)
}
}
+
+type Tables struct {
+ HTable string `xml:"http://www.w3.org/TR/html4/ table"`
+ FTable string `xml:"http://www.w3schools.com/furniture table"`
+}
+
+var tables = []struct {
+ xml string
+ tab Tables
+ ns string
+}{
+ {
+ xml: `` +
+ `` +
+ `` +
+ ``,
+ tab: Tables{"hello", "world"},
+ },
+ {
+ xml: `` +
+ `` +
+ `` +
+ ``,
+ tab: Tables{"hello", "world"},
+ },
+ {
+ xml: `` +
+ `world` +
+ `hello` +
+ ``,
+ tab: Tables{"hello", "world"},
+ },
+ {
+ xml: `` +
+ `` +
+ ``,
+ tab: Tables{},
+ },
+ {
+ xml: `` +
+ `` +
+ ``,
+ tab: Tables{HTable: "only"},
+ ns: "http://www.w3.org/TR/html4/",
+ },
+ {
+ xml: `` +
+ `` +
+ ``,
+ tab: Tables{FTable: "only"},
+ ns: "http://www.w3schools.com/furniture",
+ },
+ {
+ xml: `` +
+ `` +
+ ``,
+ tab: Tables{},
+ ns: "something else entirely",
+ },
+}
+
+func TestUnmarshalNS(t *testing.T) {
+ for i, tt := range tables {
+ var dst Tables
+ var err error
+ if tt.ns != "" {
+ d := NewDecoder(strings.NewReader(tt.xml))
+ d.DefaultSpace = tt.ns
+ err = d.Decode(&dst)
+ } else {
+ err = Unmarshal([]byte(tt.xml), &dst)
+ }
+ if err != nil {
+ t.Errorf("#%d: Unmarshal: %v", i, err)
+ continue
+ }
+ want := tt.tab
+ if dst != want {
+ t.Errorf("#%d: dst=%+v, want %+v", i, dst, want)
+ }
+ }
+}
+
+func TestMarshalNS(t *testing.T) {
+ dst := Tables{"hello", "world"}
+ data, err := Marshal(&dst)
+ if err != nil {
+ t.Fatalf("Marshal: %v", err)
+ }
+ want := ``
+ str := string(data)
+ if str != want {
+ t.Errorf("have: %q\nwant: %q\n", str, want)
+ }
+}
+
+type TableAttrs struct {
+ TAttr TAttr
+}
+
+type TAttr struct {
+ HTable string `xml:"http://www.w3.org/TR/html4/ table,attr"`
+ FTable string `xml:"http://www.w3schools.com/furniture table,attr"`
+ Lang string `xml:"http://www.w3.org/XML/1998/namespace lang,attr,omitempty"`
+ Other1 string `xml:"http://golang.org/xml/ other,attr,omitempty"`
+ Other2 string `xml:"http://golang.org/xmlfoo/ other,attr,omitempty"`
+ Other3 string `xml:"http://golang.org/json/ other,attr,omitempty"`
+ Other4 string `xml:"http://golang.org/2/json/ other,attr,omitempty"`
+}
+
+var tableAttrs = []struct {
+ xml string
+ tab TableAttrs
+ ns string
+}{
+ {
+ xml: ``,
+ tab: TableAttrs{TAttr{HTable: "hello", FTable: "world"}},
+ },
+ {
+ xml: ``,
+ tab: TableAttrs{TAttr{HTable: "hello", FTable: "world"}},
+ },
+ {
+ xml: ``,
+ tab: TableAttrs{TAttr{HTable: "hello", FTable: "world"}},
+ },
+ {
+ // Default space does not apply to attribute names.
+ xml: ``,
+ tab: TableAttrs{TAttr{HTable: "hello", FTable: ""}},
+ },
+ {
+ // Default space does not apply to attribute names.
+ xml: ``,
+ tab: TableAttrs{TAttr{HTable: "", FTable: "world"}},
+ },
+ {
+ xml: ``,
+ tab: TableAttrs{},
+ },
+ {
+ // Default space does not apply to attribute names.
+ xml: ``,
+ tab: TableAttrs{TAttr{HTable: "hello", FTable: ""}},
+ ns: "http://www.w3schools.com/furniture",
+ },
+ {
+ // Default space does not apply to attribute names.
+ xml: ``,
+ tab: TableAttrs{TAttr{HTable: "", FTable: "world"}},
+ ns: "http://www.w3.org/TR/html4/",
+ },
+ {
+ xml: ``,
+ tab: TableAttrs{},
+ ns: "something else entirely",
+ },
+}
+
+func TestUnmarshalNSAttr(t *testing.T) {
+ for i, tt := range tableAttrs {
+ var dst TableAttrs
+ var err error
+ if tt.ns != "" {
+ d := NewDecoder(strings.NewReader(tt.xml))
+ d.DefaultSpace = tt.ns
+ err = d.Decode(&dst)
+ } else {
+ err = Unmarshal([]byte(tt.xml), &dst)
+ }
+ if err != nil {
+ t.Errorf("#%d: Unmarshal: %v", i, err)
+ continue
+ }
+ want := tt.tab
+ if dst != want {
+ t.Errorf("#%d: dst=%+v, want %+v", i, dst, want)
+ }
+ }
+}
+
+func TestMarshalNSAttr(t *testing.T) {
+ src := TableAttrs{TAttr{"hello", "world", "en_US", "other1", "other2", "other3", "other4"}}
+ data, err := Marshal(&src)
+ if err != nil {
+ t.Fatalf("Marshal: %v", err)
+ }
+ want := ``
+ str := string(data)
+ if str != want {
+ t.Errorf("Marshal:\nhave: %#q\nwant: %#q\n", str, want)
+ }
+
+ var dst TableAttrs
+ if err := Unmarshal(data, &dst); err != nil {
+ t.Errorf("Unmarshal: %v", err)
+ }
+
+ if dst != src {
+ t.Errorf("Unmarshal = %q, want %q", dst, src)
+ }
+}
diff --git a/libgo/go/encoding/xml/typeinfo.go b/libgo/go/encoding/xml/typeinfo.go
index bbeb28d87ea..83e65402c00 100644
--- a/libgo/go/encoding/xml/typeinfo.go
+++ b/libgo/go/encoding/xml/typeinfo.go
@@ -70,20 +70,19 @@ func getTypeInfo(typ reflect.Type) (*typeInfo, error) {
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
- if t.Kind() != reflect.Struct {
- continue
- }
- inner, err := getTypeInfo(t)
- if err != nil {
- return nil, err
- }
- for _, finfo := range inner.fields {
- finfo.idx = append([]int{i}, finfo.idx...)
- if err := addFieldInfo(typ, tinfo, &finfo); err != nil {
+ if t.Kind() == reflect.Struct {
+ inner, err := getTypeInfo(t)
+ if err != nil {
return nil, err
}
+ for _, finfo := range inner.fields {
+ finfo.idx = append([]int{i}, finfo.idx...)
+ if err := addFieldInfo(typ, tinfo, &finfo); err != nil {
+ return nil, err
+ }
+ }
+ continue
}
- continue
}
finfo, err := structFieldInfo(typ, &f)
@@ -193,16 +192,19 @@ func structFieldInfo(typ reflect.Type, f *reflect.StructField) (*fieldInfo, erro
}
// Prepare field name and parents.
- tokens = strings.Split(tag, ">")
- if tokens[0] == "" {
- tokens[0] = f.Name
+ parents := strings.Split(tag, ">")
+ if parents[0] == "" {
+ parents[0] = f.Name
}
- if tokens[len(tokens)-1] == "" {
+ if parents[len(parents)-1] == "" {
return nil, fmt.Errorf("xml: trailing '>' in field %s of type %s", f.Name, typ)
}
- finfo.name = tokens[len(tokens)-1]
- if len(tokens) > 1 {
- finfo.parents = tokens[:len(tokens)-1]
+ finfo.name = parents[len(parents)-1]
+ if len(parents) > 1 {
+ if (finfo.flags & fElement) == 0 {
+ return nil, fmt.Errorf("xml: %s chain not valid with %s flag", tag, strings.Join(tokens[1:], ","))
+ }
+ finfo.parents = parents[:len(parents)-1]
}
// If the field type has an XMLName field, the names must match
@@ -268,6 +270,9 @@ Loop:
if oldf.flags&fMode != newf.flags&fMode {
continue
}
+ if oldf.xmlns != "" && newf.xmlns != "" && oldf.xmlns != newf.xmlns {
+ continue
+ }
minl := min(len(newf.parents), len(oldf.parents))
for p := 0; p < minl; p++ {
if oldf.parents[p] != newf.parents[p] {
diff --git a/libgo/go/encoding/xml/xml.go b/libgo/go/encoding/xml/xml.go
index decb2bec650..021f7e47d91 100644
--- a/libgo/go/encoding/xml/xml.go
+++ b/libgo/go/encoding/xml/xml.go
@@ -169,6 +169,11 @@ type Decoder struct {
// the CharsetReader's result values must be non-nil.
CharsetReader func(charset string, input io.Reader) (io.Reader, error)
+ // DefaultSpace sets the default name space used for unadorned tags,
+ // as if the entire XML stream were wrapped in an element containing
+ // the attribute xmlns="DefaultSpace".
+ DefaultSpace string
+
r io.ByteReader
buf bytes.Buffer
saved *bytes.Buffer
@@ -268,6 +273,8 @@ func (d *Decoder) Token() (t Token, err error) {
return
}
+const xmlURL = "http://www.w3.org/XML/1998/namespace"
+
// Apply name space translation to name n.
// The default name space (for Space=="")
// applies only to element names, not to attribute names.
@@ -277,11 +284,15 @@ func (d *Decoder) translate(n *Name, isElementName bool) {
return
case n.Space == "" && !isElementName:
return
+ case n.Space == "xml":
+ n.Space = xmlURL
case n.Space == "" && n.Local == "xmlns":
return
}
if v, ok := d.ns[n.Space]; ok {
n.Space = v
+ } else if n.Space == "" {
+ n.Space = d.DefaultSpace
}
}
@@ -956,7 +967,7 @@ Input:
b0, b1 = 0, 0
continue Input
}
- ent := string(d.buf.Bytes()[before])
+ ent := string(d.buf.Bytes()[before:])
if ent[len(ent)-1] != ';' {
ent += " (no semicolon)"
}
@@ -1692,7 +1703,7 @@ var HTMLAutoClose = htmlAutoClose
var htmlAutoClose = []string{
/*
hget http://www.w3.org/TR/html4/loose.dtd |
- 9 sed -n 's/", "illegal character code U+FFFE"},
{"\r\n\x07", "illegal character code U+0007"},
{"what's up", "expected attribute name in element"},
+ {"&abc\x01;", "invalid character entity &abc (no semicolon)"},
{"&\x01;", "invalid character entity & (no semicolon)"},
- {"&\xef\xbf\xbe;", "invalid character entity & (no semicolon)"},
+ {"&\xef\xbf\xbe;", "invalid character entity &\uFFFE;"},
+ {"&hello;", "invalid character entity &hello;"},
}
func TestDisallowedCharacters(t *testing.T) {
@@ -629,7 +625,7 @@ func TestDisallowedCharacters(t *testing.T) {
t.Fatalf("input %d d.Token() = _, %v, want _, *SyntaxError", i, err)
}
if synerr.Msg != tt.err {
- t.Fatalf("input %d synerr.Msg wrong: want '%s', got '%s'", i, tt.err, synerr.Msg)
+ t.Fatalf("input %d synerr.Msg wrong: want %q, got %q", i, tt.err, synerr.Msg)
}
}
}
@@ -689,3 +685,32 @@ func TestDirectivesWithComments(t *testing.T) {
}
}
}
+
+// Writer whose Write method always returns an error.
+type errWriter struct{}
+
+func (errWriter) Write(p []byte) (n int, err error) { return 0, fmt.Errorf("unwritable") }
+
+func TestEscapeTextIOErrors(t *testing.T) {
+ expectErr := "unwritable"
+ err := EscapeText(errWriter{}, []byte{'A'})
+
+ if err == nil || err.Error() != expectErr {
+ t.Errorf("have %v, want %v", err, expectErr)
+ }
+}
+
+func TestEscapeTextInvalidChar(t *testing.T) {
+ input := []byte("A \x00 terminated string.")
+ expected := "A \uFFFD terminated string."
+
+ buff := new(bytes.Buffer)
+ if err := EscapeText(buff, input); err != nil {
+ t.Fatalf("have %v, want nil", err)
+ }
+ text := buff.String()
+
+ if text != expected {
+ t.Errorf("have %v, want %v", text, expected)
+ }
+}
diff --git a/libgo/go/exp/cookiejar/jar.go b/libgo/go/exp/cookiejar/jar.go
deleted file mode 100644
index 2159ec532a2..00000000000
--- a/libgo/go/exp/cookiejar/jar.go
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package cookiejar implements an RFC 6265-compliant http.CookieJar.
-//
-// TODO: example code to create a memory-backed cookie jar with the default
-// public suffix list.
-package cookiejar
-
-import (
- "net/http"
- "net/url"
-)
-
-// PublicSuffixList provides the public suffix of a domain. For example:
-// - the public suffix of "example.com" is "com",
-// - the public suffix of "foo1.foo2.foo3.co.uk" is "co.uk", and
-// - the public suffix of "bar.pvt.k12.wy.us" is "pvt.k12.wy.us".
-//
-// Implementations of PublicSuffixList must be safe for concurrent use by
-// multiple goroutines.
-//
-// An implementation that always returns "" is valid and may be useful for
-// testing but it is not secure: it means that the HTTP server for foo.com can
-// set a cookie for bar.com.
-type PublicSuffixList interface {
- // PublicSuffix returns the public suffix of domain.
- //
- // TODO: specify which of the caller and callee is responsible for IP
- // addresses, for leading and trailing dots, for case sensitivity, and
- // for IDN/Punycode.
- PublicSuffix(domain string) string
-
- // String returns a description of the source of this public suffix list.
- // A Jar will store its PublicSuffixList's description in its storage,
- // and update the stored cookies if its list has a different description
- // than the stored list. The description will typically contain something
- // like a time stamp or version number.
- String() string
-}
-
-// Options are the options for creating a new Jar.
-type Options struct {
- // Storage is the cookie jar storage. It may not be nil.
- Storage Storage
-
- // PublicSuffixList is the public suffix list that determines whether an
- // HTTP server can set a cookie for a domain. It may not be nil.
- PublicSuffixList PublicSuffixList
-
- // TODO: ErrorFunc for handling storage errors?
-}
-
-// Jar implements the http.CookieJar interface from the net/http package.
-type Jar struct {
- storage Storage
- psList PublicSuffixList
-}
-
-// New returns a new cookie jar.
-func New(o *Options) *Jar {
- return &Jar{
- storage: o.Storage,
- psList: o.PublicSuffixList,
- }
-}
-
-// TODO(nigeltao): how do we reject HttpOnly cookies? Do we post-process the
-// return value from Jar.Cookies?
-//
-// HttpOnly cookies are those for regular HTTP(S) requests but should not be
-// visible from JavaScript. The HttpOnly bit mitigates XSS attacks; it's not
-// for HTTP vs HTTPS vs FTP transports.
-
-// Cookies implements the Cookies method of the http.CookieJar interface.
-//
-// It returns an empty slice if the URL's scheme is not HTTP or HTTPS.
-func (j *Jar) Cookies(u *url.URL) []*http.Cookie {
- // TODO.
- return nil
-}
-
-// SetCookies implements the SetCookies method of the http.CookieJar interface.
-//
-// It does nothing if the URL's scheme is not HTTP or HTTPS.
-func (j *Jar) SetCookies(u *url.URL, cookies []*http.Cookie) {
- // TODO.
-}
diff --git a/libgo/go/exp/cookiejar/storage.go b/libgo/go/exp/cookiejar/storage.go
deleted file mode 100644
index 5294f587e4c..00000000000
--- a/libgo/go/exp/cookiejar/storage.go
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package cookiejar
-
-import (
- "time"
-)
-
-// Storage is a Jar's storage. It is a multi-map, mapping keys to one or more
-// entries. Each entry consists of a subkey, creation time, last access time,
-// and some arbitrary data.
-//
-// The Add and Delete methods have undefined behavior if the key is invalid.
-// A valid key must use only bytes in the character class [a-z0-9.-] and
-// must have at least one non-. byte. Note that this excludes any key
-// containing a capital ASCII letter as well as the empty string.
-type Storage interface {
- // A client must call Lock before calling other methods and must call
- // Unlock when finished. Between the calls to Lock and Unlock, a client
- // can assume that other clients are not modifying the Storage.
- Lock()
- Unlock()
-
- // Add adds entries to the storage. Each entry's Subkey and Data must
- // both be non-empty.
- //
- // If the Storage already contains an entry with the same key and
- // subkey then the new entry is stored with the creation time of the
- // old entry, and the old entry is deleted.
- //
- // Adding entries may cause other entries to be deleted, to maintain an
- // implementation-specific storage constraint.
- Add(key string, entries ...Entry) error
-
- // Delete deletes all entries for the given key.
- Delete(key string) error
-
- // Entries calls f for each entry stored for that key. If f returns a
- // non-nil error then the iteration stops and Entries returns that
- // error. Iteration is not guaranteed to be in any particular order.
- //
- // If f returns an Update action then that stored entry's LastAccess
- // time will be set to the time that f returned. If f returns a Delete
- // action then that entry will be deleted from the Storage.
- //
- // f may call a Storage's Add and Delete methods; those modifications
- // will not affect the list of entries visited in this call to Entries.
- Entries(key string, f func(entry Entry) (Action, time.Time, error)) error
-
- // Keys calls f for each key stored. f will not be called on a key with
- // zero entries. If f returns a non-nil error then the iteration stops
- // and Keys returns that error. Iteration is not guaranteed to be in any
- // particular order.
- //
- // f may call a Storage's Add, Delete and Entries methods; those
- // modifications will not affect the list of keys visited in this call
- // to Keys.
- Keys(f func(key string) error) error
-}
-
-// Entry is an entry in a Storage.
-type Entry struct {
- Subkey string
- Data string
- Creation time.Time
- LastAccess time.Time
-}
-
-// Action is an action returned by the function passed to Entries.
-type Action int
-
-const (
- // Pass means to take no further action with an Entry.
- Pass Action = iota
- // Update means to update the LastAccess time of an Entry.
- Update
- // Delete means to delete an Entry.
- Delete
-)
-
-// ValidStorageKey returns whether the given key is valid for a Storage.
-func ValidStorageKey(key string) bool {
- hasNonDot := false
- for i := 0; i < len(key); i++ {
- switch c := key[i]; {
- case 'a' <= c && c <= 'z':
- fallthrough
- case '0' <= c && c <= '9':
- fallthrough
- case c == '-':
- hasNonDot = true
- case c == '.':
- // No-op.
- default:
- return false
- }
- }
- return hasNonDot
-}
diff --git a/libgo/go/exp/cookiejar/storage_test.go b/libgo/go/exp/cookiejar/storage_test.go
deleted file mode 100644
index de6aa2b6a7f..00000000000
--- a/libgo/go/exp/cookiejar/storage_test.go
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package cookiejar
-
-import (
- "testing"
-)
-
-var validStorageKeyTests = map[string]bool{
- "": false,
- ".": false,
- "..": false,
- "/": false,
- "EXAMPLE.com": false,
- "\n": false,
- "\r": false,
- "\r\n": false,
- "\x00": false,
- "back\\slash": false,
- "co:lon": false,
- "com,ma": false,
- "semi;colon": false,
- "sl/ash": false,
- "sp ace": false,
- "under_score": false,
- "π": false,
-
- "-": true,
- ".dot": true,
- ".dot.": true,
- ".metadata": true,
- ".x..y..z...": true,
- "dot.": true,
- "example.com": true,
- "foo": true,
- "hy-phen": true,
- "xn--bcher-kva.ch": true,
-}
-
-func TestValidStorageKey(t *testing.T) {
- for key, want := range validStorageKeyTests {
- if got := ValidStorageKey(key); got != want {
- t.Errorf("%q: got %v, want %v", key, got, want)
- }
- }
-}
diff --git a/libgo/go/exp/ebnf/ebnf.go b/libgo/go/exp/ebnf/ebnf.go
deleted file mode 100644
index cd8c83c9210..00000000000
--- a/libgo/go/exp/ebnf/ebnf.go
+++ /dev/null
@@ -1,269 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package ebnf is a library for EBNF grammars. The input is text ([]byte)
-// satisfying the following grammar (represented itself in EBNF):
-//
-// Production = name "=" [ Expression ] "." .
-// Expression = Alternative { "|" Alternative } .
-// Alternative = Term { Term } .
-// Term = name | token [ "…" token ] | Group | Option | Repetition .
-// Group = "(" Expression ")" .
-// Option = "[" Expression "]" .
-// Repetition = "{" Expression "}" .
-//
-// A name is a Go identifier, a token is a Go string, and comments
-// and white space follow the same rules as for the Go language.
-// Production names starting with an uppercase Unicode letter denote
-// non-terminal productions (i.e., productions which allow white-space
-// and comments between tokens); all other production names denote
-// lexical productions.
-//
-package ebnf
-
-import (
- "errors"
- "fmt"
- "text/scanner"
- "unicode"
- "unicode/utf8"
-)
-
-// ----------------------------------------------------------------------------
-// Error handling
-
-type errorList []error
-
-func (list errorList) Err() error {
- if len(list) == 0 {
- return nil
- }
- return list
-}
-
-func (list errorList) Error() string {
- switch len(list) {
- case 0:
- return "no errors"
- case 1:
- return list[0].Error()
- }
- return fmt.Sprintf("%s (and %d more errors)", list[0], len(list)-1)
-}
-
-func newError(pos scanner.Position, msg string) error {
- return errors.New(fmt.Sprintf("%s: %s", pos, msg))
-}
-
-// ----------------------------------------------------------------------------
-// Internal representation
-
-type (
- // An Expression node represents a production expression.
- Expression interface {
- // Pos is the position of the first character of the syntactic construct
- Pos() scanner.Position
- }
-
- // An Alternative node represents a non-empty list of alternative expressions.
- Alternative []Expression // x | y | z
-
- // A Sequence node represents a non-empty list of sequential expressions.
- Sequence []Expression // x y z
-
- // A Name node represents a production name.
- Name struct {
- StringPos scanner.Position
- String string
- }
-
- // A Token node represents a literal.
- Token struct {
- StringPos scanner.Position
- String string
- }
-
- // A List node represents a range of characters.
- Range struct {
- Begin, End *Token // begin ... end
- }
-
- // A Group node represents a grouped expression.
- Group struct {
- Lparen scanner.Position
- Body Expression // (body)
- }
-
- // An Option node represents an optional expression.
- Option struct {
- Lbrack scanner.Position
- Body Expression // [body]
- }
-
- // A Repetition node represents a repeated expression.
- Repetition struct {
- Lbrace scanner.Position
- Body Expression // {body}
- }
-
- // A Production node represents an EBNF production.
- Production struct {
- Name *Name
- Expr Expression
- }
-
- // A Bad node stands for pieces of source code that lead to a parse error.
- Bad struct {
- TokPos scanner.Position
- Error string // parser error message
- }
-
- // A Grammar is a set of EBNF productions. The map
- // is indexed by production name.
- //
- Grammar map[string]*Production
-)
-
-func (x Alternative) Pos() scanner.Position { return x[0].Pos() } // the parser always generates non-empty Alternative
-func (x Sequence) Pos() scanner.Position { return x[0].Pos() } // the parser always generates non-empty Sequences
-func (x *Name) Pos() scanner.Position { return x.StringPos }
-func (x *Token) Pos() scanner.Position { return x.StringPos }
-func (x *Range) Pos() scanner.Position { return x.Begin.Pos() }
-func (x *Group) Pos() scanner.Position { return x.Lparen }
-func (x *Option) Pos() scanner.Position { return x.Lbrack }
-func (x *Repetition) Pos() scanner.Position { return x.Lbrace }
-func (x *Production) Pos() scanner.Position { return x.Name.Pos() }
-func (x *Bad) Pos() scanner.Position { return x.TokPos }
-
-// ----------------------------------------------------------------------------
-// Grammar verification
-
-func isLexical(name string) bool {
- ch, _ := utf8.DecodeRuneInString(name)
- return !unicode.IsUpper(ch)
-}
-
-type verifier struct {
- errors errorList
- worklist []*Production
- reached Grammar // set of productions reached from (and including) the root production
- grammar Grammar
-}
-
-func (v *verifier) error(pos scanner.Position, msg string) {
- v.errors = append(v.errors, newError(pos, msg))
-}
-
-func (v *verifier) push(prod *Production) {
- name := prod.Name.String
- if _, found := v.reached[name]; !found {
- v.worklist = append(v.worklist, prod)
- v.reached[name] = prod
- }
-}
-
-func (v *verifier) verifyChar(x *Token) rune {
- s := x.String
- if utf8.RuneCountInString(s) != 1 {
- v.error(x.Pos(), "single char expected, found "+s)
- return 0
- }
- ch, _ := utf8.DecodeRuneInString(s)
- return ch
-}
-
-func (v *verifier) verifyExpr(expr Expression, lexical bool) {
- switch x := expr.(type) {
- case nil:
- // empty expression
- case Alternative:
- for _, e := range x {
- v.verifyExpr(e, lexical)
- }
- case Sequence:
- for _, e := range x {
- v.verifyExpr(e, lexical)
- }
- case *Name:
- // a production with this name must exist;
- // add it to the worklist if not yet processed
- if prod, found := v.grammar[x.String]; found {
- v.push(prod)
- } else {
- v.error(x.Pos(), "missing production "+x.String)
- }
- // within a lexical production references
- // to non-lexical productions are invalid
- if lexical && !isLexical(x.String) {
- v.error(x.Pos(), "reference to non-lexical production "+x.String)
- }
- case *Token:
- // nothing to do for now
- case *Range:
- i := v.verifyChar(x.Begin)
- j := v.verifyChar(x.End)
- if i >= j {
- v.error(x.Pos(), "decreasing character range")
- }
- case *Group:
- v.verifyExpr(x.Body, lexical)
- case *Option:
- v.verifyExpr(x.Body, lexical)
- case *Repetition:
- v.verifyExpr(x.Body, lexical)
- case *Bad:
- v.error(x.Pos(), x.Error)
- default:
- panic(fmt.Sprintf("internal error: unexpected type %T", expr))
- }
-}
-
-func (v *verifier) verify(grammar Grammar, start string) {
- // find root production
- root, found := grammar[start]
- if !found {
- var noPos scanner.Position
- v.error(noPos, "no start production "+start)
- return
- }
-
- // initialize verifier
- v.worklist = v.worklist[0:0]
- v.reached = make(Grammar)
- v.grammar = grammar
-
- // work through the worklist
- v.push(root)
- for {
- n := len(v.worklist) - 1
- if n < 0 {
- break
- }
- prod := v.worklist[n]
- v.worklist = v.worklist[0:n]
- v.verifyExpr(prod.Expr, isLexical(prod.Name.String))
- }
-
- // check if all productions were reached
- if len(v.reached) < len(v.grammar) {
- for name, prod := range v.grammar {
- if _, found := v.reached[name]; !found {
- v.error(prod.Pos(), name+" is unreachable")
- }
- }
- }
-}
-
-// Verify checks that:
-// - all productions used are defined
-// - all productions defined are used when beginning at start
-// - lexical productions refer only to other lexical productions
-//
-// Position information is interpreted relative to the file set fset.
-//
-func Verify(grammar Grammar, start string) error {
- var v verifier
- v.verify(grammar, start)
- return v.errors.Err()
-}
diff --git a/libgo/go/exp/ebnf/ebnf_test.go b/libgo/go/exp/ebnf/ebnf_test.go
deleted file mode 100644
index 8cfd6b9c370..00000000000
--- a/libgo/go/exp/ebnf/ebnf_test.go
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package ebnf
-
-import (
- "bytes"
- "testing"
-)
-
-var goodGrammars = []string{
- `Program = .`,
-
- `Program = foo .
- foo = "foo" .`,
-
- `Program = "a" | "b" "c" .`,
-
- `Program = "a" … "z" .`,
-
- `Program = Song .
- Song = { Note } .
- Note = Do | (Re | Mi | Fa | So | La) | Ti .
- Do = "c" .
- Re = "d" .
- Mi = "e" .
- Fa = "f" .
- So = "g" .
- La = "a" .
- Ti = ti .
- ti = "b" .`,
-}
-
-var badGrammars = []string{
- `Program = | .`,
- `Program = | b .`,
- `Program = a … b .`,
- `Program = "a" … .`,
- `Program = … "b" .`,
- `Program = () .`,
- `Program = [] .`,
- `Program = {} .`,
-}
-
-func checkGood(t *testing.T, src string) {
- grammar, err := Parse("", bytes.NewBuffer([]byte(src)))
- if err != nil {
- t.Errorf("Parse(%s) failed: %v", src, err)
- return
- }
- if err = Verify(grammar, "Program"); err != nil {
- t.Errorf("Verify(%s) failed: %v", src, err)
- }
-}
-
-func checkBad(t *testing.T, src string) {
- _, err := Parse("", bytes.NewBuffer([]byte(src)))
- if err == nil {
- t.Errorf("Parse(%s) should have failed", src)
- }
-}
-
-func TestGrammars(t *testing.T) {
- for _, src := range goodGrammars {
- checkGood(t, src)
- }
- for _, src := range badGrammars {
- checkBad(t, src)
- }
-}
diff --git a/libgo/go/exp/ebnf/parser.go b/libgo/go/exp/ebnf/parser.go
deleted file mode 100644
index 7a7e3cc16e4..00000000000
--- a/libgo/go/exp/ebnf/parser.go
+++ /dev/null
@@ -1,190 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package ebnf
-
-import (
- "io"
- "strconv"
- "text/scanner"
-)
-
-type parser struct {
- errors errorList
- scanner scanner.Scanner
- pos scanner.Position // token position
- tok rune // one token look-ahead
- lit string // token literal
-}
-
-func (p *parser) next() {
- p.tok = p.scanner.Scan()
- p.pos = p.scanner.Position
- p.lit = p.scanner.TokenText()
-}
-
-func (p *parser) error(pos scanner.Position, msg string) {
- p.errors = append(p.errors, newError(pos, msg))
-}
-
-func (p *parser) errorExpected(pos scanner.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 " + scanner.TokenString(p.tok)
- if p.tok < 0 {
- msg += " " + p.lit
- }
- }
- p.error(pos, msg)
-}
-
-func (p *parser) expect(tok rune) scanner.Position {
- pos := p.pos
- if p.tok != tok {
- p.errorExpected(pos, scanner.TokenString(tok))
- }
- p.next() // make progress in any case
- return pos
-}
-
-func (p *parser) parseIdentifier() *Name {
- pos := p.pos
- name := p.lit
- p.expect(scanner.Ident)
- return &Name{pos, name}
-}
-
-func (p *parser) parseToken() *Token {
- pos := p.pos
- value := ""
- if p.tok == scanner.String {
- value, _ = strconv.Unquote(p.lit)
- // Unquote may fail with an error, but only if the scanner found
- // an illegal string in the first place. In this case the error
- // has already been reported.
- p.next()
- } else {
- p.expect(scanner.String)
- }
- return &Token{pos, value}
-}
-
-// ParseTerm returns nil if no term was found.
-func (p *parser) parseTerm() (x Expression) {
- pos := p.pos
-
- switch p.tok {
- case scanner.Ident:
- x = p.parseIdentifier()
-
- case scanner.String:
- tok := p.parseToken()
- x = tok
- const ellipsis = '…' // U+2026, the horizontal ellipsis character
- if p.tok == ellipsis {
- p.next()
- x = &Range{tok, p.parseToken()}
- }
-
- case '(':
- p.next()
- x = &Group{pos, p.parseExpression()}
- p.expect(')')
-
- case '[':
- p.next()
- x = &Option{pos, p.parseExpression()}
- p.expect(']')
-
- case '{':
- p.next()
- x = &Repetition{pos, p.parseExpression()}
- p.expect('}')
- }
-
- return x
-}
-
-func (p *parser) parseSequence() Expression {
- var list Sequence
-
- for x := p.parseTerm(); x != nil; x = p.parseTerm() {
- list = append(list, x)
- }
-
- // no need for a sequence if list.Len() < 2
- switch len(list) {
- case 0:
- p.errorExpected(p.pos, "term")
- return &Bad{p.pos, "term expected"}
- case 1:
- return list[0]
- }
-
- return list
-}
-
-func (p *parser) parseExpression() Expression {
- var list Alternative
-
- for {
- list = append(list, p.parseSequence())
- if p.tok != '|' {
- break
- }
- p.next()
- }
- // len(list) > 0
-
- // no need for an Alternative node if list.Len() < 2
- if len(list) == 1 {
- return list[0]
- }
-
- return list
-}
-
-func (p *parser) parseProduction() *Production {
- name := p.parseIdentifier()
- p.expect('=')
- var expr Expression
- if p.tok != '.' {
- expr = p.parseExpression()
- }
- p.expect('.')
- return &Production{name, expr}
-}
-
-func (p *parser) parse(filename string, src io.Reader) Grammar {
- p.scanner.Init(src)
- p.scanner.Filename = filename
- p.next() // initializes pos, tok, lit
-
- grammar := make(Grammar)
- for p.tok != scanner.EOF {
- prod := p.parseProduction()
- name := prod.Name.String
- if _, found := grammar[name]; !found {
- grammar[name] = prod
- } else {
- p.error(prod.Pos(), name+" declared already")
- }
- }
-
- return grammar
-}
-
-// Parse parses a set of EBNF productions from source src.
-// It returns a set of productions. Errors are reported
-// for incorrect syntax and if a production is declared
-// more than once; the filename is used only for error
-// positions.
-//
-func Parse(filename string, src io.Reader) (Grammar, error) {
- var p parser
- grammar := p.parse(filename, src)
- return grammar, p.errors.Err()
-}
diff --git a/libgo/go/exp/ebnflint/doc.go b/libgo/go/exp/ebnflint/doc.go
deleted file mode 100644
index 4bb22a4cb80..00000000000
--- a/libgo/go/exp/ebnflint/doc.go
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
-
-Ebnflint verifies that EBNF productions are consistent and grammatically correct.
-It reads them from an HTML document such as the Go specification.
-
-Grammar productions are grouped in boxes demarcated by the HTML elements
-
-
-
-
-Usage:
- go tool ebnflint [--start production] [file]
-
-The --start flag specifies the name of the start production for
-the grammar; it defaults to "Start".
-
-*/
-package documentation
diff --git a/libgo/go/exp/ebnflint/ebnflint.go b/libgo/go/exp/ebnflint/ebnflint.go
deleted file mode 100644
index d54fb229d03..00000000000
--- a/libgo/go/exp/ebnflint/ebnflint.go
+++ /dev/null
@@ -1,122 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import (
- "bytes"
- "exp/ebnf"
- "flag"
- "fmt"
- "go/scanner"
- "go/token"
- "io"
- "io/ioutil"
- "os"
- "path/filepath"
-)
-
-var fset = token.NewFileSet()
-var start = flag.String("start", "Start", "name of start production")
-
-func usage() {
- fmt.Fprintf(os.Stderr, "usage: go tool ebnflint [flags] [filename]\n")
- flag.PrintDefaults()
- os.Exit(1)
-}
-
-// Markers around EBNF sections in .html files
-var (
- open = []byte(``)
- close = []byte(`
`)
-)
-
-func report(err error) {
- scanner.PrintError(os.Stderr, err)
- os.Exit(1)
-}
-
-func extractEBNF(src []byte) []byte {
- var buf bytes.Buffer
-
- for {
- // i = beginning of EBNF text
- i := bytes.Index(src, open)
- if i < 0 {
- break // no EBNF found - we are done
- }
- i += len(open)
-
- // write as many newlines as found in the excluded text
- // to maintain correct line numbers in error messages
- for _, ch := range src[0:i] {
- if ch == '\n' {
- buf.WriteByte('\n')
- }
- }
-
- // j = end of EBNF text (or end of source)
- j := bytes.Index(src[i:], close) // close marker
- if j < 0 {
- j = len(src) - i
- }
- j += i
-
- // copy EBNF text
- buf.Write(src[i:j])
-
- // advance
- src = src[j:]
- }
-
- return buf.Bytes()
-}
-
-func main() {
- flag.Parse()
-
- var (
- name string
- r io.Reader
- )
- switch flag.NArg() {
- case 0:
- name, r = "", os.Stdin
- case 1:
- name = flag.Arg(0)
- default:
- usage()
- }
-
- if err := verify(name, *start, r); err != nil {
- report(err)
- }
-}
-
-func verify(name, start string, r io.Reader) error {
- if r == nil {
- f, err := os.Open(name)
- if err != nil {
- return err
- }
- defer f.Close()
- r = f
- }
-
- src, err := ioutil.ReadAll(r)
- if err != nil {
- return err
- }
-
- if filepath.Ext(name) == ".html" || bytes.Index(src, open) >= 0 {
- src = extractEBNF(src)
- }
-
- grammar, err := ebnf.Parse(name, bytes.NewBuffer(src))
- if err != nil {
- return err
- }
-
- return ebnf.Verify(grammar, start)
-}
diff --git a/libgo/go/exp/ebnflint/ebnflint_test.go b/libgo/go/exp/ebnflint/ebnflint_test.go
deleted file mode 100644
index 875dbc19aca..00000000000
--- a/libgo/go/exp/ebnflint/ebnflint_test.go
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import (
- "runtime"
- "testing"
-)
-
-func TestSpec(t *testing.T) {
- if err := verify(runtime.GOROOT()+"/doc/go_spec.html", "SourceFile", nil); err != nil {
- t.Fatal(err)
- }
-}
diff --git a/libgo/go/exp/gotype/doc.go b/libgo/go/exp/gotype/doc.go
deleted file mode 100644
index 1168086771f..00000000000
--- a/libgo/go/exp/gotype/doc.go
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
-The gotype command does syntactic and semantic analysis of Go files
-and packages similar to the analysis performed by the front-end of
-a Go compiler. Errors are reported if the analysis fails; otherwise
-gotype is quiet (unless -v is set).
-
-Without a list of paths, gotype processes the standard input, which must
-be the source of a single package file.
-
-Given a list of file names, each file must be a source file belonging to
-the same package unless the package name is explicitly specified with the
--p flag.
-
-Given a directory name, gotype collects all .go files in the directory
-and processes them as if they were provided as an explicit list of file
-names. Each directory is processed independently. Files starting with .
-or not ending in .go are ignored.
-
-Usage:
- gotype [flags] [path ...]
-
-The flags are:
- -e
- Print all (including spurious) errors.
- -p pkgName
- Process only those files in package pkgName.
- -r
- Recursively process subdirectories.
- -v
- Verbose mode.
-
-Debugging flags:
- -comments
- Parse comments (ignored if -ast not set).
- -ast
- Print AST (disables concurrent parsing).
- -trace
- Print parse trace (disables concurrent parsing).
-
-
-Examples
-
-To check the files file.go, old.saved, and .ignored:
-
- gotype file.go old.saved .ignored
-
-To check all .go files belonging to package main in the current directory
-and recursively in all subdirectories:
-
- gotype -p main -r .
-
-To verify the output of a pipe:
-
- echo "package foo" | gotype
-
-*/
-package documentation
-
-// BUG(gri): At the moment, only single-file scope analysis is performed.
diff --git a/libgo/go/exp/gotype/gotype.go b/libgo/go/exp/gotype/gotype.go
deleted file mode 100644
index bb3237c37cb..00000000000
--- a/libgo/go/exp/gotype/gotype.go
+++ /dev/null
@@ -1,184 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import (
- "flag"
- "fmt"
- "go/ast"
- "go/parser"
- "go/scanner"
- "go/token"
- "go/types"
- "io/ioutil"
- "os"
- "path/filepath"
- "strings"
-)
-
-var (
- // main operation modes
- pkgName = flag.String("p", "", "process only those files in package pkgName")
- recursive = flag.Bool("r", false, "recursively process subdirectories")
- verbose = flag.Bool("v", false, "verbose mode")
- allErrors = flag.Bool("e", false, "print all (including spurious) errors")
-
- // debugging support
- parseComments = flag.Bool("comments", false, "parse comments (ignored if -ast not set)")
- printTrace = flag.Bool("trace", false, "print parse trace")
- printAST = flag.Bool("ast", false, "print AST")
-)
-
-var exitCode = 0
-
-func usage() {
- fmt.Fprintf(os.Stderr, "usage: gotype [flags] [path ...]\n")
- flag.PrintDefaults()
- os.Exit(2)
-}
-
-func report(err error) {
- scanner.PrintError(os.Stderr, err)
- exitCode = 2
-}
-
-// parse returns the AST for the Go source src.
-// The filename is for error reporting only.
-// The result is nil if there were errors or if
-// the file does not belong to the -p package.
-func parse(fset *token.FileSet, filename string, src []byte) *ast.File {
- if *verbose {
- fmt.Println(filename)
- }
-
- // ignore files with different package name
- if *pkgName != "" {
- file, err := parser.ParseFile(fset, filename, src, parser.PackageClauseOnly)
- if err != nil {
- report(err)
- return nil
- }
- if file.Name.Name != *pkgName {
- if *verbose {
- fmt.Printf("\tignored (package %s)\n", file.Name.Name)
- }
- return nil
- }
- }
-
- // parse entire file
- mode := parser.DeclarationErrors
- if *allErrors {
- mode |= parser.SpuriousErrors
- }
- if *parseComments && *printAST {
- mode |= parser.ParseComments
- }
- if *printTrace {
- mode |= parser.Trace
- }
- file, err := parser.ParseFile(fset, filename, src, mode)
- if err != nil {
- report(err)
- return nil
- }
- if *printAST {
- ast.Print(fset, file)
- }
-
- return file
-}
-
-func parseStdin(fset *token.FileSet) (files []*ast.File) {
- src, err := ioutil.ReadAll(os.Stdin)
- if err != nil {
- report(err)
- return
- }
- const filename = ""
- if file := parse(fset, filename, src); file != nil {
- files = []*ast.File{file}
- }
- return
-}
-
-func parseFiles(fset *token.FileSet, filenames []string) (files []*ast.File) {
- for _, filename := range filenames {
- src, err := ioutil.ReadFile(filename)
- if err != nil {
- report(err)
- continue
- }
- if file := parse(fset, filename, src); file != nil {
- files = append(files, file)
- }
- }
- return
-}
-
-func isGoFilename(filename string) bool {
- // ignore non-Go files
- return !strings.HasPrefix(filename, ".") && strings.HasSuffix(filename, ".go")
-}
-
-func processDirectory(dirname string) {
- f, err := os.Open(dirname)
- if err != nil {
- report(err)
- return
- }
- filenames, err := f.Readdirnames(-1)
- f.Close()
- if err != nil {
- report(err)
- // continue since filenames may not be empty
- }
- for i, filename := range filenames {
- filenames[i] = filepath.Join(dirname, filename)
- }
- processFiles(filenames, false)
-}
-
-func processFiles(filenames []string, allFiles bool) {
- i := 0
- for _, filename := range filenames {
- switch info, err := os.Stat(filename); {
- case err != nil:
- report(err)
- case info.IsDir():
- if allFiles || *recursive {
- processDirectory(filename)
- }
- default:
- if allFiles || isGoFilename(info.Name()) {
- filenames[i] = filename
- i++
- }
- }
- }
- fset := token.NewFileSet()
- processPackage(fset, parseFiles(fset, filenames[0:i]))
-}
-
-func processPackage(fset *token.FileSet, files []*ast.File) {
- _, err := types.Check(fset, files)
- if err != nil {
- report(err)
- }
-}
-
-func main() {
- flag.Usage = usage
- flag.Parse()
-
- if flag.NArg() == 0 {
- fset := token.NewFileSet()
- processPackage(fset, parseStdin(fset))
- } else {
- processFiles(flag.Args(), true)
- }
-
- os.Exit(exitCode)
-}
diff --git a/libgo/go/exp/gotype/gotype_test.go b/libgo/go/exp/gotype/gotype_test.go
deleted file mode 100644
index 67ab7cfa74a..00000000000
--- a/libgo/go/exp/gotype/gotype_test.go
+++ /dev/null
@@ -1,215 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import (
- "go/build"
- "path/filepath"
- "runtime"
- "strings"
- "testing"
-)
-
-func runTest(t *testing.T, path string) {
- exitCode = 0
-
- *recursive = false
- if suffix := ".go"; strings.HasSuffix(path, suffix) {
- // single file
- path = filepath.Join(runtime.GOROOT(), "src/pkg", path)
- path, file := filepath.Split(path)
- *pkgName = file[:len(file)-len(suffix)]
- processFiles([]string{path}, true)
- } else {
- // package directory
- // TODO(gri) gotype should use the build package instead
- ctxt := build.Default
- ctxt.CgoEnabled = false
- pkg, err := ctxt.Import(path, "", 0)
- if err != nil {
- t.Errorf("build.Import error for path = %s: %s", path, err)
- return
- }
- // TODO(gri) there ought to be a more direct way using the build package...
- files := make([]string, len(pkg.GoFiles))
- for i, file := range pkg.GoFiles {
- files[i] = filepath.Join(pkg.Dir, file)
- }
- *pkgName = pkg.Name
- processFiles(files, true)
- }
-
- if exitCode != 0 {
- t.Errorf("processing %s failed: exitCode = %d", path, exitCode)
- }
-}
-
-var tests = []string{
- // individual files
- "exp/gotype/testdata/test1.go",
-
- // directories
- // Note: Packages that don't typecheck yet are commented out.
- // Unless there is a comment next to the commented out packages,
- // the package doesn't typecheck due to errors in the shift
- // expression checker.
- "archive/tar",
- "archive/zip",
-
- "bufio",
- "bytes",
-
- // "compress/bzip2",
- "compress/flate",
- "compress/gzip",
- // "compress/lzw",
- "compress/zlib",
-
- "container/heap",
- "container/list",
- "container/ring",
-
- "crypto",
- "crypto/aes",
- "crypto/cipher",
- "crypto/des",
- "crypto/dsa",
- "crypto/ecdsa",
- "crypto/elliptic",
- "crypto/hmac",
- "crypto/md5",
- // "crypto/rand",
- "crypto/rc4",
- // "crypto/rsa", // intermittent failure: /home/gri/go2/src/pkg/crypto/rsa/pkcs1v15.go:21:27: undeclared name: io
- "crypto/sha1",
- "crypto/sha256",
- "crypto/sha512",
- "crypto/subtle",
- "crypto/tls",
- "crypto/x509",
- "crypto/x509/pkix",
-
- "database/sql",
- "database/sql/driver",
-
- // "debug/dwarf",
- "debug/elf",
- "debug/gosym",
- "debug/macho",
- "debug/pe",
-
- "encoding/ascii85",
- // "encoding/asn1",
- "encoding/base32",
- "encoding/base64",
- "encoding/binary",
- "encoding/csv",
- "encoding/gob",
- "encoding/hex",
- "encoding/json",
- "encoding/pem",
- "encoding/xml",
-
- "errors",
- "expvar",
- "flag",
- "fmt",
-
- "exp/gotype",
-
- "go/ast",
- "go/build",
- "go/doc",
- "go/format",
- "go/parser",
- "go/printer",
- "go/scanner",
- // "go/token",
- "go/types",
-
- "hash/adler32",
- "hash/crc32",
- "hash/crc64",
- "hash/fnv",
-
- "image",
- "image/color",
- "image/draw",
- "image/gif",
- // "image/jpeg",
- "image/png",
-
- "index/suffixarray",
-
- "io",
- "io/ioutil",
-
- "log",
- "log/syslog",
-
- // "math",
- //"math/big",
- "math/cmplx",
- "math/rand",
-
- "mime",
- "mime/multipart",
-
- // "net",
- "net/http",
- "net/http/cgi",
- "net/http/fcgi",
- "net/http/httptest",
- "net/http/httputil",
- "net/http/pprof",
- "net/mail",
- "net/rpc",
- "net/rpc/jsonrpc",
- "net/smtp",
- // "net/textproto",
- "net/url",
-
- "path",
- "path/filepath",
-
- "reflect",
-
- "regexp",
- "regexp/syntax",
-
- // "runtime",
- "runtime/cgo",
- "runtime/debug",
- "runtime/pprof",
-
- "sort",
- // "strconv",
- "strings",
-
- "sync",
- "sync/atomic",
-
- // "syscall",
-
- "testing",
- "testing/iotest",
- "testing/quick",
-
- // "text/scanner",
- "text/tabwriter",
- "text/template",
- "text/template/parse",
-
- "time",
- "unicode",
- "unicode/utf16",
- "unicode/utf8",
-}
-
-func Test(t *testing.T) {
- for _, test := range tests {
- runTest(t, test)
- }
-}
diff --git a/libgo/go/exp/gotype/testdata/test1.go b/libgo/go/exp/gotype/testdata/test1.go
deleted file mode 100644
index 6a6f477e780..00000000000
--- a/libgo/go/exp/gotype/testdata/test1.go
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package test1
-
-func _() {
- // the scope of a local type declaration starts immediately after the type name
- type T struct{ _ *T }
-}
-
-func _(x interface{}) {
- // the variable defined by a TypeSwitchGuard is declared in each TypeCaseClause
- switch t := x.(type) {
- case int:
- _ = t
- case float32:
- _ = t
- default:
- _ = t
- }
-
- // the variable defined by a TypeSwitchGuard must not conflict with other
- // variables declared in the initial simple statement
- switch t := 0; t := x.(type) {
- }
-}
diff --git a/libgo/go/exp/html/atom/atom.go b/libgo/go/exp/html/atom/atom.go
deleted file mode 100644
index 2dbd0fbf7f5..00000000000
--- a/libgo/go/exp/html/atom/atom.go
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package atom provides integer codes (also known as atoms) for a fixed set of
-// frequently occurring HTML strings: tag names and attribute keys such as "p"
-// and "id".
-//
-// Sharing an atom's name between all elements with the same tag can result in
-// fewer string allocations when tokenizing and parsing HTML. Integer
-// comparisons are also generally faster than string comparisons.
-//
-// The value of an atom's particular code is not guaranteed to stay the same
-// between versions of this package. Neither is any ordering guaranteed:
-// whether atom.H1 < atom.H2 may also change. The codes are not guaranteed to
-// be dense. The only guarantees are that e.g. looking up "div" will yield
-// atom.Div, calling atom.Div.String will return "div", and atom.Div != 0.
-//
-// TODO(rsc): When this package moves out of exp we need to freeze atom values
-// across releases.
-package atom
-
-// Atom is an integer code for a string. The zero value maps to "".
-type Atom uint32
-
-// String returns the atom's name.
-func (a Atom) String() string {
- start := uint32(a >> 8)
- n := uint32(a & 0xff)
- if start+n > uint32(len(atomText)) {
- return ""
- }
- return atomText[start : start+n]
-}
-
-func (a Atom) string() string {
- return atomText[a>>8 : a>>8+a&0xff]
-}
-
-// fnv computes the FNV hash with an arbitrary starting value h.
-func fnv(h uint32, s []byte) uint32 {
- for i := range s {
- h ^= uint32(s[i])
- h *= 16777619
- }
- return h
-}
-
-func match(s string, t []byte) bool {
- for i, c := range t {
- if s[i] != c {
- return false
- }
- }
- return true
-}
-
-// Lookup returns the atom whose name is s. It returns zero if there is no
-// such atom. The lookup is case sensitive.
-func Lookup(s []byte) Atom {
- if len(s) == 0 || len(s) > maxAtomLen {
- return 0
- }
- h := fnv(hash0, s)
- if a := table[h&uint32(len(table)-1)]; int(a&0xff) == len(s) && match(a.string(), s) {
- return a
- }
- if a := table[(h>>16)&uint32(len(table)-1)]; int(a&0xff) == len(s) && match(a.string(), s) {
- return a
- }
- return 0
-}
-
-// String returns a string whose contents are equal to s. In that sense, it is
-// equivalent to string(s) but may be more efficient.
-func String(s []byte) string {
- if a := Lookup(s); a != 0 {
- return a.String()
- }
- return string(s)
-}
diff --git a/libgo/go/exp/html/atom/atom_test.go b/libgo/go/exp/html/atom/atom_test.go
deleted file mode 100644
index 6e33704dd5e..00000000000
--- a/libgo/go/exp/html/atom/atom_test.go
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package atom
-
-import (
- "sort"
- "testing"
-)
-
-func TestKnown(t *testing.T) {
- for _, s := range testAtomList {
- if atom := Lookup([]byte(s)); atom.String() != s {
- t.Errorf("Lookup(%q) = %#x (%q)", s, uint32(atom), atom.String())
- }
- }
-}
-
-func TestHits(t *testing.T) {
- for _, a := range table {
- if a == 0 {
- continue
- }
- got := Lookup([]byte(a.String()))
- if got != a {
- t.Errorf("Lookup(%q) = %#x, want %#x", a.String(), uint32(got), uint32(a))
- }
- }
-}
-
-func TestMisses(t *testing.T) {
- testCases := []string{
- "",
- "\x00",
- "\xff",
- "A",
- "DIV",
- "Div",
- "dIV",
- "aa",
- "a\x00",
- "ab",
- "abb",
- "abbr0",
- "abbr ",
- " abbr",
- " a",
- "acceptcharset",
- "acceptCharset",
- "accept_charset",
- "h0",
- "h1h2",
- "h7",
- "onClick",
- "λ",
- // The following string has the same hash (0xa1d7fab7) as "onmouseover".
- "\x00\x00\x00\x00\x00\x50\x18\xae\x38\xd0\xb7",
- }
- for _, tc := range testCases {
- got := Lookup([]byte(tc))
- if got != 0 {
- t.Errorf("Lookup(%q): got %d, want 0", tc, got)
- }
- }
-}
-
-func TestForeignObject(t *testing.T) {
- const (
- afo = Foreignobject
- afO = ForeignObject
- sfo = "foreignobject"
- sfO = "foreignObject"
- )
- if got := Lookup([]byte(sfo)); got != afo {
- t.Errorf("Lookup(%q): got %#v, want %#v", sfo, got, afo)
- }
- if got := Lookup([]byte(sfO)); got != afO {
- t.Errorf("Lookup(%q): got %#v, want %#v", sfO, got, afO)
- }
- if got := afo.String(); got != sfo {
- t.Errorf("Atom(%#v).String(): got %q, want %q", afo, got, sfo)
- }
- if got := afO.String(); got != sfO {
- t.Errorf("Atom(%#v).String(): got %q, want %q", afO, got, sfO)
- }
-}
-
-func BenchmarkLookup(b *testing.B) {
- sortedTable := make([]string, 0, len(table))
- for _, a := range table {
- if a != 0 {
- sortedTable = append(sortedTable, a.String())
- }
- }
- sort.Strings(sortedTable)
-
- x := make([][]byte, 1000)
- for i := range x {
- x[i] = []byte(sortedTable[i%len(sortedTable)])
- }
-
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- for _, s := range x {
- Lookup(s)
- }
- }
-}
diff --git a/libgo/go/exp/html/atom/gen.go b/libgo/go/exp/html/atom/gen.go
deleted file mode 100644
index 9958a718842..00000000000
--- a/libgo/go/exp/html/atom/gen.go
+++ /dev/null
@@ -1,636 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build ignore
-
-package main
-
-// This program generates table.go and table_test.go.
-// Invoke as
-//
-// go run gen.go |gofmt >table.go
-// go run gen.go -test |gofmt >table_test.go
-
-import (
- "flag"
- "fmt"
- "math/rand"
- "os"
- "sort"
- "strings"
-)
-
-// identifier converts s to a Go exported identifier.
-// It converts "div" to "Div" and "accept-charset" to "AcceptCharset".
-func identifier(s string) string {
- b := make([]byte, 0, len(s))
- cap := true
- for _, c := range s {
- if c == '-' {
- cap = true
- continue
- }
- if cap && 'a' <= c && c <= 'z' {
- c -= 'a' - 'A'
- }
- cap = false
- b = append(b, byte(c))
- }
- return string(b)
-}
-
-var test = flag.Bool("test", false, "generate table_test.go")
-
-func main() {
- flag.Parse()
-
- var all []string
- all = append(all, elements...)
- all = append(all, attributes...)
- all = append(all, eventHandlers...)
- all = append(all, extra...)
- sort.Strings(all)
-
- if *test {
- fmt.Printf("// generated by go run gen.go -test; DO NOT EDIT\n\n")
- fmt.Printf("package atom\n\n")
- fmt.Printf("var testAtomList = []string{\n")
- for _, s := range all {
- fmt.Printf("\t%q,\n", s)
- }
- fmt.Printf("}\n")
- return
- }
-
- // uniq - lists have dups
- // compute max len too
- maxLen := 0
- w := 0
- for _, s := range all {
- if w == 0 || all[w-1] != s {
- if maxLen < len(s) {
- maxLen = len(s)
- }
- all[w] = s
- w++
- }
- }
- all = all[:w]
-
- // Find hash that minimizes table size.
- var best *table
- for i := 0; i < 1000000; i++ {
- if best != nil && 1<<(best.k-1) < len(all) {
- break
- }
- h := rand.Uint32()
- for k := uint(0); k <= 16; k++ {
- if best != nil && k >= best.k {
- break
- }
- var t table
- if t.init(h, k, all) {
- best = &t
- break
- }
- }
- }
- if best == nil {
- fmt.Fprintf(os.Stderr, "failed to construct string table\n")
- os.Exit(1)
- }
-
- // Lay out strings, using overlaps when possible.
- layout := append([]string{}, all...)
-
- // Remove strings that are substrings of other strings
- for changed := true; changed; {
- changed = false
- for i, s := range layout {
- if s == "" {
- continue
- }
- for j, t := range layout {
- if i != j && t != "" && strings.Contains(s, t) {
- changed = true
- layout[j] = ""
- }
- }
- }
- }
-
- // Join strings where one suffix matches another prefix.
- for {
- // Find best i, j, k such that layout[i][len-k:] == layout[j][:k],
- // maximizing overlap length k.
- besti := -1
- bestj := -1
- bestk := 0
- for i, s := range layout {
- if s == "" {
- continue
- }
- for j, t := range layout {
- if i == j {
- continue
- }
- for k := bestk + 1; k <= len(s) && k <= len(t); k++ {
- if s[len(s)-k:] == t[:k] {
- besti = i
- bestj = j
- bestk = k
- }
- }
- }
- }
- if bestk > 0 {
- layout[besti] += layout[bestj][bestk:]
- layout[bestj] = ""
- continue
- }
- break
- }
-
- text := strings.Join(layout, "")
-
- atom := map[string]uint32{}
- for _, s := range all {
- off := strings.Index(text, s)
- if off < 0 {
- panic("lost string " + s)
- }
- atom[s] = uint32(off<<8 | len(s))
- }
-
- // Generate the Go code.
- fmt.Printf("// generated by go run gen.go; DO NOT EDIT\n\n")
- fmt.Printf("package atom\n\nconst (\n")
- for _, s := range all {
- fmt.Printf("\t%s Atom = %#x\n", identifier(s), atom[s])
- }
- fmt.Printf(")\n\n")
-
- fmt.Printf("const hash0 = %#x\n\n", best.h0)
- fmt.Printf("const maxAtomLen = %d\n\n", maxLen)
-
- fmt.Printf("var table = [1<<%d]Atom{\n", best.k)
- for i, s := range best.tab {
- if s == "" {
- continue
- }
- fmt.Printf("\t%#x: %#x, // %s\n", i, atom[s], s)
- }
- fmt.Printf("}\n")
- datasize := (1 << best.k) * 4
-
- fmt.Printf("const atomText =\n")
- textsize := len(text)
- for len(text) > 60 {
- fmt.Printf("\t%q +\n", text[:60])
- text = text[60:]
- }
- fmt.Printf("\t%q\n\n", text)
-
- fmt.Fprintf(os.Stderr, "%d atoms; %d string bytes + %d tables = %d total data\n", len(all), textsize, datasize, textsize+datasize)
-}
-
-type byLen []string
-
-func (x byLen) Less(i, j int) bool { return len(x[i]) > len(x[j]) }
-func (x byLen) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
-func (x byLen) Len() int { return len(x) }
-
-// fnv computes the FNV hash with an arbitrary starting value h.
-func fnv(h uint32, s string) uint32 {
- for i := 0; i < len(s); i++ {
- h ^= uint32(s[i])
- h *= 16777619
- }
- return h
-}
-
-// A table represents an attempt at constructing the lookup table.
-// The lookup table uses cuckoo hashing, meaning that each string
-// can be found in one of two positions.
-type table struct {
- h0 uint32
- k uint
- mask uint32
- tab []string
-}
-
-// hash returns the two hashes for s.
-func (t *table) hash(s string) (h1, h2 uint32) {
- h := fnv(t.h0, s)
- h1 = h & t.mask
- h2 = (h >> 16) & t.mask
- return
-}
-
-// init initializes the table with the given parameters.
-// h0 is the initial hash value,
-// k is the number of bits of hash value to use, and
-// x is the list of strings to store in the table.
-// init returns false if the table cannot be constructed.
-func (t *table) init(h0 uint32, k uint, x []string) bool {
- t.h0 = h0
- t.k = k
- t.tab = make([]string, 1< len(t.tab) {
- return false
- }
- s := t.tab[i]
- h1, h2 := t.hash(s)
- j := h1 + h2 - i
- if t.tab[j] != "" && !t.push(j, depth+1) {
- return false
- }
- t.tab[j] = s
- return true
-}
-
-// The lists of element names and attribute keys were taken from
-// http://www.whatwg.org/specs/web-apps/current-work/multipage/section-index.html
-// as of the "HTML Living Standard - Last Updated 30 May 2012" version.
-
-var elements = []string{
- "a",
- "abbr",
- "address",
- "area",
- "article",
- "aside",
- "audio",
- "b",
- "base",
- "bdi",
- "bdo",
- "blockquote",
- "body",
- "br",
- "button",
- "canvas",
- "caption",
- "cite",
- "code",
- "col",
- "colgroup",
- "command",
- "data",
- "datalist",
- "dd",
- "del",
- "details",
- "dfn",
- "dialog",
- "div",
- "dl",
- "dt",
- "em",
- "embed",
- "fieldset",
- "figcaption",
- "figure",
- "footer",
- "form",
- "h1",
- "h2",
- "h3",
- "h4",
- "h5",
- "h6",
- "head",
- "header",
- "hgroup",
- "hr",
- "html",
- "i",
- "iframe",
- "img",
- "input",
- "ins",
- "kbd",
- "keygen",
- "label",
- "legend",
- "li",
- "link",
- "map",
- "mark",
- "menu",
- "meta",
- "meter",
- "nav",
- "noscript",
- "object",
- "ol",
- "optgroup",
- "option",
- "output",
- "p",
- "param",
- "pre",
- "progress",
- "q",
- "rp",
- "rt",
- "ruby",
- "s",
- "samp",
- "script",
- "section",
- "select",
- "small",
- "source",
- "span",
- "strong",
- "style",
- "sub",
- "summary",
- "sup",
- "table",
- "tbody",
- "td",
- "textarea",
- "tfoot",
- "th",
- "thead",
- "time",
- "title",
- "tr",
- "track",
- "u",
- "ul",
- "var",
- "video",
- "wbr",
-}
-
-var attributes = []string{
- "accept",
- "accept-charset",
- "accesskey",
- "action",
- "alt",
- "async",
- "autocomplete",
- "autofocus",
- "autoplay",
- "border",
- "challenge",
- "charset",
- "checked",
- "cite",
- "class",
- "cols",
- "colspan",
- "command",
- "content",
- "contenteditable",
- "contextmenu",
- "controls",
- "coords",
- "crossorigin",
- "data",
- "datetime",
- "default",
- "defer",
- "dir",
- "dirname",
- "disabled",
- "download",
- "draggable",
- "dropzone",
- "enctype",
- "for",
- "form",
- "formaction",
- "formenctype",
- "formmethod",
- "formnovalidate",
- "formtarget",
- "headers",
- "height",
- "hidden",
- "high",
- "href",
- "hreflang",
- "http-equiv",
- "icon",
- "id",
- "inert",
- "ismap",
- "itemid",
- "itemprop",
- "itemref",
- "itemscope",
- "itemtype",
- "keytype",
- "kind",
- "label",
- "lang",
- "list",
- "loop",
- "low",
- "manifest",
- "max",
- "maxlength",
- "media",
- "mediagroup",
- "method",
- "min",
- "multiple",
- "muted",
- "name",
- "novalidate",
- "open",
- "optimum",
- "pattern",
- "ping",
- "placeholder",
- "poster",
- "preload",
- "radiogroup",
- "readonly",
- "rel",
- "required",
- "reversed",
- "rows",
- "rowspan",
- "sandbox",
- "spellcheck",
- "scope",
- "scoped",
- "seamless",
- "selected",
- "shape",
- "size",
- "sizes",
- "span",
- "src",
- "srcdoc",
- "srclang",
- "start",
- "step",
- "style",
- "tabindex",
- "target",
- "title",
- "translate",
- "type",
- "typemustmatch",
- "usemap",
- "value",
- "width",
- "wrap",
-}
-
-var eventHandlers = []string{
- "onabort",
- "onafterprint",
- "onbeforeprint",
- "onbeforeunload",
- "onblur",
- "oncancel",
- "oncanplay",
- "oncanplaythrough",
- "onchange",
- "onclick",
- "onclose",
- "oncontextmenu",
- "oncuechange",
- "ondblclick",
- "ondrag",
- "ondragend",
- "ondragenter",
- "ondragleave",
- "ondragover",
- "ondragstart",
- "ondrop",
- "ondurationchange",
- "onemptied",
- "onended",
- "onerror",
- "onfocus",
- "onhashchange",
- "oninput",
- "oninvalid",
- "onkeydown",
- "onkeypress",
- "onkeyup",
- "onload",
- "onloadeddata",
- "onloadedmetadata",
- "onloadstart",
- "onmessage",
- "onmousedown",
- "onmousemove",
- "onmouseout",
- "onmouseover",
- "onmouseup",
- "onmousewheel",
- "onoffline",
- "ononline",
- "onpagehide",
- "onpageshow",
- "onpause",
- "onplay",
- "onplaying",
- "onpopstate",
- "onprogress",
- "onratechange",
- "onreset",
- "onresize",
- "onscroll",
- "onseeked",
- "onseeking",
- "onselect",
- "onshow",
- "onstalled",
- "onstorage",
- "onsubmit",
- "onsuspend",
- "ontimeupdate",
- "onunload",
- "onvolumechange",
- "onwaiting",
-}
-
-// extra are ad-hoc values not covered by any of the lists above.
-var extra = []string{
- "align",
- "annotation",
- "annotation-xml",
- "applet",
- "basefont",
- "bgsound",
- "big",
- "blink",
- "center",
- "color",
- "desc",
- "face",
- "font",
- "foreignObject", // HTML is case-insensitive, but SVG-embedded-in-HTML is case-sensitive.
- "foreignobject",
- "frame",
- "frameset",
- "image",
- "isindex",
- "listing",
- "malignmark",
- "marquee",
- "math",
- "mglyph",
- "mi",
- "mn",
- "mo",
- "ms",
- "mtext",
- "nobr",
- "noembed",
- "noframes",
- "plaintext",
- "prompt",
- "public",
- "spacer",
- "strike",
- "svg",
- "system",
- "tt",
- "xmp",
-}
diff --git a/libgo/go/exp/html/atom/table.go b/libgo/go/exp/html/atom/table.go
deleted file mode 100644
index 20b8b8a5903..00000000000
--- a/libgo/go/exp/html/atom/table.go
+++ /dev/null
@@ -1,694 +0,0 @@
-// generated by go run gen.go; DO NOT EDIT
-
-package atom
-
-const (
- A Atom = 0x1
- Abbr Atom = 0x4
- Accept Atom = 0x2106
- AcceptCharset Atom = 0x210e
- Accesskey Atom = 0x3309
- Action Atom = 0x21b06
- Address Atom = 0x5d507
- Align Atom = 0x1105
- Alt Atom = 0x4503
- Annotation Atom = 0x18d0a
- AnnotationXml Atom = 0x18d0e
- Applet Atom = 0x2d106
- Area Atom = 0x31804
- Article Atom = 0x39907
- Aside Atom = 0x4f05
- Async Atom = 0x9305
- Audio Atom = 0xaf05
- Autocomplete Atom = 0xd50c
- Autofocus Atom = 0xe109
- Autoplay Atom = 0x10c08
- B Atom = 0x101
- Base Atom = 0x11404
- Basefont Atom = 0x11408
- Bdi Atom = 0x1a03
- Bdo Atom = 0x12503
- Bgsound Atom = 0x13807
- Big Atom = 0x14403
- Blink Atom = 0x14705
- Blockquote Atom = 0x14c0a
- Body Atom = 0x2f04
- Border Atom = 0x15606
- Br Atom = 0x202
- Button Atom = 0x15c06
- Canvas Atom = 0x4b06
- Caption Atom = 0x1e007
- Center Atom = 0x2df06
- Challenge Atom = 0x23e09
- Charset Atom = 0x2807
- Checked Atom = 0x33f07
- Cite Atom = 0x9704
- Class Atom = 0x3d905
- Code Atom = 0x16f04
- Col Atom = 0x17603
- Colgroup Atom = 0x17608
- Color Atom = 0x18305
- Cols Atom = 0x18804
- Colspan Atom = 0x18807
- Command Atom = 0x19b07
- Content Atom = 0x42c07
- Contenteditable Atom = 0x42c0f
- Contextmenu Atom = 0x3480b
- Controls Atom = 0x1ae08
- Coords Atom = 0x1ba06
- Crossorigin Atom = 0x1c40b
- Data Atom = 0x44304
- Datalist Atom = 0x44308
- Datetime Atom = 0x25b08
- Dd Atom = 0x28802
- Default Atom = 0x5207
- Defer Atom = 0x17105
- Del Atom = 0x4d603
- Desc Atom = 0x4804
- Details Atom = 0x6507
- Dfn Atom = 0x8303
- Dialog Atom = 0x1b06
- Dir Atom = 0x9d03
- Dirname Atom = 0x9d07
- Disabled Atom = 0x10008
- Div Atom = 0x10703
- Dl Atom = 0x13e02
- Download Atom = 0x40908
- Draggable Atom = 0x1a109
- Dropzone Atom = 0x3a208
- Dt Atom = 0x4e402
- Em Atom = 0x7f02
- Embed Atom = 0x7f05
- Enctype Atom = 0x23007
- Face Atom = 0x2dd04
- Fieldset Atom = 0x1d508
- Figcaption Atom = 0x1dd0a
- Figure Atom = 0x1f106
- Font Atom = 0x11804
- Footer Atom = 0x5906
- For Atom = 0x1fd03
- ForeignObject Atom = 0x1fd0d
- Foreignobject Atom = 0x20a0d
- Form Atom = 0x21704
- Formaction Atom = 0x2170a
- Formenctype Atom = 0x22c0b
- Formmethod Atom = 0x2470a
- Formnovalidate Atom = 0x2510e
- Formtarget Atom = 0x2660a
- Frame Atom = 0x8705
- Frameset Atom = 0x8708
- H1 Atom = 0x13602
- H2 Atom = 0x29602
- H3 Atom = 0x2c502
- H4 Atom = 0x30e02
- H5 Atom = 0x4e602
- H6 Atom = 0x27002
- Head Atom = 0x2fa04
- Header Atom = 0x2fa06
- Headers Atom = 0x2fa07
- Height Atom = 0x27206
- Hgroup Atom = 0x27a06
- Hidden Atom = 0x28606
- High Atom = 0x29304
- Hr Atom = 0x13102
- Href Atom = 0x29804
- Hreflang Atom = 0x29808
- Html Atom = 0x27604
- HttpEquiv Atom = 0x2a00a
- I Atom = 0x601
- Icon Atom = 0x42b04
- Id Atom = 0x5102
- Iframe Atom = 0x2b406
- Image Atom = 0x2ba05
- Img Atom = 0x2bf03
- Inert Atom = 0x4c105
- Input Atom = 0x3f605
- Ins Atom = 0x1cd03
- Isindex Atom = 0x2c707
- Ismap Atom = 0x2ce05
- Itemid Atom = 0x9806
- Itemprop Atom = 0x57e08
- Itemref Atom = 0x2d707
- Itemscope Atom = 0x2e509
- Itemtype Atom = 0x2ef08
- Kbd Atom = 0x1903
- Keygen Atom = 0x3906
- Keytype Atom = 0x51207
- Kind Atom = 0xfd04
- Label Atom = 0xba05
- Lang Atom = 0x29c04
- Legend Atom = 0x1a806
- Li Atom = 0x1202
- Link Atom = 0x14804
- List Atom = 0x44704
- Listing Atom = 0x44707
- Loop Atom = 0xbe04
- Low Atom = 0x13f03
- Malignmark Atom = 0x100a
- Manifest Atom = 0x5b608
- Map Atom = 0x2d003
- Mark Atom = 0x1604
- Marquee Atom = 0x5f207
- Math Atom = 0x2f704
- Max Atom = 0x30603
- Maxlength Atom = 0x30609
- Media Atom = 0xa205
- Mediagroup Atom = 0xa20a
- Menu Atom = 0x34f04
- Meta Atom = 0x45604
- Meter Atom = 0x26105
- Method Atom = 0x24b06
- Mglyph Atom = 0x2c006
- Mi Atom = 0x9b02
- Min Atom = 0x31003
- Mn Atom = 0x25402
- Mo Atom = 0x47a02
- Ms Atom = 0x2e802
- Mtext Atom = 0x31305
- Multiple Atom = 0x32108
- Muted Atom = 0x32905
- Name Atom = 0xa004
- Nav Atom = 0x3e03
- Nobr Atom = 0x7404
- Noembed Atom = 0x7d07
- Noframes Atom = 0x8508
- Noscript Atom = 0x28b08
- Novalidate Atom = 0x2550a
- Object Atom = 0x21106
- Ol Atom = 0xcd02
- Onabort Atom = 0x16007
- Onafterprint Atom = 0x1e50c
- Onbeforeprint Atom = 0x21f0d
- Onbeforeunload Atom = 0x5c90e
- Onblur Atom = 0x3e206
- Oncancel Atom = 0xb308
- Oncanplay Atom = 0x12709
- Oncanplaythrough Atom = 0x12710
- Onchange Atom = 0x3b808
- Onclick Atom = 0x2ad07
- Onclose Atom = 0x32e07
- Oncontextmenu Atom = 0x3460d
- Oncuechange Atom = 0x3530b
- Ondblclick Atom = 0x35e0a
- Ondrag Atom = 0x36806
- Ondragend Atom = 0x36809
- Ondragenter Atom = 0x3710b
- Ondragleave Atom = 0x37c0b
- Ondragover Atom = 0x3870a
- Ondragstart Atom = 0x3910b
- Ondrop Atom = 0x3a006
- Ondurationchange Atom = 0x3b010
- Onemptied Atom = 0x3a709
- Onended Atom = 0x3c007
- Onerror Atom = 0x3c707
- Onfocus Atom = 0x3ce07
- Onhashchange Atom = 0x3e80c
- Oninput Atom = 0x3f407
- Oninvalid Atom = 0x3fb09
- Onkeydown Atom = 0x40409
- Onkeypress Atom = 0x4110a
- Onkeyup Atom = 0x42107
- Onload Atom = 0x43b06
- Onloadeddata Atom = 0x43b0c
- Onloadedmetadata Atom = 0x44e10
- Onloadstart Atom = 0x4640b
- Onmessage Atom = 0x46f09
- Onmousedown Atom = 0x4780b
- Onmousemove Atom = 0x4830b
- Onmouseout Atom = 0x48e0a
- Onmouseover Atom = 0x49b0b
- Onmouseup Atom = 0x4a609
- Onmousewheel Atom = 0x4af0c
- Onoffline Atom = 0x4bb09
- Ononline Atom = 0x4c608
- Onpagehide Atom = 0x4ce0a
- Onpageshow Atom = 0x4d90a
- Onpause Atom = 0x4e807
- Onplay Atom = 0x4f206
- Onplaying Atom = 0x4f209
- Onpopstate Atom = 0x4fb0a
- Onprogress Atom = 0x5050a
- Onratechange Atom = 0x5190c
- Onreset Atom = 0x52507
- Onresize Atom = 0x52c08
- Onscroll Atom = 0x53a08
- Onseeked Atom = 0x54208
- Onseeking Atom = 0x54a09
- Onselect Atom = 0x55308
- Onshow Atom = 0x55d06
- Onstalled Atom = 0x56609
- Onstorage Atom = 0x56f09
- Onsubmit Atom = 0x57808
- Onsuspend Atom = 0x58809
- Ontimeupdate Atom = 0x1190c
- Onunload Atom = 0x59108
- Onvolumechange Atom = 0x5990e
- Onwaiting Atom = 0x5a709
- Open Atom = 0x58404
- Optgroup Atom = 0xc008
- Optimum Atom = 0x5b007
- Option Atom = 0x5c506
- Output Atom = 0x49506
- P Atom = 0xc01
- Param Atom = 0xc05
- Pattern Atom = 0x6e07
- Ping Atom = 0xab04
- Placeholder Atom = 0xc70b
- Plaintext Atom = 0xf109
- Poster Atom = 0x17d06
- Pre Atom = 0x27f03
- Preload Atom = 0x27f07
- Progress Atom = 0x50708
- Prompt Atom = 0x5bf06
- Public Atom = 0x42706
- Q Atom = 0x15101
- Radiogroup Atom = 0x30a
- Readonly Atom = 0x31908
- Rel Atom = 0x28003
- Required Atom = 0x1f508
- Reversed Atom = 0x5e08
- Rows Atom = 0x7704
- Rowspan Atom = 0x7707
- Rp Atom = 0x1eb02
- Rt Atom = 0x16502
- Ruby Atom = 0xd104
- S Atom = 0x2c01
- Samp Atom = 0x6b04
- Sandbox Atom = 0xe907
- Scope Atom = 0x2e905
- Scoped Atom = 0x2e906
- Script Atom = 0x28d06
- Seamless Atom = 0x33308
- Section Atom = 0x3dd07
- Select Atom = 0x55506
- Selected Atom = 0x55508
- Shape Atom = 0x1b505
- Size Atom = 0x53004
- Sizes Atom = 0x53005
- Small Atom = 0x1bf05
- Source Atom = 0x1cf06
- Spacer Atom = 0x30006
- Span Atom = 0x7a04
- Spellcheck Atom = 0x33a0a
- Src Atom = 0x3d403
- Srcdoc Atom = 0x3d406
- Srclang Atom = 0x41a07
- Start Atom = 0x39705
- Step Atom = 0x5bc04
- Strike Atom = 0x50e06
- Strong Atom = 0x53406
- Style Atom = 0x5db05
- Sub Atom = 0x57a03
- Summary Atom = 0x5e007
- Sup Atom = 0x5e703
- Svg Atom = 0x5ea03
- System Atom = 0x5ed06
- Tabindex Atom = 0x45c08
- Table Atom = 0x43605
- Target Atom = 0x26a06
- Tbody Atom = 0x2e05
- Td Atom = 0x4702
- Textarea Atom = 0x31408
- Tfoot Atom = 0x5805
- Th Atom = 0x13002
- Thead Atom = 0x2f905
- Time Atom = 0x11b04
- Title Atom = 0x8e05
- Tr Atom = 0xf902
- Track Atom = 0xf905
- Translate Atom = 0x16609
- Tt Atom = 0x7002
- Type Atom = 0x23304
- Typemustmatch Atom = 0x2330d
- U Atom = 0xb01
- Ul Atom = 0x5602
- Usemap Atom = 0x4ec06
- Value Atom = 0x4005
- Var Atom = 0x10903
- Video Atom = 0x2a905
- Wbr Atom = 0x14103
- Width Atom = 0x4e205
- Wrap Atom = 0x56204
- Xmp Atom = 0xef03
-)
-
-const hash0 = 0xc17da63e
-
-const maxAtomLen = 16
-
-var table = [1 << 9]Atom{
- 0x1: 0x4830b, // onmousemove
- 0x2: 0x5a709, // onwaiting
- 0x4: 0x5bf06, // prompt
- 0x7: 0x5b007, // optimum
- 0x8: 0x1604, // mark
- 0xa: 0x2d707, // itemref
- 0xb: 0x4d90a, // onpageshow
- 0xc: 0x55506, // select
- 0xd: 0x1a109, // draggable
- 0xe: 0x3e03, // nav
- 0xf: 0x19b07, // command
- 0x11: 0xb01, // u
- 0x14: 0x2fa07, // headers
- 0x15: 0x44308, // datalist
- 0x17: 0x6b04, // samp
- 0x1a: 0x40409, // onkeydown
- 0x1b: 0x53a08, // onscroll
- 0x1c: 0x17603, // col
- 0x20: 0x57e08, // itemprop
- 0x21: 0x2a00a, // http-equiv
- 0x22: 0x5e703, // sup
- 0x24: 0x1f508, // required
- 0x2b: 0x27f07, // preload
- 0x2c: 0x21f0d, // onbeforeprint
- 0x2d: 0x3710b, // ondragenter
- 0x2e: 0x4e402, // dt
- 0x2f: 0x57808, // onsubmit
- 0x30: 0x13102, // hr
- 0x31: 0x3460d, // oncontextmenu
- 0x33: 0x2ba05, // image
- 0x34: 0x4e807, // onpause
- 0x35: 0x27a06, // hgroup
- 0x36: 0xab04, // ping
- 0x37: 0x55308, // onselect
- 0x3a: 0x10703, // div
- 0x40: 0x9b02, // mi
- 0x41: 0x33308, // seamless
- 0x42: 0x2807, // charset
- 0x43: 0x5102, // id
- 0x44: 0x4fb0a, // onpopstate
- 0x45: 0x4d603, // del
- 0x46: 0x5f207, // marquee
- 0x47: 0x3309, // accesskey
- 0x49: 0x5906, // footer
- 0x4a: 0x2d106, // applet
- 0x4b: 0x2ce05, // ismap
- 0x51: 0x34f04, // menu
- 0x52: 0x2f04, // body
- 0x55: 0x8708, // frameset
- 0x56: 0x52507, // onreset
- 0x57: 0x14705, // blink
- 0x58: 0x8e05, // title
- 0x59: 0x39907, // article
- 0x5b: 0x13002, // th
- 0x5d: 0x15101, // q
- 0x5e: 0x58404, // open
- 0x5f: 0x31804, // area
- 0x61: 0x43b06, // onload
- 0x62: 0x3f605, // input
- 0x63: 0x11404, // base
- 0x64: 0x18807, // colspan
- 0x65: 0x51207, // keytype
- 0x66: 0x13e02, // dl
- 0x68: 0x1d508, // fieldset
- 0x6a: 0x31003, // min
- 0x6b: 0x10903, // var
- 0x6f: 0x2fa06, // header
- 0x70: 0x16502, // rt
- 0x71: 0x17608, // colgroup
- 0x72: 0x25402, // mn
- 0x74: 0x16007, // onabort
- 0x75: 0x3906, // keygen
- 0x76: 0x4bb09, // onoffline
- 0x77: 0x23e09, // challenge
- 0x78: 0x2d003, // map
- 0x7a: 0x30e02, // h4
- 0x7b: 0x3c707, // onerror
- 0x7c: 0x30609, // maxlength
- 0x7d: 0x31305, // mtext
- 0x7e: 0x5805, // tfoot
- 0x7f: 0x11804, // font
- 0x80: 0x100a, // malignmark
- 0x81: 0x45604, // meta
- 0x82: 0x9305, // async
- 0x83: 0x2c502, // h3
- 0x84: 0x28802, // dd
- 0x85: 0x29804, // href
- 0x86: 0xa20a, // mediagroup
- 0x87: 0x1ba06, // coords
- 0x88: 0x41a07, // srclang
- 0x89: 0x35e0a, // ondblclick
- 0x8a: 0x4005, // value
- 0x8c: 0xb308, // oncancel
- 0x8e: 0x33a0a, // spellcheck
- 0x8f: 0x8705, // frame
- 0x91: 0x14403, // big
- 0x94: 0x21b06, // action
- 0x95: 0x9d03, // dir
- 0x97: 0x31908, // readonly
- 0x99: 0x43605, // table
- 0x9a: 0x5e007, // summary
- 0x9b: 0x14103, // wbr
- 0x9c: 0x30a, // radiogroup
- 0x9d: 0xa004, // name
- 0x9f: 0x5ed06, // system
- 0xa1: 0x18305, // color
- 0xa2: 0x4b06, // canvas
- 0xa3: 0x27604, // html
- 0xa5: 0x54a09, // onseeking
- 0xac: 0x1b505, // shape
- 0xad: 0x28003, // rel
- 0xae: 0x12710, // oncanplaythrough
- 0xaf: 0x3870a, // ondragover
- 0xb1: 0x1fd0d, // foreignObject
- 0xb3: 0x7704, // rows
- 0xb6: 0x44707, // listing
- 0xb7: 0x49506, // output
- 0xb9: 0x3480b, // contextmenu
- 0xbb: 0x13f03, // low
- 0xbc: 0x1eb02, // rp
- 0xbd: 0x58809, // onsuspend
- 0xbe: 0x15c06, // button
- 0xbf: 0x4804, // desc
- 0xc1: 0x3dd07, // section
- 0xc2: 0x5050a, // onprogress
- 0xc3: 0x56f09, // onstorage
- 0xc4: 0x2f704, // math
- 0xc5: 0x4f206, // onplay
- 0xc7: 0x5602, // ul
- 0xc8: 0x6e07, // pattern
- 0xc9: 0x4af0c, // onmousewheel
- 0xca: 0x36809, // ondragend
- 0xcb: 0xd104, // ruby
- 0xcc: 0xc01, // p
- 0xcd: 0x32e07, // onclose
- 0xce: 0x26105, // meter
- 0xcf: 0x13807, // bgsound
- 0xd2: 0x27206, // height
- 0xd4: 0x101, // b
- 0xd5: 0x2ef08, // itemtype
- 0xd8: 0x1e007, // caption
- 0xd9: 0x10008, // disabled
- 0xdc: 0x5ea03, // svg
- 0xdd: 0x1bf05, // small
- 0xde: 0x44304, // data
- 0xe0: 0x4c608, // ononline
- 0xe1: 0x2c006, // mglyph
- 0xe3: 0x7f05, // embed
- 0xe4: 0xf902, // tr
- 0xe5: 0x4640b, // onloadstart
- 0xe7: 0x3b010, // ondurationchange
- 0xed: 0x12503, // bdo
- 0xee: 0x4702, // td
- 0xef: 0x4f05, // aside
- 0xf0: 0x29602, // h2
- 0xf1: 0x50708, // progress
- 0xf2: 0x14c0a, // blockquote
- 0xf4: 0xba05, // label
- 0xf5: 0x601, // i
- 0xf7: 0x7707, // rowspan
- 0xfb: 0x4f209, // onplaying
- 0xfd: 0x2bf03, // img
- 0xfe: 0xc008, // optgroup
- 0xff: 0x42c07, // content
- 0x101: 0x5190c, // onratechange
- 0x103: 0x3e80c, // onhashchange
- 0x104: 0x6507, // details
- 0x106: 0x40908, // download
- 0x109: 0xe907, // sandbox
- 0x10b: 0x42c0f, // contenteditable
- 0x10d: 0x37c0b, // ondragleave
- 0x10e: 0x2106, // accept
- 0x10f: 0x55508, // selected
- 0x112: 0x2170a, // formaction
- 0x113: 0x2df06, // center
- 0x115: 0x44e10, // onloadedmetadata
- 0x116: 0x14804, // link
- 0x117: 0x11b04, // time
- 0x118: 0x1c40b, // crossorigin
- 0x119: 0x3ce07, // onfocus
- 0x11a: 0x56204, // wrap
- 0x11b: 0x42b04, // icon
- 0x11d: 0x2a905, // video
- 0x11e: 0x3d905, // class
- 0x121: 0x5990e, // onvolumechange
- 0x122: 0x3e206, // onblur
- 0x123: 0x2e509, // itemscope
- 0x124: 0x5db05, // style
- 0x127: 0x42706, // public
- 0x129: 0x2510e, // formnovalidate
- 0x12a: 0x55d06, // onshow
- 0x12c: 0x16609, // translate
- 0x12d: 0x9704, // cite
- 0x12e: 0x2e802, // ms
- 0x12f: 0x1190c, // ontimeupdate
- 0x130: 0xfd04, // kind
- 0x131: 0x2660a, // formtarget
- 0x135: 0x3c007, // onended
- 0x136: 0x28606, // hidden
- 0x137: 0x2c01, // s
- 0x139: 0x2470a, // formmethod
- 0x13a: 0x44704, // list
- 0x13c: 0x27002, // h6
- 0x13d: 0xcd02, // ol
- 0x13e: 0x3530b, // oncuechange
- 0x13f: 0x20a0d, // foreignobject
- 0x143: 0x5c90e, // onbeforeunload
- 0x145: 0x3a709, // onemptied
- 0x146: 0x17105, // defer
- 0x147: 0xef03, // xmp
- 0x148: 0xaf05, // audio
- 0x149: 0x1903, // kbd
- 0x14c: 0x46f09, // onmessage
- 0x14d: 0x5c506, // option
- 0x14e: 0x4503, // alt
- 0x14f: 0x33f07, // checked
- 0x150: 0x10c08, // autoplay
- 0x152: 0x202, // br
- 0x153: 0x2550a, // novalidate
- 0x156: 0x7d07, // noembed
- 0x159: 0x2ad07, // onclick
- 0x15a: 0x4780b, // onmousedown
- 0x15b: 0x3b808, // onchange
- 0x15e: 0x3fb09, // oninvalid
- 0x15f: 0x2e906, // scoped
- 0x160: 0x1ae08, // controls
- 0x161: 0x32905, // muted
- 0x163: 0x4ec06, // usemap
- 0x164: 0x1dd0a, // figcaption
- 0x165: 0x36806, // ondrag
- 0x166: 0x29304, // high
- 0x168: 0x3d403, // src
- 0x169: 0x17d06, // poster
- 0x16b: 0x18d0e, // annotation-xml
- 0x16c: 0x5bc04, // step
- 0x16d: 0x4, // abbr
- 0x16e: 0x1b06, // dialog
- 0x170: 0x1202, // li
- 0x172: 0x47a02, // mo
- 0x175: 0x1fd03, // for
- 0x176: 0x1cd03, // ins
- 0x178: 0x53004, // size
- 0x17a: 0x5207, // default
- 0x17b: 0x1a03, // bdi
- 0x17c: 0x4ce0a, // onpagehide
- 0x17d: 0x9d07, // dirname
- 0x17e: 0x23304, // type
- 0x17f: 0x21704, // form
- 0x180: 0x4c105, // inert
- 0x181: 0x12709, // oncanplay
- 0x182: 0x8303, // dfn
- 0x183: 0x45c08, // tabindex
- 0x186: 0x7f02, // em
- 0x187: 0x29c04, // lang
- 0x189: 0x3a208, // dropzone
- 0x18a: 0x4110a, // onkeypress
- 0x18b: 0x25b08, // datetime
- 0x18c: 0x18804, // cols
- 0x18d: 0x1, // a
- 0x18e: 0x43b0c, // onloadeddata
- 0x191: 0x15606, // border
- 0x192: 0x2e05, // tbody
- 0x193: 0x24b06, // method
- 0x195: 0xbe04, // loop
- 0x196: 0x2b406, // iframe
- 0x198: 0x2fa04, // head
- 0x19e: 0x5b608, // manifest
- 0x19f: 0xe109, // autofocus
- 0x1a0: 0x16f04, // code
- 0x1a1: 0x53406, // strong
- 0x1a2: 0x32108, // multiple
- 0x1a3: 0xc05, // param
- 0x1a6: 0x23007, // enctype
- 0x1a7: 0x2dd04, // face
- 0x1a8: 0xf109, // plaintext
- 0x1a9: 0x13602, // h1
- 0x1aa: 0x56609, // onstalled
- 0x1ad: 0x28d06, // script
- 0x1ae: 0x30006, // spacer
- 0x1af: 0x52c08, // onresize
- 0x1b0: 0x49b0b, // onmouseover
- 0x1b1: 0x59108, // onunload
- 0x1b2: 0x54208, // onseeked
- 0x1b4: 0x2330d, // typemustmatch
- 0x1b5: 0x1f106, // figure
- 0x1b6: 0x48e0a, // onmouseout
- 0x1b7: 0x27f03, // pre
- 0x1b8: 0x4e205, // width
- 0x1bb: 0x7404, // nobr
- 0x1be: 0x7002, // tt
- 0x1bf: 0x1105, // align
- 0x1c0: 0x3f407, // oninput
- 0x1c3: 0x42107, // onkeyup
- 0x1c6: 0x1e50c, // onafterprint
- 0x1c7: 0x210e, // accept-charset
- 0x1c8: 0x9806, // itemid
- 0x1cb: 0x50e06, // strike
- 0x1cc: 0x57a03, // sub
- 0x1cd: 0xf905, // track
- 0x1ce: 0x39705, // start
- 0x1d0: 0x11408, // basefont
- 0x1d6: 0x1cf06, // source
- 0x1d7: 0x1a806, // legend
- 0x1d8: 0x2f905, // thead
- 0x1da: 0x2e905, // scope
- 0x1dd: 0x21106, // object
- 0x1de: 0xa205, // media
- 0x1df: 0x18d0a, // annotation
- 0x1e0: 0x22c0b, // formenctype
- 0x1e2: 0x28b08, // noscript
- 0x1e4: 0x53005, // sizes
- 0x1e5: 0xd50c, // autocomplete
- 0x1e6: 0x7a04, // span
- 0x1e7: 0x8508, // noframes
- 0x1e8: 0x26a06, // target
- 0x1e9: 0x3a006, // ondrop
- 0x1ea: 0x3d406, // srcdoc
- 0x1ec: 0x5e08, // reversed
- 0x1f0: 0x2c707, // isindex
- 0x1f3: 0x29808, // hreflang
- 0x1f5: 0x4e602, // h5
- 0x1f6: 0x5d507, // address
- 0x1fa: 0x30603, // max
- 0x1fb: 0xc70b, // placeholder
- 0x1fc: 0x31408, // textarea
- 0x1fe: 0x4a609, // onmouseup
- 0x1ff: 0x3910b, // ondragstart
-}
-
-const atomText = "abbradiogrouparamalignmarkbdialogaccept-charsetbodyaccesskey" +
- "genavaluealtdescanvasidefaultfootereversedetailsampatternobr" +
- "owspanoembedfnoframesetitleasyncitemidirnamediagroupingaudio" +
- "ncancelabelooptgrouplaceholderubyautocompleteautofocusandbox" +
- "mplaintextrackindisabledivarautoplaybasefontimeupdatebdoncan" +
- "playthrough1bgsoundlowbrbigblinkblockquoteborderbuttonabortr" +
- "anslatecodefercolgroupostercolorcolspannotation-xmlcommandra" +
- "ggablegendcontrolshapecoordsmallcrossoriginsourcefieldsetfig" +
- "captionafterprintfigurequiredforeignObjectforeignobjectforma" +
- "ctionbeforeprintformenctypemustmatchallengeformmethodformnov" +
- "alidatetimeterformtargeth6heightmlhgroupreloadhiddenoscripth" +
- "igh2hreflanghttp-equivideonclickiframeimageimglyph3isindexis" +
- "mappletitemrefacenteritemscopeditemtypematheaderspacermaxlen" +
- "gth4minmtextareadonlymultiplemutedoncloseamlesspellcheckedon" +
- "contextmenuoncuechangeondblclickondragendondragenterondragle" +
- "aveondragoverondragstarticleondropzonemptiedondurationchange" +
- "onendedonerroronfocusrcdoclassectionbluronhashchangeoninputo" +
- "ninvalidonkeydownloadonkeypressrclangonkeyupublicontentedita" +
- "bleonloadeddatalistingonloadedmetadatabindexonloadstartonmes" +
- "sageonmousedownonmousemoveonmouseoutputonmouseoveronmouseupo" +
- "nmousewheelonofflinertononlineonpagehidelonpageshowidth5onpa" +
- "usemaponplayingonpopstateonprogresstrikeytypeonratechangeonr" +
- "esetonresizestrongonscrollonseekedonseekingonselectedonshowr" +
- "aponstalledonstorageonsubmitempropenonsuspendonunloadonvolum" +
- "echangeonwaitingoptimumanifestepromptoptionbeforeunloaddress" +
- "tylesummarysupsvgsystemarquee"
diff --git a/libgo/go/exp/html/atom/table_test.go b/libgo/go/exp/html/atom/table_test.go
deleted file mode 100644
index db016a1c01c..00000000000
--- a/libgo/go/exp/html/atom/table_test.go
+++ /dev/null
@@ -1,341 +0,0 @@
-// generated by go run gen.go -test; DO NOT EDIT
-
-package atom
-
-var testAtomList = []string{
- "a",
- "abbr",
- "accept",
- "accept-charset",
- "accesskey",
- "action",
- "address",
- "align",
- "alt",
- "annotation",
- "annotation-xml",
- "applet",
- "area",
- "article",
- "aside",
- "async",
- "audio",
- "autocomplete",
- "autofocus",
- "autoplay",
- "b",
- "base",
- "basefont",
- "bdi",
- "bdo",
- "bgsound",
- "big",
- "blink",
- "blockquote",
- "body",
- "border",
- "br",
- "button",
- "canvas",
- "caption",
- "center",
- "challenge",
- "charset",
- "checked",
- "cite",
- "cite",
- "class",
- "code",
- "col",
- "colgroup",
- "color",
- "cols",
- "colspan",
- "command",
- "command",
- "content",
- "contenteditable",
- "contextmenu",
- "controls",
- "coords",
- "crossorigin",
- "data",
- "data",
- "datalist",
- "datetime",
- "dd",
- "default",
- "defer",
- "del",
- "desc",
- "details",
- "dfn",
- "dialog",
- "dir",
- "dirname",
- "disabled",
- "div",
- "dl",
- "download",
- "draggable",
- "dropzone",
- "dt",
- "em",
- "embed",
- "enctype",
- "face",
- "fieldset",
- "figcaption",
- "figure",
- "font",
- "footer",
- "for",
- "foreignObject",
- "foreignobject",
- "form",
- "form",
- "formaction",
- "formenctype",
- "formmethod",
- "formnovalidate",
- "formtarget",
- "frame",
- "frameset",
- "h1",
- "h2",
- "h3",
- "h4",
- "h5",
- "h6",
- "head",
- "header",
- "headers",
- "height",
- "hgroup",
- "hidden",
- "high",
- "hr",
- "href",
- "hreflang",
- "html",
- "http-equiv",
- "i",
- "icon",
- "id",
- "iframe",
- "image",
- "img",
- "inert",
- "input",
- "ins",
- "isindex",
- "ismap",
- "itemid",
- "itemprop",
- "itemref",
- "itemscope",
- "itemtype",
- "kbd",
- "keygen",
- "keytype",
- "kind",
- "label",
- "label",
- "lang",
- "legend",
- "li",
- "link",
- "list",
- "listing",
- "loop",
- "low",
- "malignmark",
- "manifest",
- "map",
- "mark",
- "marquee",
- "math",
- "max",
- "maxlength",
- "media",
- "mediagroup",
- "menu",
- "meta",
- "meter",
- "method",
- "mglyph",
- "mi",
- "min",
- "mn",
- "mo",
- "ms",
- "mtext",
- "multiple",
- "muted",
- "name",
- "nav",
- "nobr",
- "noembed",
- "noframes",
- "noscript",
- "novalidate",
- "object",
- "ol",
- "onabort",
- "onafterprint",
- "onbeforeprint",
- "onbeforeunload",
- "onblur",
- "oncancel",
- "oncanplay",
- "oncanplaythrough",
- "onchange",
- "onclick",
- "onclose",
- "oncontextmenu",
- "oncuechange",
- "ondblclick",
- "ondrag",
- "ondragend",
- "ondragenter",
- "ondragleave",
- "ondragover",
- "ondragstart",
- "ondrop",
- "ondurationchange",
- "onemptied",
- "onended",
- "onerror",
- "onfocus",
- "onhashchange",
- "oninput",
- "oninvalid",
- "onkeydown",
- "onkeypress",
- "onkeyup",
- "onload",
- "onloadeddata",
- "onloadedmetadata",
- "onloadstart",
- "onmessage",
- "onmousedown",
- "onmousemove",
- "onmouseout",
- "onmouseover",
- "onmouseup",
- "onmousewheel",
- "onoffline",
- "ononline",
- "onpagehide",
- "onpageshow",
- "onpause",
- "onplay",
- "onplaying",
- "onpopstate",
- "onprogress",
- "onratechange",
- "onreset",
- "onresize",
- "onscroll",
- "onseeked",
- "onseeking",
- "onselect",
- "onshow",
- "onstalled",
- "onstorage",
- "onsubmit",
- "onsuspend",
- "ontimeupdate",
- "onunload",
- "onvolumechange",
- "onwaiting",
- "open",
- "optgroup",
- "optimum",
- "option",
- "output",
- "p",
- "param",
- "pattern",
- "ping",
- "placeholder",
- "plaintext",
- "poster",
- "pre",
- "preload",
- "progress",
- "prompt",
- "public",
- "q",
- "radiogroup",
- "readonly",
- "rel",
- "required",
- "reversed",
- "rows",
- "rowspan",
- "rp",
- "rt",
- "ruby",
- "s",
- "samp",
- "sandbox",
- "scope",
- "scoped",
- "script",
- "seamless",
- "section",
- "select",
- "selected",
- "shape",
- "size",
- "sizes",
- "small",
- "source",
- "spacer",
- "span",
- "span",
- "spellcheck",
- "src",
- "srcdoc",
- "srclang",
- "start",
- "step",
- "strike",
- "strong",
- "style",
- "style",
- "sub",
- "summary",
- "sup",
- "svg",
- "system",
- "tabindex",
- "table",
- "target",
- "tbody",
- "td",
- "textarea",
- "tfoot",
- "th",
- "thead",
- "time",
- "title",
- "title",
- "tr",
- "track",
- "translate",
- "tt",
- "type",
- "typemustmatch",
- "u",
- "ul",
- "usemap",
- "value",
- "var",
- "video",
- "wbr",
- "width",
- "wrap",
- "xmp",
-}
diff --git a/libgo/go/exp/html/const.go b/libgo/go/exp/html/const.go
deleted file mode 100644
index d7cc8bb9a99..00000000000
--- a/libgo/go/exp/html/const.go
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package html
-
-// Section 12.2.3.2 of the HTML5 specification says "The following elements
-// have varying levels of special parsing rules".
-// http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#the-stack-of-open-elements
-var isSpecialElementMap = map[string]bool{
- "address": true,
- "applet": true,
- "area": true,
- "article": true,
- "aside": true,
- "base": true,
- "basefont": true,
- "bgsound": true,
- "blockquote": true,
- "body": true,
- "br": true,
- "button": true,
- "caption": true,
- "center": true,
- "col": true,
- "colgroup": true,
- "command": true,
- "dd": true,
- "details": true,
- "dir": true,
- "div": true,
- "dl": true,
- "dt": true,
- "embed": true,
- "fieldset": true,
- "figcaption": true,
- "figure": true,
- "footer": true,
- "form": true,
- "frame": true,
- "frameset": true,
- "h1": true,
- "h2": true,
- "h3": true,
- "h4": true,
- "h5": true,
- "h6": true,
- "head": true,
- "header": true,
- "hgroup": true,
- "hr": true,
- "html": true,
- "iframe": true,
- "img": true,
- "input": true,
- "isindex": true,
- "li": true,
- "link": true,
- "listing": true,
- "marquee": true,
- "menu": true,
- "meta": true,
- "nav": true,
- "noembed": true,
- "noframes": true,
- "noscript": true,
- "object": true,
- "ol": true,
- "p": true,
- "param": true,
- "plaintext": true,
- "pre": true,
- "script": true,
- "section": true,
- "select": true,
- "style": true,
- "summary": true,
- "table": true,
- "tbody": true,
- "td": true,
- "textarea": true,
- "tfoot": true,
- "th": true,
- "thead": true,
- "title": true,
- "tr": true,
- "ul": true,
- "wbr": true,
- "xmp": true,
-}
-
-func isSpecialElement(element *Node) bool {
- switch element.Namespace {
- case "", "html":
- return isSpecialElementMap[element.Data]
- case "svg":
- return element.Data == "foreignObject"
- }
- return false
-}
diff --git a/libgo/go/exp/html/doc.go b/libgo/go/exp/html/doc.go
deleted file mode 100644
index fac0f54e78a..00000000000
--- a/libgo/go/exp/html/doc.go
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
-Package html implements an HTML5-compliant tokenizer and parser.
-
-Tokenization is done by creating a Tokenizer for an io.Reader r. It is the
-caller's responsibility to ensure that r provides UTF-8 encoded HTML.
-
- z := html.NewTokenizer(r)
-
-Given a Tokenizer z, the HTML is tokenized by repeatedly calling z.Next(),
-which parses the next token and returns its type, or an error:
-
- for {
- tt := z.Next()
- if tt == html.ErrorToken {
- // ...
- return ...
- }
- // Process the current token.
- }
-
-There are two APIs for retrieving the current token. The high-level API is to
-call Token; the low-level API is to call Text or TagName / TagAttr. Both APIs
-allow optionally calling Raw after Next but before Token, Text, TagName, or
-TagAttr. In EBNF notation, the valid call sequence per token is:
-
- Next {Raw} [ Token | Text | TagName {TagAttr} ]
-
-Token returns an independent data structure that completely describes a token.
-Entities (such as "<") are unescaped, tag names and attribute keys are
-lower-cased, and attributes are collected into a []Attribute. For example:
-
- for {
- if z.Next() == html.ErrorToken {
- // Returning io.EOF indicates success.
- return z.Err()
- }
- emitToken(z.Token())
- }
-
-The low-level API performs fewer allocations and copies, but the contents of
-the []byte values returned by Text, TagName and TagAttr may change on the next
-call to Next. For example, to extract an HTML page's anchor text:
-
- depth := 0
- for {
- tt := z.Next()
- switch tt {
- case ErrorToken:
- return z.Err()
- case TextToken:
- if depth > 0 {
- // emitBytes should copy the []byte it receives,
- // if it doesn't process it immediately.
- emitBytes(z.Text())
- }
- case StartTagToken, EndTagToken:
- tn, _ := z.TagName()
- if len(tn) == 1 && tn[0] == 'a' {
- if tt == StartTagToken {
- depth++
- } else {
- depth--
- }
- }
- }
- }
-
-Parsing is done by calling Parse with an io.Reader, which returns the root of
-the parse tree (the document element) as a *Node. It is the caller's
-responsibility to ensure that the Reader provides UTF-8 encoded HTML. For
-example, to process each anchor node in depth-first order:
-
- doc, err := html.Parse(r)
- if err != nil {
- // ...
- }
- var f func(*html.Node)
- f = func(n *html.Node) {
- if n.Type == html.ElementNode && n.Data == "a" {
- // Do something with n...
- }
- for c := n.FirstChild; c != nil; c = c.NextSibling {
- f(c)
- }
- }
- f(doc)
-
-The relevant specifications include:
-http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html and
-http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html
-*/
-package html
-
-// The tokenization algorithm implemented by this package is not a line-by-line
-// transliteration of the relatively verbose state-machine in the WHATWG
-// specification. A more direct approach is used instead, where the program
-// counter implies the state, such as whether it is tokenizing a tag or a text
-// node. Specification compliance is verified by checking expected and actual
-// outputs over a test suite rather than aiming for algorithmic fidelity.
-
-// TODO(nigeltao): Does a DOM API belong in this package or a separate one?
-// TODO(nigeltao): How does parsing interact with a JavaScript engine?
diff --git a/libgo/go/exp/html/doctype.go b/libgo/go/exp/html/doctype.go
deleted file mode 100644
index c484e5a94fb..00000000000
--- a/libgo/go/exp/html/doctype.go
+++ /dev/null
@@ -1,156 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package html
-
-import (
- "strings"
-)
-
-// parseDoctype parses the data from a DoctypeToken into a name,
-// public identifier, and system identifier. It returns a Node whose Type
-// is DoctypeNode, whose Data is the name, and which has attributes
-// named "system" and "public" for the two identifiers if they were present.
-// quirks is whether the document should be parsed in "quirks mode".
-func parseDoctype(s string) (n *Node, quirks bool) {
- n = &Node{Type: DoctypeNode}
-
- // Find the name.
- space := strings.IndexAny(s, whitespace)
- if space == -1 {
- space = len(s)
- }
- n.Data = s[:space]
- // The comparison to "html" is case-sensitive.
- if n.Data != "html" {
- quirks = true
- }
- n.Data = strings.ToLower(n.Data)
- s = strings.TrimLeft(s[space:], whitespace)
-
- if len(s) < 6 {
- // It can't start with "PUBLIC" or "SYSTEM".
- // Ignore the rest of the string.
- return n, quirks || s != ""
- }
-
- key := strings.ToLower(s[:6])
- s = s[6:]
- for key == "public" || key == "system" {
- s = strings.TrimLeft(s, whitespace)
- if s == "" {
- break
- }
- quote := s[0]
- if quote != '"' && quote != '\'' {
- break
- }
- s = s[1:]
- q := strings.IndexRune(s, rune(quote))
- var id string
- if q == -1 {
- id = s
- s = ""
- } else {
- id = s[:q]
- s = s[q+1:]
- }
- n.Attr = append(n.Attr, Attribute{Key: key, Val: id})
- if key == "public" {
- key = "system"
- } else {
- key = ""
- }
- }
-
- if key != "" || s != "" {
- quirks = true
- } else if len(n.Attr) > 0 {
- if n.Attr[0].Key == "public" {
- public := strings.ToLower(n.Attr[0].Val)
- switch public {
- case "-//w3o//dtd w3 html strict 3.0//en//", "-/w3d/dtd html 4.0 transitional/en", "html":
- quirks = true
- default:
- for _, q := range quirkyIDs {
- if strings.HasPrefix(public, q) {
- quirks = true
- break
- }
- }
- }
- // The following two public IDs only cause quirks mode if there is no system ID.
- if len(n.Attr) == 1 && (strings.HasPrefix(public, "-//w3c//dtd html 4.01 frameset//") ||
- strings.HasPrefix(public, "-//w3c//dtd html 4.01 transitional//")) {
- quirks = true
- }
- }
- if lastAttr := n.Attr[len(n.Attr)-1]; lastAttr.Key == "system" &&
- strings.ToLower(lastAttr.Val) == "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd" {
- quirks = true
- }
- }
-
- return n, quirks
-}
-
-// quirkyIDs is a list of public doctype identifiers that cause a document
-// to be interpreted in quirks mode. The identifiers should be in lower case.
-var quirkyIDs = []string{
- "+//silmaril//dtd html pro v0r11 19970101//",
- "-//advasoft ltd//dtd html 3.0 aswedit + extensions//",
- "-//as//dtd html 3.0 aswedit + extensions//",
- "-//ietf//dtd html 2.0 level 1//",
- "-//ietf//dtd html 2.0 level 2//",
- "-//ietf//dtd html 2.0 strict level 1//",
- "-//ietf//dtd html 2.0 strict level 2//",
- "-//ietf//dtd html 2.0 strict//",
- "-//ietf//dtd html 2.0//",
- "-//ietf//dtd html 2.1e//",
- "-//ietf//dtd html 3.0//",
- "-//ietf//dtd html 3.2 final//",
- "-//ietf//dtd html 3.2//",
- "-//ietf//dtd html 3//",
- "-//ietf//dtd html level 0//",
- "-//ietf//dtd html level 1//",
- "-//ietf//dtd html level 2//",
- "-//ietf//dtd html level 3//",
- "-//ietf//dtd html strict level 0//",
- "-//ietf//dtd html strict level 1//",
- "-//ietf//dtd html strict level 2//",
- "-//ietf//dtd html strict level 3//",
- "-//ietf//dtd html strict//",
- "-//ietf//dtd html//",
- "-//metrius//dtd metrius presentational//",
- "-//microsoft//dtd internet explorer 2.0 html strict//",
- "-//microsoft//dtd internet explorer 2.0 html//",
- "-//microsoft//dtd internet explorer 2.0 tables//",
- "-//microsoft//dtd internet explorer 3.0 html strict//",
- "-//microsoft//dtd internet explorer 3.0 html//",
- "-//microsoft//dtd internet explorer 3.0 tables//",
- "-//netscape comm. corp.//dtd html//",
- "-//netscape comm. corp.//dtd strict html//",
- "-//o'reilly and associates//dtd html 2.0//",
- "-//o'reilly and associates//dtd html extended 1.0//",
- "-//o'reilly and associates//dtd html extended relaxed 1.0//",
- "-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//",
- "-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//",
- "-//spyglass//dtd html 2.0 extended//",
- "-//sq//dtd html 2.0 hotmetal + extensions//",
- "-//sun microsystems corp.//dtd hotjava html//",
- "-//sun microsystems corp.//dtd hotjava strict html//",
- "-//w3c//dtd html 3 1995-03-24//",
- "-//w3c//dtd html 3.2 draft//",
- "-//w3c//dtd html 3.2 final//",
- "-//w3c//dtd html 3.2//",
- "-//w3c//dtd html 3.2s draft//",
- "-//w3c//dtd html 4.0 frameset//",
- "-//w3c//dtd html 4.0 transitional//",
- "-//w3c//dtd html experimental 19960712//",
- "-//w3c//dtd html experimental 970421//",
- "-//w3c//dtd w3 html//",
- "-//w3o//dtd w3 html 3.0//",
- "-//webtechs//dtd mozilla html 2.0//",
- "-//webtechs//dtd mozilla html//",
-}
diff --git a/libgo/go/exp/html/entity.go b/libgo/go/exp/html/entity.go
deleted file mode 100644
index af8a007ed04..00000000000
--- a/libgo/go/exp/html/entity.go
+++ /dev/null
@@ -1,2253 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package html
-
-// All entities that do not end with ';' are 6 or fewer bytes long.
-const longestEntityWithoutSemicolon = 6
-
-// entity is a map from HTML entity names to their values. The semicolon matters:
-// http://www.whatwg.org/specs/web-apps/current-work/multipage/named-character-references.html
-// lists both "amp" and "amp;" as two separate entries.
-//
-// Note that the HTML5 list is larger than the HTML4 list at
-// http://www.w3.org/TR/html4/sgml/entities.html
-var entity = map[string]rune{
- "AElig;": '\U000000C6',
- "AMP;": '\U00000026',
- "Aacute;": '\U000000C1',
- "Abreve;": '\U00000102',
- "Acirc;": '\U000000C2',
- "Acy;": '\U00000410',
- "Afr;": '\U0001D504',
- "Agrave;": '\U000000C0',
- "Alpha;": '\U00000391',
- "Amacr;": '\U00000100',
- "And;": '\U00002A53',
- "Aogon;": '\U00000104',
- "Aopf;": '\U0001D538',
- "ApplyFunction;": '\U00002061',
- "Aring;": '\U000000C5',
- "Ascr;": '\U0001D49C',
- "Assign;": '\U00002254',
- "Atilde;": '\U000000C3',
- "Auml;": '\U000000C4',
- "Backslash;": '\U00002216',
- "Barv;": '\U00002AE7',
- "Barwed;": '\U00002306',
- "Bcy;": '\U00000411',
- "Because;": '\U00002235',
- "Bernoullis;": '\U0000212C',
- "Beta;": '\U00000392',
- "Bfr;": '\U0001D505',
- "Bopf;": '\U0001D539',
- "Breve;": '\U000002D8',
- "Bscr;": '\U0000212C',
- "Bumpeq;": '\U0000224E',
- "CHcy;": '\U00000427',
- "COPY;": '\U000000A9',
- "Cacute;": '\U00000106',
- "Cap;": '\U000022D2',
- "CapitalDifferentialD;": '\U00002145',
- "Cayleys;": '\U0000212D',
- "Ccaron;": '\U0000010C',
- "Ccedil;": '\U000000C7',
- "Ccirc;": '\U00000108',
- "Cconint;": '\U00002230',
- "Cdot;": '\U0000010A',
- "Cedilla;": '\U000000B8',
- "CenterDot;": '\U000000B7',
- "Cfr;": '\U0000212D',
- "Chi;": '\U000003A7',
- "CircleDot;": '\U00002299',
- "CircleMinus;": '\U00002296',
- "CirclePlus;": '\U00002295',
- "CircleTimes;": '\U00002297',
- "ClockwiseContourIntegral;": '\U00002232',
- "CloseCurlyDoubleQuote;": '\U0000201D',
- "CloseCurlyQuote;": '\U00002019',
- "Colon;": '\U00002237',
- "Colone;": '\U00002A74',
- "Congruent;": '\U00002261',
- "Conint;": '\U0000222F',
- "ContourIntegral;": '\U0000222E',
- "Copf;": '\U00002102',
- "Coproduct;": '\U00002210',
- "CounterClockwiseContourIntegral;": '\U00002233',
- "Cross;": '\U00002A2F',
- "Cscr;": '\U0001D49E',
- "Cup;": '\U000022D3',
- "CupCap;": '\U0000224D',
- "DD;": '\U00002145',
- "DDotrahd;": '\U00002911',
- "DJcy;": '\U00000402',
- "DScy;": '\U00000405',
- "DZcy;": '\U0000040F',
- "Dagger;": '\U00002021',
- "Darr;": '\U000021A1',
- "Dashv;": '\U00002AE4',
- "Dcaron;": '\U0000010E',
- "Dcy;": '\U00000414',
- "Del;": '\U00002207',
- "Delta;": '\U00000394',
- "Dfr;": '\U0001D507',
- "DiacriticalAcute;": '\U000000B4',
- "DiacriticalDot;": '\U000002D9',
- "DiacriticalDoubleAcute;": '\U000002DD',
- "DiacriticalGrave;": '\U00000060',
- "DiacriticalTilde;": '\U000002DC',
- "Diamond;": '\U000022C4',
- "DifferentialD;": '\U00002146',
- "Dopf;": '\U0001D53B',
- "Dot;": '\U000000A8',
- "DotDot;": '\U000020DC',
- "DotEqual;": '\U00002250',
- "DoubleContourIntegral;": '\U0000222F',
- "DoubleDot;": '\U000000A8',
- "DoubleDownArrow;": '\U000021D3',
- "DoubleLeftArrow;": '\U000021D0',
- "DoubleLeftRightArrow;": '\U000021D4',
- "DoubleLeftTee;": '\U00002AE4',
- "DoubleLongLeftArrow;": '\U000027F8',
- "DoubleLongLeftRightArrow;": '\U000027FA',
- "DoubleLongRightArrow;": '\U000027F9',
- "DoubleRightArrow;": '\U000021D2',
- "DoubleRightTee;": '\U000022A8',
- "DoubleUpArrow;": '\U000021D1',
- "DoubleUpDownArrow;": '\U000021D5',
- "DoubleVerticalBar;": '\U00002225',
- "DownArrow;": '\U00002193',
- "DownArrowBar;": '\U00002913',
- "DownArrowUpArrow;": '\U000021F5',
- "DownBreve;": '\U00000311',
- "DownLeftRightVector;": '\U00002950',
- "DownLeftTeeVector;": '\U0000295E',
- "DownLeftVector;": '\U000021BD',
- "DownLeftVectorBar;": '\U00002956',
- "DownRightTeeVector;": '\U0000295F',
- "DownRightVector;": '\U000021C1',
- "DownRightVectorBar;": '\U00002957',
- "DownTee;": '\U000022A4',
- "DownTeeArrow;": '\U000021A7',
- "Downarrow;": '\U000021D3',
- "Dscr;": '\U0001D49F',
- "Dstrok;": '\U00000110',
- "ENG;": '\U0000014A',
- "ETH;": '\U000000D0',
- "Eacute;": '\U000000C9',
- "Ecaron;": '\U0000011A',
- "Ecirc;": '\U000000CA',
- "Ecy;": '\U0000042D',
- "Edot;": '\U00000116',
- "Efr;": '\U0001D508',
- "Egrave;": '\U000000C8',
- "Element;": '\U00002208',
- "Emacr;": '\U00000112',
- "EmptySmallSquare;": '\U000025FB',
- "EmptyVerySmallSquare;": '\U000025AB',
- "Eogon;": '\U00000118',
- "Eopf;": '\U0001D53C',
- "Epsilon;": '\U00000395',
- "Equal;": '\U00002A75',
- "EqualTilde;": '\U00002242',
- "Equilibrium;": '\U000021CC',
- "Escr;": '\U00002130',
- "Esim;": '\U00002A73',
- "Eta;": '\U00000397',
- "Euml;": '\U000000CB',
- "Exists;": '\U00002203',
- "ExponentialE;": '\U00002147',
- "Fcy;": '\U00000424',
- "Ffr;": '\U0001D509',
- "FilledSmallSquare;": '\U000025FC',
- "FilledVerySmallSquare;": '\U000025AA',
- "Fopf;": '\U0001D53D',
- "ForAll;": '\U00002200',
- "Fouriertrf;": '\U00002131',
- "Fscr;": '\U00002131',
- "GJcy;": '\U00000403',
- "GT;": '\U0000003E',
- "Gamma;": '\U00000393',
- "Gammad;": '\U000003DC',
- "Gbreve;": '\U0000011E',
- "Gcedil;": '\U00000122',
- "Gcirc;": '\U0000011C',
- "Gcy;": '\U00000413',
- "Gdot;": '\U00000120',
- "Gfr;": '\U0001D50A',
- "Gg;": '\U000022D9',
- "Gopf;": '\U0001D53E',
- "GreaterEqual;": '\U00002265',
- "GreaterEqualLess;": '\U000022DB',
- "GreaterFullEqual;": '\U00002267',
- "GreaterGreater;": '\U00002AA2',
- "GreaterLess;": '\U00002277',
- "GreaterSlantEqual;": '\U00002A7E',
- "GreaterTilde;": '\U00002273',
- "Gscr;": '\U0001D4A2',
- "Gt;": '\U0000226B',
- "HARDcy;": '\U0000042A',
- "Hacek;": '\U000002C7',
- "Hat;": '\U0000005E',
- "Hcirc;": '\U00000124',
- "Hfr;": '\U0000210C',
- "HilbertSpace;": '\U0000210B',
- "Hopf;": '\U0000210D',
- "HorizontalLine;": '\U00002500',
- "Hscr;": '\U0000210B',
- "Hstrok;": '\U00000126',
- "HumpDownHump;": '\U0000224E',
- "HumpEqual;": '\U0000224F',
- "IEcy;": '\U00000415',
- "IJlig;": '\U00000132',
- "IOcy;": '\U00000401',
- "Iacute;": '\U000000CD',
- "Icirc;": '\U000000CE',
- "Icy;": '\U00000418',
- "Idot;": '\U00000130',
- "Ifr;": '\U00002111',
- "Igrave;": '\U000000CC',
- "Im;": '\U00002111',
- "Imacr;": '\U0000012A',
- "ImaginaryI;": '\U00002148',
- "Implies;": '\U000021D2',
- "Int;": '\U0000222C',
- "Integral;": '\U0000222B',
- "Intersection;": '\U000022C2',
- "InvisibleComma;": '\U00002063',
- "InvisibleTimes;": '\U00002062',
- "Iogon;": '\U0000012E',
- "Iopf;": '\U0001D540',
- "Iota;": '\U00000399',
- "Iscr;": '\U00002110',
- "Itilde;": '\U00000128',
- "Iukcy;": '\U00000406',
- "Iuml;": '\U000000CF',
- "Jcirc;": '\U00000134',
- "Jcy;": '\U00000419',
- "Jfr;": '\U0001D50D',
- "Jopf;": '\U0001D541',
- "Jscr;": '\U0001D4A5',
- "Jsercy;": '\U00000408',
- "Jukcy;": '\U00000404',
- "KHcy;": '\U00000425',
- "KJcy;": '\U0000040C',
- "Kappa;": '\U0000039A',
- "Kcedil;": '\U00000136',
- "Kcy;": '\U0000041A',
- "Kfr;": '\U0001D50E',
- "Kopf;": '\U0001D542',
- "Kscr;": '\U0001D4A6',
- "LJcy;": '\U00000409',
- "LT;": '\U0000003C',
- "Lacute;": '\U00000139',
- "Lambda;": '\U0000039B',
- "Lang;": '\U000027EA',
- "Laplacetrf;": '\U00002112',
- "Larr;": '\U0000219E',
- "Lcaron;": '\U0000013D',
- "Lcedil;": '\U0000013B',
- "Lcy;": '\U0000041B',
- "LeftAngleBracket;": '\U000027E8',
- "LeftArrow;": '\U00002190',
- "LeftArrowBar;": '\U000021E4',
- "LeftArrowRightArrow;": '\U000021C6',
- "LeftCeiling;": '\U00002308',
- "LeftDoubleBracket;": '\U000027E6',
- "LeftDownTeeVector;": '\U00002961',
- "LeftDownVector;": '\U000021C3',
- "LeftDownVectorBar;": '\U00002959',
- "LeftFloor;": '\U0000230A',
- "LeftRightArrow;": '\U00002194',
- "LeftRightVector;": '\U0000294E',
- "LeftTee;": '\U000022A3',
- "LeftTeeArrow;": '\U000021A4',
- "LeftTeeVector;": '\U0000295A',
- "LeftTriangle;": '\U000022B2',
- "LeftTriangleBar;": '\U000029CF',
- "LeftTriangleEqual;": '\U000022B4',
- "LeftUpDownVector;": '\U00002951',
- "LeftUpTeeVector;": '\U00002960',
- "LeftUpVector;": '\U000021BF',
- "LeftUpVectorBar;": '\U00002958',
- "LeftVector;": '\U000021BC',
- "LeftVectorBar;": '\U00002952',
- "Leftarrow;": '\U000021D0',
- "Leftrightarrow;": '\U000021D4',
- "LessEqualGreater;": '\U000022DA',
- "LessFullEqual;": '\U00002266',
- "LessGreater;": '\U00002276',
- "LessLess;": '\U00002AA1',
- "LessSlantEqual;": '\U00002A7D',
- "LessTilde;": '\U00002272',
- "Lfr;": '\U0001D50F',
- "Ll;": '\U000022D8',
- "Lleftarrow;": '\U000021DA',
- "Lmidot;": '\U0000013F',
- "LongLeftArrow;": '\U000027F5',
- "LongLeftRightArrow;": '\U000027F7',
- "LongRightArrow;": '\U000027F6',
- "Longleftarrow;": '\U000027F8',
- "Longleftrightarrow;": '\U000027FA',
- "Longrightarrow;": '\U000027F9',
- "Lopf;": '\U0001D543',
- "LowerLeftArrow;": '\U00002199',
- "LowerRightArrow;": '\U00002198',
- "Lscr;": '\U00002112',
- "Lsh;": '\U000021B0',
- "Lstrok;": '\U00000141',
- "Lt;": '\U0000226A',
- "Map;": '\U00002905',
- "Mcy;": '\U0000041C',
- "MediumSpace;": '\U0000205F',
- "Mellintrf;": '\U00002133',
- "Mfr;": '\U0001D510',
- "MinusPlus;": '\U00002213',
- "Mopf;": '\U0001D544',
- "Mscr;": '\U00002133',
- "Mu;": '\U0000039C',
- "NJcy;": '\U0000040A',
- "Nacute;": '\U00000143',
- "Ncaron;": '\U00000147',
- "Ncedil;": '\U00000145',
- "Ncy;": '\U0000041D',
- "NegativeMediumSpace;": '\U0000200B',
- "NegativeThickSpace;": '\U0000200B',
- "NegativeThinSpace;": '\U0000200B',
- "NegativeVeryThinSpace;": '\U0000200B',
- "NestedGreaterGreater;": '\U0000226B',
- "NestedLessLess;": '\U0000226A',
- "NewLine;": '\U0000000A',
- "Nfr;": '\U0001D511',
- "NoBreak;": '\U00002060',
- "NonBreakingSpace;": '\U000000A0',
- "Nopf;": '\U00002115',
- "Not;": '\U00002AEC',
- "NotCongruent;": '\U00002262',
- "NotCupCap;": '\U0000226D',
- "NotDoubleVerticalBar;": '\U00002226',
- "NotElement;": '\U00002209',
- "NotEqual;": '\U00002260',
- "NotExists;": '\U00002204',
- "NotGreater;": '\U0000226F',
- "NotGreaterEqual;": '\U00002271',
- "NotGreaterLess;": '\U00002279',
- "NotGreaterTilde;": '\U00002275',
- "NotLeftTriangle;": '\U000022EA',
- "NotLeftTriangleEqual;": '\U000022EC',
- "NotLess;": '\U0000226E',
- "NotLessEqual;": '\U00002270',
- "NotLessGreater;": '\U00002278',
- "NotLessTilde;": '\U00002274',
- "NotPrecedes;": '\U00002280',
- "NotPrecedesSlantEqual;": '\U000022E0',
- "NotReverseElement;": '\U0000220C',
- "NotRightTriangle;": '\U000022EB',
- "NotRightTriangleEqual;": '\U000022ED',
- "NotSquareSubsetEqual;": '\U000022E2',
- "NotSquareSupersetEqual;": '\U000022E3',
- "NotSubsetEqual;": '\U00002288',
- "NotSucceeds;": '\U00002281',
- "NotSucceedsSlantEqual;": '\U000022E1',
- "NotSupersetEqual;": '\U00002289',
- "NotTilde;": '\U00002241',
- "NotTildeEqual;": '\U00002244',
- "NotTildeFullEqual;": '\U00002247',
- "NotTildeTilde;": '\U00002249',
- "NotVerticalBar;": '\U00002224',
- "Nscr;": '\U0001D4A9',
- "Ntilde;": '\U000000D1',
- "Nu;": '\U0000039D',
- "OElig;": '\U00000152',
- "Oacute;": '\U000000D3',
- "Ocirc;": '\U000000D4',
- "Ocy;": '\U0000041E',
- "Odblac;": '\U00000150',
- "Ofr;": '\U0001D512',
- "Ograve;": '\U000000D2',
- "Omacr;": '\U0000014C',
- "Omega;": '\U000003A9',
- "Omicron;": '\U0000039F',
- "Oopf;": '\U0001D546',
- "OpenCurlyDoubleQuote;": '\U0000201C',
- "OpenCurlyQuote;": '\U00002018',
- "Or;": '\U00002A54',
- "Oscr;": '\U0001D4AA',
- "Oslash;": '\U000000D8',
- "Otilde;": '\U000000D5',
- "Otimes;": '\U00002A37',
- "Ouml;": '\U000000D6',
- "OverBar;": '\U0000203E',
- "OverBrace;": '\U000023DE',
- "OverBracket;": '\U000023B4',
- "OverParenthesis;": '\U000023DC',
- "PartialD;": '\U00002202',
- "Pcy;": '\U0000041F',
- "Pfr;": '\U0001D513',
- "Phi;": '\U000003A6',
- "Pi;": '\U000003A0',
- "PlusMinus;": '\U000000B1',
- "Poincareplane;": '\U0000210C',
- "Popf;": '\U00002119',
- "Pr;": '\U00002ABB',
- "Precedes;": '\U0000227A',
- "PrecedesEqual;": '\U00002AAF',
- "PrecedesSlantEqual;": '\U0000227C',
- "PrecedesTilde;": '\U0000227E',
- "Prime;": '\U00002033',
- "Product;": '\U0000220F',
- "Proportion;": '\U00002237',
- "Proportional;": '\U0000221D',
- "Pscr;": '\U0001D4AB',
- "Psi;": '\U000003A8',
- "QUOT;": '\U00000022',
- "Qfr;": '\U0001D514',
- "Qopf;": '\U0000211A',
- "Qscr;": '\U0001D4AC',
- "RBarr;": '\U00002910',
- "REG;": '\U000000AE',
- "Racute;": '\U00000154',
- "Rang;": '\U000027EB',
- "Rarr;": '\U000021A0',
- "Rarrtl;": '\U00002916',
- "Rcaron;": '\U00000158',
- "Rcedil;": '\U00000156',
- "Rcy;": '\U00000420',
- "Re;": '\U0000211C',
- "ReverseElement;": '\U0000220B',
- "ReverseEquilibrium;": '\U000021CB',
- "ReverseUpEquilibrium;": '\U0000296F',
- "Rfr;": '\U0000211C',
- "Rho;": '\U000003A1',
- "RightAngleBracket;": '\U000027E9',
- "RightArrow;": '\U00002192',
- "RightArrowBar;": '\U000021E5',
- "RightArrowLeftArrow;": '\U000021C4',
- "RightCeiling;": '\U00002309',
- "RightDoubleBracket;": '\U000027E7',
- "RightDownTeeVector;": '\U0000295D',
- "RightDownVector;": '\U000021C2',
- "RightDownVectorBar;": '\U00002955',
- "RightFloor;": '\U0000230B',
- "RightTee;": '\U000022A2',
- "RightTeeArrow;": '\U000021A6',
- "RightTeeVector;": '\U0000295B',
- "RightTriangle;": '\U000022B3',
- "RightTriangleBar;": '\U000029D0',
- "RightTriangleEqual;": '\U000022B5',
- "RightUpDownVector;": '\U0000294F',
- "RightUpTeeVector;": '\U0000295C',
- "RightUpVector;": '\U000021BE',
- "RightUpVectorBar;": '\U00002954',
- "RightVector;": '\U000021C0',
- "RightVectorBar;": '\U00002953',
- "Rightarrow;": '\U000021D2',
- "Ropf;": '\U0000211D',
- "RoundImplies;": '\U00002970',
- "Rrightarrow;": '\U000021DB',
- "Rscr;": '\U0000211B',
- "Rsh;": '\U000021B1',
- "RuleDelayed;": '\U000029F4',
- "SHCHcy;": '\U00000429',
- "SHcy;": '\U00000428',
- "SOFTcy;": '\U0000042C',
- "Sacute;": '\U0000015A',
- "Sc;": '\U00002ABC',
- "Scaron;": '\U00000160',
- "Scedil;": '\U0000015E',
- "Scirc;": '\U0000015C',
- "Scy;": '\U00000421',
- "Sfr;": '\U0001D516',
- "ShortDownArrow;": '\U00002193',
- "ShortLeftArrow;": '\U00002190',
- "ShortRightArrow;": '\U00002192',
- "ShortUpArrow;": '\U00002191',
- "Sigma;": '\U000003A3',
- "SmallCircle;": '\U00002218',
- "Sopf;": '\U0001D54A',
- "Sqrt;": '\U0000221A',
- "Square;": '\U000025A1',
- "SquareIntersection;": '\U00002293',
- "SquareSubset;": '\U0000228F',
- "SquareSubsetEqual;": '\U00002291',
- "SquareSuperset;": '\U00002290',
- "SquareSupersetEqual;": '\U00002292',
- "SquareUnion;": '\U00002294',
- "Sscr;": '\U0001D4AE',
- "Star;": '\U000022C6',
- "Sub;": '\U000022D0',
- "Subset;": '\U000022D0',
- "SubsetEqual;": '\U00002286',
- "Succeeds;": '\U0000227B',
- "SucceedsEqual;": '\U00002AB0',
- "SucceedsSlantEqual;": '\U0000227D',
- "SucceedsTilde;": '\U0000227F',
- "SuchThat;": '\U0000220B',
- "Sum;": '\U00002211',
- "Sup;": '\U000022D1',
- "Superset;": '\U00002283',
- "SupersetEqual;": '\U00002287',
- "Supset;": '\U000022D1',
- "THORN;": '\U000000DE',
- "TRADE;": '\U00002122',
- "TSHcy;": '\U0000040B',
- "TScy;": '\U00000426',
- "Tab;": '\U00000009',
- "Tau;": '\U000003A4',
- "Tcaron;": '\U00000164',
- "Tcedil;": '\U00000162',
- "Tcy;": '\U00000422',
- "Tfr;": '\U0001D517',
- "Therefore;": '\U00002234',
- "Theta;": '\U00000398',
- "ThinSpace;": '\U00002009',
- "Tilde;": '\U0000223C',
- "TildeEqual;": '\U00002243',
- "TildeFullEqual;": '\U00002245',
- "TildeTilde;": '\U00002248',
- "Topf;": '\U0001D54B',
- "TripleDot;": '\U000020DB',
- "Tscr;": '\U0001D4AF',
- "Tstrok;": '\U00000166',
- "Uacute;": '\U000000DA',
- "Uarr;": '\U0000219F',
- "Uarrocir;": '\U00002949',
- "Ubrcy;": '\U0000040E',
- "Ubreve;": '\U0000016C',
- "Ucirc;": '\U000000DB',
- "Ucy;": '\U00000423',
- "Udblac;": '\U00000170',
- "Ufr;": '\U0001D518',
- "Ugrave;": '\U000000D9',
- "Umacr;": '\U0000016A',
- "UnderBar;": '\U0000005F',
- "UnderBrace;": '\U000023DF',
- "UnderBracket;": '\U000023B5',
- "UnderParenthesis;": '\U000023DD',
- "Union;": '\U000022C3',
- "UnionPlus;": '\U0000228E',
- "Uogon;": '\U00000172',
- "Uopf;": '\U0001D54C',
- "UpArrow;": '\U00002191',
- "UpArrowBar;": '\U00002912',
- "UpArrowDownArrow;": '\U000021C5',
- "UpDownArrow;": '\U00002195',
- "UpEquilibrium;": '\U0000296E',
- "UpTee;": '\U000022A5',
- "UpTeeArrow;": '\U000021A5',
- "Uparrow;": '\U000021D1',
- "Updownarrow;": '\U000021D5',
- "UpperLeftArrow;": '\U00002196',
- "UpperRightArrow;": '\U00002197',
- "Upsi;": '\U000003D2',
- "Upsilon;": '\U000003A5',
- "Uring;": '\U0000016E',
- "Uscr;": '\U0001D4B0',
- "Utilde;": '\U00000168',
- "Uuml;": '\U000000DC',
- "VDash;": '\U000022AB',
- "Vbar;": '\U00002AEB',
- "Vcy;": '\U00000412',
- "Vdash;": '\U000022A9',
- "Vdashl;": '\U00002AE6',
- "Vee;": '\U000022C1',
- "Verbar;": '\U00002016',
- "Vert;": '\U00002016',
- "VerticalBar;": '\U00002223',
- "VerticalLine;": '\U0000007C',
- "VerticalSeparator;": '\U00002758',
- "VerticalTilde;": '\U00002240',
- "VeryThinSpace;": '\U0000200A',
- "Vfr;": '\U0001D519',
- "Vopf;": '\U0001D54D',
- "Vscr;": '\U0001D4B1',
- "Vvdash;": '\U000022AA',
- "Wcirc;": '\U00000174',
- "Wedge;": '\U000022C0',
- "Wfr;": '\U0001D51A',
- "Wopf;": '\U0001D54E',
- "Wscr;": '\U0001D4B2',
- "Xfr;": '\U0001D51B',
- "Xi;": '\U0000039E',
- "Xopf;": '\U0001D54F',
- "Xscr;": '\U0001D4B3',
- "YAcy;": '\U0000042F',
- "YIcy;": '\U00000407',
- "YUcy;": '\U0000042E',
- "Yacute;": '\U000000DD',
- "Ycirc;": '\U00000176',
- "Ycy;": '\U0000042B',
- "Yfr;": '\U0001D51C',
- "Yopf;": '\U0001D550',
- "Yscr;": '\U0001D4B4',
- "Yuml;": '\U00000178',
- "ZHcy;": '\U00000416',
- "Zacute;": '\U00000179',
- "Zcaron;": '\U0000017D',
- "Zcy;": '\U00000417',
- "Zdot;": '\U0000017B',
- "ZeroWidthSpace;": '\U0000200B',
- "Zeta;": '\U00000396',
- "Zfr;": '\U00002128',
- "Zopf;": '\U00002124',
- "Zscr;": '\U0001D4B5',
- "aacute;": '\U000000E1',
- "abreve;": '\U00000103',
- "ac;": '\U0000223E',
- "acd;": '\U0000223F',
- "acirc;": '\U000000E2',
- "acute;": '\U000000B4',
- "acy;": '\U00000430',
- "aelig;": '\U000000E6',
- "af;": '\U00002061',
- "afr;": '\U0001D51E',
- "agrave;": '\U000000E0',
- "alefsym;": '\U00002135',
- "aleph;": '\U00002135',
- "alpha;": '\U000003B1',
- "amacr;": '\U00000101',
- "amalg;": '\U00002A3F',
- "amp;": '\U00000026',
- "and;": '\U00002227',
- "andand;": '\U00002A55',
- "andd;": '\U00002A5C',
- "andslope;": '\U00002A58',
- "andv;": '\U00002A5A',
- "ang;": '\U00002220',
- "ange;": '\U000029A4',
- "angle;": '\U00002220',
- "angmsd;": '\U00002221',
- "angmsdaa;": '\U000029A8',
- "angmsdab;": '\U000029A9',
- "angmsdac;": '\U000029AA',
- "angmsdad;": '\U000029AB',
- "angmsdae;": '\U000029AC',
- "angmsdaf;": '\U000029AD',
- "angmsdag;": '\U000029AE',
- "angmsdah;": '\U000029AF',
- "angrt;": '\U0000221F',
- "angrtvb;": '\U000022BE',
- "angrtvbd;": '\U0000299D',
- "angsph;": '\U00002222',
- "angst;": '\U000000C5',
- "angzarr;": '\U0000237C',
- "aogon;": '\U00000105',
- "aopf;": '\U0001D552',
- "ap;": '\U00002248',
- "apE;": '\U00002A70',
- "apacir;": '\U00002A6F',
- "ape;": '\U0000224A',
- "apid;": '\U0000224B',
- "apos;": '\U00000027',
- "approx;": '\U00002248',
- "approxeq;": '\U0000224A',
- "aring;": '\U000000E5',
- "ascr;": '\U0001D4B6',
- "ast;": '\U0000002A',
- "asymp;": '\U00002248',
- "asympeq;": '\U0000224D',
- "atilde;": '\U000000E3',
- "auml;": '\U000000E4',
- "awconint;": '\U00002233',
- "awint;": '\U00002A11',
- "bNot;": '\U00002AED',
- "backcong;": '\U0000224C',
- "backepsilon;": '\U000003F6',
- "backprime;": '\U00002035',
- "backsim;": '\U0000223D',
- "backsimeq;": '\U000022CD',
- "barvee;": '\U000022BD',
- "barwed;": '\U00002305',
- "barwedge;": '\U00002305',
- "bbrk;": '\U000023B5',
- "bbrktbrk;": '\U000023B6',
- "bcong;": '\U0000224C',
- "bcy;": '\U00000431',
- "bdquo;": '\U0000201E',
- "becaus;": '\U00002235',
- "because;": '\U00002235',
- "bemptyv;": '\U000029B0',
- "bepsi;": '\U000003F6',
- "bernou;": '\U0000212C',
- "beta;": '\U000003B2',
- "beth;": '\U00002136',
- "between;": '\U0000226C',
- "bfr;": '\U0001D51F',
- "bigcap;": '\U000022C2',
- "bigcirc;": '\U000025EF',
- "bigcup;": '\U000022C3',
- "bigodot;": '\U00002A00',
- "bigoplus;": '\U00002A01',
- "bigotimes;": '\U00002A02',
- "bigsqcup;": '\U00002A06',
- "bigstar;": '\U00002605',
- "bigtriangledown;": '\U000025BD',
- "bigtriangleup;": '\U000025B3',
- "biguplus;": '\U00002A04',
- "bigvee;": '\U000022C1',
- "bigwedge;": '\U000022C0',
- "bkarow;": '\U0000290D',
- "blacklozenge;": '\U000029EB',
- "blacksquare;": '\U000025AA',
- "blacktriangle;": '\U000025B4',
- "blacktriangledown;": '\U000025BE',
- "blacktriangleleft;": '\U000025C2',
- "blacktriangleright;": '\U000025B8',
- "blank;": '\U00002423',
- "blk12;": '\U00002592',
- "blk14;": '\U00002591',
- "blk34;": '\U00002593',
- "block;": '\U00002588',
- "bnot;": '\U00002310',
- "bopf;": '\U0001D553',
- "bot;": '\U000022A5',
- "bottom;": '\U000022A5',
- "bowtie;": '\U000022C8',
- "boxDL;": '\U00002557',
- "boxDR;": '\U00002554',
- "boxDl;": '\U00002556',
- "boxDr;": '\U00002553',
- "boxH;": '\U00002550',
- "boxHD;": '\U00002566',
- "boxHU;": '\U00002569',
- "boxHd;": '\U00002564',
- "boxHu;": '\U00002567',
- "boxUL;": '\U0000255D',
- "boxUR;": '\U0000255A',
- "boxUl;": '\U0000255C',
- "boxUr;": '\U00002559',
- "boxV;": '\U00002551',
- "boxVH;": '\U0000256C',
- "boxVL;": '\U00002563',
- "boxVR;": '\U00002560',
- "boxVh;": '\U0000256B',
- "boxVl;": '\U00002562',
- "boxVr;": '\U0000255F',
- "boxbox;": '\U000029C9',
- "boxdL;": '\U00002555',
- "boxdR;": '\U00002552',
- "boxdl;": '\U00002510',
- "boxdr;": '\U0000250C',
- "boxh;": '\U00002500',
- "boxhD;": '\U00002565',
- "boxhU;": '\U00002568',
- "boxhd;": '\U0000252C',
- "boxhu;": '\U00002534',
- "boxminus;": '\U0000229F',
- "boxplus;": '\U0000229E',
- "boxtimes;": '\U000022A0',
- "boxuL;": '\U0000255B',
- "boxuR;": '\U00002558',
- "boxul;": '\U00002518',
- "boxur;": '\U00002514',
- "boxv;": '\U00002502',
- "boxvH;": '\U0000256A',
- "boxvL;": '\U00002561',
- "boxvR;": '\U0000255E',
- "boxvh;": '\U0000253C',
- "boxvl;": '\U00002524',
- "boxvr;": '\U0000251C',
- "bprime;": '\U00002035',
- "breve;": '\U000002D8',
- "brvbar;": '\U000000A6',
- "bscr;": '\U0001D4B7',
- "bsemi;": '\U0000204F',
- "bsim;": '\U0000223D',
- "bsime;": '\U000022CD',
- "bsol;": '\U0000005C',
- "bsolb;": '\U000029C5',
- "bsolhsub;": '\U000027C8',
- "bull;": '\U00002022',
- "bullet;": '\U00002022',
- "bump;": '\U0000224E',
- "bumpE;": '\U00002AAE',
- "bumpe;": '\U0000224F',
- "bumpeq;": '\U0000224F',
- "cacute;": '\U00000107',
- "cap;": '\U00002229',
- "capand;": '\U00002A44',
- "capbrcup;": '\U00002A49',
- "capcap;": '\U00002A4B',
- "capcup;": '\U00002A47',
- "capdot;": '\U00002A40',
- "caret;": '\U00002041',
- "caron;": '\U000002C7',
- "ccaps;": '\U00002A4D',
- "ccaron;": '\U0000010D',
- "ccedil;": '\U000000E7',
- "ccirc;": '\U00000109',
- "ccups;": '\U00002A4C',
- "ccupssm;": '\U00002A50',
- "cdot;": '\U0000010B',
- "cedil;": '\U000000B8',
- "cemptyv;": '\U000029B2',
- "cent;": '\U000000A2',
- "centerdot;": '\U000000B7',
- "cfr;": '\U0001D520',
- "chcy;": '\U00000447',
- "check;": '\U00002713',
- "checkmark;": '\U00002713',
- "chi;": '\U000003C7',
- "cir;": '\U000025CB',
- "cirE;": '\U000029C3',
- "circ;": '\U000002C6',
- "circeq;": '\U00002257',
- "circlearrowleft;": '\U000021BA',
- "circlearrowright;": '\U000021BB',
- "circledR;": '\U000000AE',
- "circledS;": '\U000024C8',
- "circledast;": '\U0000229B',
- "circledcirc;": '\U0000229A',
- "circleddash;": '\U0000229D',
- "cire;": '\U00002257',
- "cirfnint;": '\U00002A10',
- "cirmid;": '\U00002AEF',
- "cirscir;": '\U000029C2',
- "clubs;": '\U00002663',
- "clubsuit;": '\U00002663',
- "colon;": '\U0000003A',
- "colone;": '\U00002254',
- "coloneq;": '\U00002254',
- "comma;": '\U0000002C',
- "commat;": '\U00000040',
- "comp;": '\U00002201',
- "compfn;": '\U00002218',
- "complement;": '\U00002201',
- "complexes;": '\U00002102',
- "cong;": '\U00002245',
- "congdot;": '\U00002A6D',
- "conint;": '\U0000222E',
- "copf;": '\U0001D554',
- "coprod;": '\U00002210',
- "copy;": '\U000000A9',
- "copysr;": '\U00002117',
- "crarr;": '\U000021B5',
- "cross;": '\U00002717',
- "cscr;": '\U0001D4B8',
- "csub;": '\U00002ACF',
- "csube;": '\U00002AD1',
- "csup;": '\U00002AD0',
- "csupe;": '\U00002AD2',
- "ctdot;": '\U000022EF',
- "cudarrl;": '\U00002938',
- "cudarrr;": '\U00002935',
- "cuepr;": '\U000022DE',
- "cuesc;": '\U000022DF',
- "cularr;": '\U000021B6',
- "cularrp;": '\U0000293D',
- "cup;": '\U0000222A',
- "cupbrcap;": '\U00002A48',
- "cupcap;": '\U00002A46',
- "cupcup;": '\U00002A4A',
- "cupdot;": '\U0000228D',
- "cupor;": '\U00002A45',
- "curarr;": '\U000021B7',
- "curarrm;": '\U0000293C',
- "curlyeqprec;": '\U000022DE',
- "curlyeqsucc;": '\U000022DF',
- "curlyvee;": '\U000022CE',
- "curlywedge;": '\U000022CF',
- "curren;": '\U000000A4',
- "curvearrowleft;": '\U000021B6',
- "curvearrowright;": '\U000021B7',
- "cuvee;": '\U000022CE',
- "cuwed;": '\U000022CF',
- "cwconint;": '\U00002232',
- "cwint;": '\U00002231',
- "cylcty;": '\U0000232D',
- "dArr;": '\U000021D3',
- "dHar;": '\U00002965',
- "dagger;": '\U00002020',
- "daleth;": '\U00002138',
- "darr;": '\U00002193',
- "dash;": '\U00002010',
- "dashv;": '\U000022A3',
- "dbkarow;": '\U0000290F',
- "dblac;": '\U000002DD',
- "dcaron;": '\U0000010F',
- "dcy;": '\U00000434',
- "dd;": '\U00002146',
- "ddagger;": '\U00002021',
- "ddarr;": '\U000021CA',
- "ddotseq;": '\U00002A77',
- "deg;": '\U000000B0',
- "delta;": '\U000003B4',
- "demptyv;": '\U000029B1',
- "dfisht;": '\U0000297F',
- "dfr;": '\U0001D521',
- "dharl;": '\U000021C3',
- "dharr;": '\U000021C2',
- "diam;": '\U000022C4',
- "diamond;": '\U000022C4',
- "diamondsuit;": '\U00002666',
- "diams;": '\U00002666',
- "die;": '\U000000A8',
- "digamma;": '\U000003DD',
- "disin;": '\U000022F2',
- "div;": '\U000000F7',
- "divide;": '\U000000F7',
- "divideontimes;": '\U000022C7',
- "divonx;": '\U000022C7',
- "djcy;": '\U00000452',
- "dlcorn;": '\U0000231E',
- "dlcrop;": '\U0000230D',
- "dollar;": '\U00000024',
- "dopf;": '\U0001D555',
- "dot;": '\U000002D9',
- "doteq;": '\U00002250',
- "doteqdot;": '\U00002251',
- "dotminus;": '\U00002238',
- "dotplus;": '\U00002214',
- "dotsquare;": '\U000022A1',
- "doublebarwedge;": '\U00002306',
- "downarrow;": '\U00002193',
- "downdownarrows;": '\U000021CA',
- "downharpoonleft;": '\U000021C3',
- "downharpoonright;": '\U000021C2',
- "drbkarow;": '\U00002910',
- "drcorn;": '\U0000231F',
- "drcrop;": '\U0000230C',
- "dscr;": '\U0001D4B9',
- "dscy;": '\U00000455',
- "dsol;": '\U000029F6',
- "dstrok;": '\U00000111',
- "dtdot;": '\U000022F1',
- "dtri;": '\U000025BF',
- "dtrif;": '\U000025BE',
- "duarr;": '\U000021F5',
- "duhar;": '\U0000296F',
- "dwangle;": '\U000029A6',
- "dzcy;": '\U0000045F',
- "dzigrarr;": '\U000027FF',
- "eDDot;": '\U00002A77',
- "eDot;": '\U00002251',
- "eacute;": '\U000000E9',
- "easter;": '\U00002A6E',
- "ecaron;": '\U0000011B',
- "ecir;": '\U00002256',
- "ecirc;": '\U000000EA',
- "ecolon;": '\U00002255',
- "ecy;": '\U0000044D',
- "edot;": '\U00000117',
- "ee;": '\U00002147',
- "efDot;": '\U00002252',
- "efr;": '\U0001D522',
- "eg;": '\U00002A9A',
- "egrave;": '\U000000E8',
- "egs;": '\U00002A96',
- "egsdot;": '\U00002A98',
- "el;": '\U00002A99',
- "elinters;": '\U000023E7',
- "ell;": '\U00002113',
- "els;": '\U00002A95',
- "elsdot;": '\U00002A97',
- "emacr;": '\U00000113',
- "empty;": '\U00002205',
- "emptyset;": '\U00002205',
- "emptyv;": '\U00002205',
- "emsp;": '\U00002003',
- "emsp13;": '\U00002004',
- "emsp14;": '\U00002005',
- "eng;": '\U0000014B',
- "ensp;": '\U00002002',
- "eogon;": '\U00000119',
- "eopf;": '\U0001D556',
- "epar;": '\U000022D5',
- "eparsl;": '\U000029E3',
- "eplus;": '\U00002A71',
- "epsi;": '\U000003B5',
- "epsilon;": '\U000003B5',
- "epsiv;": '\U000003F5',
- "eqcirc;": '\U00002256',
- "eqcolon;": '\U00002255',
- "eqsim;": '\U00002242',
- "eqslantgtr;": '\U00002A96',
- "eqslantless;": '\U00002A95',
- "equals;": '\U0000003D',
- "equest;": '\U0000225F',
- "equiv;": '\U00002261',
- "equivDD;": '\U00002A78',
- "eqvparsl;": '\U000029E5',
- "erDot;": '\U00002253',
- "erarr;": '\U00002971',
- "escr;": '\U0000212F',
- "esdot;": '\U00002250',
- "esim;": '\U00002242',
- "eta;": '\U000003B7',
- "eth;": '\U000000F0',
- "euml;": '\U000000EB',
- "euro;": '\U000020AC',
- "excl;": '\U00000021',
- "exist;": '\U00002203',
- "expectation;": '\U00002130',
- "exponentiale;": '\U00002147',
- "fallingdotseq;": '\U00002252',
- "fcy;": '\U00000444',
- "female;": '\U00002640',
- "ffilig;": '\U0000FB03',
- "fflig;": '\U0000FB00',
- "ffllig;": '\U0000FB04',
- "ffr;": '\U0001D523',
- "filig;": '\U0000FB01',
- "flat;": '\U0000266D',
- "fllig;": '\U0000FB02',
- "fltns;": '\U000025B1',
- "fnof;": '\U00000192',
- "fopf;": '\U0001D557',
- "forall;": '\U00002200',
- "fork;": '\U000022D4',
- "forkv;": '\U00002AD9',
- "fpartint;": '\U00002A0D',
- "frac12;": '\U000000BD',
- "frac13;": '\U00002153',
- "frac14;": '\U000000BC',
- "frac15;": '\U00002155',
- "frac16;": '\U00002159',
- "frac18;": '\U0000215B',
- "frac23;": '\U00002154',
- "frac25;": '\U00002156',
- "frac34;": '\U000000BE',
- "frac35;": '\U00002157',
- "frac38;": '\U0000215C',
- "frac45;": '\U00002158',
- "frac56;": '\U0000215A',
- "frac58;": '\U0000215D',
- "frac78;": '\U0000215E',
- "frasl;": '\U00002044',
- "frown;": '\U00002322',
- "fscr;": '\U0001D4BB',
- "gE;": '\U00002267',
- "gEl;": '\U00002A8C',
- "gacute;": '\U000001F5',
- "gamma;": '\U000003B3',
- "gammad;": '\U000003DD',
- "gap;": '\U00002A86',
- "gbreve;": '\U0000011F',
- "gcirc;": '\U0000011D',
- "gcy;": '\U00000433',
- "gdot;": '\U00000121',
- "ge;": '\U00002265',
- "gel;": '\U000022DB',
- "geq;": '\U00002265',
- "geqq;": '\U00002267',
- "geqslant;": '\U00002A7E',
- "ges;": '\U00002A7E',
- "gescc;": '\U00002AA9',
- "gesdot;": '\U00002A80',
- "gesdoto;": '\U00002A82',
- "gesdotol;": '\U00002A84',
- "gesles;": '\U00002A94',
- "gfr;": '\U0001D524',
- "gg;": '\U0000226B',
- "ggg;": '\U000022D9',
- "gimel;": '\U00002137',
- "gjcy;": '\U00000453',
- "gl;": '\U00002277',
- "glE;": '\U00002A92',
- "gla;": '\U00002AA5',
- "glj;": '\U00002AA4',
- "gnE;": '\U00002269',
- "gnap;": '\U00002A8A',
- "gnapprox;": '\U00002A8A',
- "gne;": '\U00002A88',
- "gneq;": '\U00002A88',
- "gneqq;": '\U00002269',
- "gnsim;": '\U000022E7',
- "gopf;": '\U0001D558',
- "grave;": '\U00000060',
- "gscr;": '\U0000210A',
- "gsim;": '\U00002273',
- "gsime;": '\U00002A8E',
- "gsiml;": '\U00002A90',
- "gt;": '\U0000003E',
- "gtcc;": '\U00002AA7',
- "gtcir;": '\U00002A7A',
- "gtdot;": '\U000022D7',
- "gtlPar;": '\U00002995',
- "gtquest;": '\U00002A7C',
- "gtrapprox;": '\U00002A86',
- "gtrarr;": '\U00002978',
- "gtrdot;": '\U000022D7',
- "gtreqless;": '\U000022DB',
- "gtreqqless;": '\U00002A8C',
- "gtrless;": '\U00002277',
- "gtrsim;": '\U00002273',
- "hArr;": '\U000021D4',
- "hairsp;": '\U0000200A',
- "half;": '\U000000BD',
- "hamilt;": '\U0000210B',
- "hardcy;": '\U0000044A',
- "harr;": '\U00002194',
- "harrcir;": '\U00002948',
- "harrw;": '\U000021AD',
- "hbar;": '\U0000210F',
- "hcirc;": '\U00000125',
- "hearts;": '\U00002665',
- "heartsuit;": '\U00002665',
- "hellip;": '\U00002026',
- "hercon;": '\U000022B9',
- "hfr;": '\U0001D525',
- "hksearow;": '\U00002925',
- "hkswarow;": '\U00002926',
- "hoarr;": '\U000021FF',
- "homtht;": '\U0000223B',
- "hookleftarrow;": '\U000021A9',
- "hookrightarrow;": '\U000021AA',
- "hopf;": '\U0001D559',
- "horbar;": '\U00002015',
- "hscr;": '\U0001D4BD',
- "hslash;": '\U0000210F',
- "hstrok;": '\U00000127',
- "hybull;": '\U00002043',
- "hyphen;": '\U00002010',
- "iacute;": '\U000000ED',
- "ic;": '\U00002063',
- "icirc;": '\U000000EE',
- "icy;": '\U00000438',
- "iecy;": '\U00000435',
- "iexcl;": '\U000000A1',
- "iff;": '\U000021D4',
- "ifr;": '\U0001D526',
- "igrave;": '\U000000EC',
- "ii;": '\U00002148',
- "iiiint;": '\U00002A0C',
- "iiint;": '\U0000222D',
- "iinfin;": '\U000029DC',
- "iiota;": '\U00002129',
- "ijlig;": '\U00000133',
- "imacr;": '\U0000012B',
- "image;": '\U00002111',
- "imagline;": '\U00002110',
- "imagpart;": '\U00002111',
- "imath;": '\U00000131',
- "imof;": '\U000022B7',
- "imped;": '\U000001B5',
- "in;": '\U00002208',
- "incare;": '\U00002105',
- "infin;": '\U0000221E',
- "infintie;": '\U000029DD',
- "inodot;": '\U00000131',
- "int;": '\U0000222B',
- "intcal;": '\U000022BA',
- "integers;": '\U00002124',
- "intercal;": '\U000022BA',
- "intlarhk;": '\U00002A17',
- "intprod;": '\U00002A3C',
- "iocy;": '\U00000451',
- "iogon;": '\U0000012F',
- "iopf;": '\U0001D55A',
- "iota;": '\U000003B9',
- "iprod;": '\U00002A3C',
- "iquest;": '\U000000BF',
- "iscr;": '\U0001D4BE',
- "isin;": '\U00002208',
- "isinE;": '\U000022F9',
- "isindot;": '\U000022F5',
- "isins;": '\U000022F4',
- "isinsv;": '\U000022F3',
- "isinv;": '\U00002208',
- "it;": '\U00002062',
- "itilde;": '\U00000129',
- "iukcy;": '\U00000456',
- "iuml;": '\U000000EF',
- "jcirc;": '\U00000135',
- "jcy;": '\U00000439',
- "jfr;": '\U0001D527',
- "jmath;": '\U00000237',
- "jopf;": '\U0001D55B',
- "jscr;": '\U0001D4BF',
- "jsercy;": '\U00000458',
- "jukcy;": '\U00000454',
- "kappa;": '\U000003BA',
- "kappav;": '\U000003F0',
- "kcedil;": '\U00000137',
- "kcy;": '\U0000043A',
- "kfr;": '\U0001D528',
- "kgreen;": '\U00000138',
- "khcy;": '\U00000445',
- "kjcy;": '\U0000045C',
- "kopf;": '\U0001D55C',
- "kscr;": '\U0001D4C0',
- "lAarr;": '\U000021DA',
- "lArr;": '\U000021D0',
- "lAtail;": '\U0000291B',
- "lBarr;": '\U0000290E',
- "lE;": '\U00002266',
- "lEg;": '\U00002A8B',
- "lHar;": '\U00002962',
- "lacute;": '\U0000013A',
- "laemptyv;": '\U000029B4',
- "lagran;": '\U00002112',
- "lambda;": '\U000003BB',
- "lang;": '\U000027E8',
- "langd;": '\U00002991',
- "langle;": '\U000027E8',
- "lap;": '\U00002A85',
- "laquo;": '\U000000AB',
- "larr;": '\U00002190',
- "larrb;": '\U000021E4',
- "larrbfs;": '\U0000291F',
- "larrfs;": '\U0000291D',
- "larrhk;": '\U000021A9',
- "larrlp;": '\U000021AB',
- "larrpl;": '\U00002939',
- "larrsim;": '\U00002973',
- "larrtl;": '\U000021A2',
- "lat;": '\U00002AAB',
- "latail;": '\U00002919',
- "late;": '\U00002AAD',
- "lbarr;": '\U0000290C',
- "lbbrk;": '\U00002772',
- "lbrace;": '\U0000007B',
- "lbrack;": '\U0000005B',
- "lbrke;": '\U0000298B',
- "lbrksld;": '\U0000298F',
- "lbrkslu;": '\U0000298D',
- "lcaron;": '\U0000013E',
- "lcedil;": '\U0000013C',
- "lceil;": '\U00002308',
- "lcub;": '\U0000007B',
- "lcy;": '\U0000043B',
- "ldca;": '\U00002936',
- "ldquo;": '\U0000201C',
- "ldquor;": '\U0000201E',
- "ldrdhar;": '\U00002967',
- "ldrushar;": '\U0000294B',
- "ldsh;": '\U000021B2',
- "le;": '\U00002264',
- "leftarrow;": '\U00002190',
- "leftarrowtail;": '\U000021A2',
- "leftharpoondown;": '\U000021BD',
- "leftharpoonup;": '\U000021BC',
- "leftleftarrows;": '\U000021C7',
- "leftrightarrow;": '\U00002194',
- "leftrightarrows;": '\U000021C6',
- "leftrightharpoons;": '\U000021CB',
- "leftrightsquigarrow;": '\U000021AD',
- "leftthreetimes;": '\U000022CB',
- "leg;": '\U000022DA',
- "leq;": '\U00002264',
- "leqq;": '\U00002266',
- "leqslant;": '\U00002A7D',
- "les;": '\U00002A7D',
- "lescc;": '\U00002AA8',
- "lesdot;": '\U00002A7F',
- "lesdoto;": '\U00002A81',
- "lesdotor;": '\U00002A83',
- "lesges;": '\U00002A93',
- "lessapprox;": '\U00002A85',
- "lessdot;": '\U000022D6',
- "lesseqgtr;": '\U000022DA',
- "lesseqqgtr;": '\U00002A8B',
- "lessgtr;": '\U00002276',
- "lesssim;": '\U00002272',
- "lfisht;": '\U0000297C',
- "lfloor;": '\U0000230A',
- "lfr;": '\U0001D529',
- "lg;": '\U00002276',
- "lgE;": '\U00002A91',
- "lhard;": '\U000021BD',
- "lharu;": '\U000021BC',
- "lharul;": '\U0000296A',
- "lhblk;": '\U00002584',
- "ljcy;": '\U00000459',
- "ll;": '\U0000226A',
- "llarr;": '\U000021C7',
- "llcorner;": '\U0000231E',
- "llhard;": '\U0000296B',
- "lltri;": '\U000025FA',
- "lmidot;": '\U00000140',
- "lmoust;": '\U000023B0',
- "lmoustache;": '\U000023B0',
- "lnE;": '\U00002268',
- "lnap;": '\U00002A89',
- "lnapprox;": '\U00002A89',
- "lne;": '\U00002A87',
- "lneq;": '\U00002A87',
- "lneqq;": '\U00002268',
- "lnsim;": '\U000022E6',
- "loang;": '\U000027EC',
- "loarr;": '\U000021FD',
- "lobrk;": '\U000027E6',
- "longleftarrow;": '\U000027F5',
- "longleftrightarrow;": '\U000027F7',
- "longmapsto;": '\U000027FC',
- "longrightarrow;": '\U000027F6',
- "looparrowleft;": '\U000021AB',
- "looparrowright;": '\U000021AC',
- "lopar;": '\U00002985',
- "lopf;": '\U0001D55D',
- "loplus;": '\U00002A2D',
- "lotimes;": '\U00002A34',
- "lowast;": '\U00002217',
- "lowbar;": '\U0000005F',
- "loz;": '\U000025CA',
- "lozenge;": '\U000025CA',
- "lozf;": '\U000029EB',
- "lpar;": '\U00000028',
- "lparlt;": '\U00002993',
- "lrarr;": '\U000021C6',
- "lrcorner;": '\U0000231F',
- "lrhar;": '\U000021CB',
- "lrhard;": '\U0000296D',
- "lrm;": '\U0000200E',
- "lrtri;": '\U000022BF',
- "lsaquo;": '\U00002039',
- "lscr;": '\U0001D4C1',
- "lsh;": '\U000021B0',
- "lsim;": '\U00002272',
- "lsime;": '\U00002A8D',
- "lsimg;": '\U00002A8F',
- "lsqb;": '\U0000005B',
- "lsquo;": '\U00002018',
- "lsquor;": '\U0000201A',
- "lstrok;": '\U00000142',
- "lt;": '\U0000003C',
- "ltcc;": '\U00002AA6',
- "ltcir;": '\U00002A79',
- "ltdot;": '\U000022D6',
- "lthree;": '\U000022CB',
- "ltimes;": '\U000022C9',
- "ltlarr;": '\U00002976',
- "ltquest;": '\U00002A7B',
- "ltrPar;": '\U00002996',
- "ltri;": '\U000025C3',
- "ltrie;": '\U000022B4',
- "ltrif;": '\U000025C2',
- "lurdshar;": '\U0000294A',
- "luruhar;": '\U00002966',
- "mDDot;": '\U0000223A',
- "macr;": '\U000000AF',
- "male;": '\U00002642',
- "malt;": '\U00002720',
- "maltese;": '\U00002720',
- "map;": '\U000021A6',
- "mapsto;": '\U000021A6',
- "mapstodown;": '\U000021A7',
- "mapstoleft;": '\U000021A4',
- "mapstoup;": '\U000021A5',
- "marker;": '\U000025AE',
- "mcomma;": '\U00002A29',
- "mcy;": '\U0000043C',
- "mdash;": '\U00002014',
- "measuredangle;": '\U00002221',
- "mfr;": '\U0001D52A',
- "mho;": '\U00002127',
- "micro;": '\U000000B5',
- "mid;": '\U00002223',
- "midast;": '\U0000002A',
- "midcir;": '\U00002AF0',
- "middot;": '\U000000B7',
- "minus;": '\U00002212',
- "minusb;": '\U0000229F',
- "minusd;": '\U00002238',
- "minusdu;": '\U00002A2A',
- "mlcp;": '\U00002ADB',
- "mldr;": '\U00002026',
- "mnplus;": '\U00002213',
- "models;": '\U000022A7',
- "mopf;": '\U0001D55E',
- "mp;": '\U00002213',
- "mscr;": '\U0001D4C2',
- "mstpos;": '\U0000223E',
- "mu;": '\U000003BC',
- "multimap;": '\U000022B8',
- "mumap;": '\U000022B8',
- "nLeftarrow;": '\U000021CD',
- "nLeftrightarrow;": '\U000021CE',
- "nRightarrow;": '\U000021CF',
- "nVDash;": '\U000022AF',
- "nVdash;": '\U000022AE',
- "nabla;": '\U00002207',
- "nacute;": '\U00000144',
- "nap;": '\U00002249',
- "napos;": '\U00000149',
- "napprox;": '\U00002249',
- "natur;": '\U0000266E',
- "natural;": '\U0000266E',
- "naturals;": '\U00002115',
- "nbsp;": '\U000000A0',
- "ncap;": '\U00002A43',
- "ncaron;": '\U00000148',
- "ncedil;": '\U00000146',
- "ncong;": '\U00002247',
- "ncup;": '\U00002A42',
- "ncy;": '\U0000043D',
- "ndash;": '\U00002013',
- "ne;": '\U00002260',
- "neArr;": '\U000021D7',
- "nearhk;": '\U00002924',
- "nearr;": '\U00002197',
- "nearrow;": '\U00002197',
- "nequiv;": '\U00002262',
- "nesear;": '\U00002928',
- "nexist;": '\U00002204',
- "nexists;": '\U00002204',
- "nfr;": '\U0001D52B',
- "nge;": '\U00002271',
- "ngeq;": '\U00002271',
- "ngsim;": '\U00002275',
- "ngt;": '\U0000226F',
- "ngtr;": '\U0000226F',
- "nhArr;": '\U000021CE',
- "nharr;": '\U000021AE',
- "nhpar;": '\U00002AF2',
- "ni;": '\U0000220B',
- "nis;": '\U000022FC',
- "nisd;": '\U000022FA',
- "niv;": '\U0000220B',
- "njcy;": '\U0000045A',
- "nlArr;": '\U000021CD',
- "nlarr;": '\U0000219A',
- "nldr;": '\U00002025',
- "nle;": '\U00002270',
- "nleftarrow;": '\U0000219A',
- "nleftrightarrow;": '\U000021AE',
- "nleq;": '\U00002270',
- "nless;": '\U0000226E',
- "nlsim;": '\U00002274',
- "nlt;": '\U0000226E',
- "nltri;": '\U000022EA',
- "nltrie;": '\U000022EC',
- "nmid;": '\U00002224',
- "nopf;": '\U0001D55F',
- "not;": '\U000000AC',
- "notin;": '\U00002209',
- "notinva;": '\U00002209',
- "notinvb;": '\U000022F7',
- "notinvc;": '\U000022F6',
- "notni;": '\U0000220C',
- "notniva;": '\U0000220C',
- "notnivb;": '\U000022FE',
- "notnivc;": '\U000022FD',
- "npar;": '\U00002226',
- "nparallel;": '\U00002226',
- "npolint;": '\U00002A14',
- "npr;": '\U00002280',
- "nprcue;": '\U000022E0',
- "nprec;": '\U00002280',
- "nrArr;": '\U000021CF',
- "nrarr;": '\U0000219B',
- "nrightarrow;": '\U0000219B',
- "nrtri;": '\U000022EB',
- "nrtrie;": '\U000022ED',
- "nsc;": '\U00002281',
- "nsccue;": '\U000022E1',
- "nscr;": '\U0001D4C3',
- "nshortmid;": '\U00002224',
- "nshortparallel;": '\U00002226',
- "nsim;": '\U00002241',
- "nsime;": '\U00002244',
- "nsimeq;": '\U00002244',
- "nsmid;": '\U00002224',
- "nspar;": '\U00002226',
- "nsqsube;": '\U000022E2',
- "nsqsupe;": '\U000022E3',
- "nsub;": '\U00002284',
- "nsube;": '\U00002288',
- "nsubseteq;": '\U00002288',
- "nsucc;": '\U00002281',
- "nsup;": '\U00002285',
- "nsupe;": '\U00002289',
- "nsupseteq;": '\U00002289',
- "ntgl;": '\U00002279',
- "ntilde;": '\U000000F1',
- "ntlg;": '\U00002278',
- "ntriangleleft;": '\U000022EA',
- "ntrianglelefteq;": '\U000022EC',
- "ntriangleright;": '\U000022EB',
- "ntrianglerighteq;": '\U000022ED',
- "nu;": '\U000003BD',
- "num;": '\U00000023',
- "numero;": '\U00002116',
- "numsp;": '\U00002007',
- "nvDash;": '\U000022AD',
- "nvHarr;": '\U00002904',
- "nvdash;": '\U000022AC',
- "nvinfin;": '\U000029DE',
- "nvlArr;": '\U00002902',
- "nvrArr;": '\U00002903',
- "nwArr;": '\U000021D6',
- "nwarhk;": '\U00002923',
- "nwarr;": '\U00002196',
- "nwarrow;": '\U00002196',
- "nwnear;": '\U00002927',
- "oS;": '\U000024C8',
- "oacute;": '\U000000F3',
- "oast;": '\U0000229B',
- "ocir;": '\U0000229A',
- "ocirc;": '\U000000F4',
- "ocy;": '\U0000043E',
- "odash;": '\U0000229D',
- "odblac;": '\U00000151',
- "odiv;": '\U00002A38',
- "odot;": '\U00002299',
- "odsold;": '\U000029BC',
- "oelig;": '\U00000153',
- "ofcir;": '\U000029BF',
- "ofr;": '\U0001D52C',
- "ogon;": '\U000002DB',
- "ograve;": '\U000000F2',
- "ogt;": '\U000029C1',
- "ohbar;": '\U000029B5',
- "ohm;": '\U000003A9',
- "oint;": '\U0000222E',
- "olarr;": '\U000021BA',
- "olcir;": '\U000029BE',
- "olcross;": '\U000029BB',
- "oline;": '\U0000203E',
- "olt;": '\U000029C0',
- "omacr;": '\U0000014D',
- "omega;": '\U000003C9',
- "omicron;": '\U000003BF',
- "omid;": '\U000029B6',
- "ominus;": '\U00002296',
- "oopf;": '\U0001D560',
- "opar;": '\U000029B7',
- "operp;": '\U000029B9',
- "oplus;": '\U00002295',
- "or;": '\U00002228',
- "orarr;": '\U000021BB',
- "ord;": '\U00002A5D',
- "order;": '\U00002134',
- "orderof;": '\U00002134',
- "ordf;": '\U000000AA',
- "ordm;": '\U000000BA',
- "origof;": '\U000022B6',
- "oror;": '\U00002A56',
- "orslope;": '\U00002A57',
- "orv;": '\U00002A5B',
- "oscr;": '\U00002134',
- "oslash;": '\U000000F8',
- "osol;": '\U00002298',
- "otilde;": '\U000000F5',
- "otimes;": '\U00002297',
- "otimesas;": '\U00002A36',
- "ouml;": '\U000000F6',
- "ovbar;": '\U0000233D',
- "par;": '\U00002225',
- "para;": '\U000000B6',
- "parallel;": '\U00002225',
- "parsim;": '\U00002AF3',
- "parsl;": '\U00002AFD',
- "part;": '\U00002202',
- "pcy;": '\U0000043F',
- "percnt;": '\U00000025',
- "period;": '\U0000002E',
- "permil;": '\U00002030',
- "perp;": '\U000022A5',
- "pertenk;": '\U00002031',
- "pfr;": '\U0001D52D',
- "phi;": '\U000003C6',
- "phiv;": '\U000003D5',
- "phmmat;": '\U00002133',
- "phone;": '\U0000260E',
- "pi;": '\U000003C0',
- "pitchfork;": '\U000022D4',
- "piv;": '\U000003D6',
- "planck;": '\U0000210F',
- "planckh;": '\U0000210E',
- "plankv;": '\U0000210F',
- "plus;": '\U0000002B',
- "plusacir;": '\U00002A23',
- "plusb;": '\U0000229E',
- "pluscir;": '\U00002A22',
- "plusdo;": '\U00002214',
- "plusdu;": '\U00002A25',
- "pluse;": '\U00002A72',
- "plusmn;": '\U000000B1',
- "plussim;": '\U00002A26',
- "plustwo;": '\U00002A27',
- "pm;": '\U000000B1',
- "pointint;": '\U00002A15',
- "popf;": '\U0001D561',
- "pound;": '\U000000A3',
- "pr;": '\U0000227A',
- "prE;": '\U00002AB3',
- "prap;": '\U00002AB7',
- "prcue;": '\U0000227C',
- "pre;": '\U00002AAF',
- "prec;": '\U0000227A',
- "precapprox;": '\U00002AB7',
- "preccurlyeq;": '\U0000227C',
- "preceq;": '\U00002AAF',
- "precnapprox;": '\U00002AB9',
- "precneqq;": '\U00002AB5',
- "precnsim;": '\U000022E8',
- "precsim;": '\U0000227E',
- "prime;": '\U00002032',
- "primes;": '\U00002119',
- "prnE;": '\U00002AB5',
- "prnap;": '\U00002AB9',
- "prnsim;": '\U000022E8',
- "prod;": '\U0000220F',
- "profalar;": '\U0000232E',
- "profline;": '\U00002312',
- "profsurf;": '\U00002313',
- "prop;": '\U0000221D',
- "propto;": '\U0000221D',
- "prsim;": '\U0000227E',
- "prurel;": '\U000022B0',
- "pscr;": '\U0001D4C5',
- "psi;": '\U000003C8',
- "puncsp;": '\U00002008',
- "qfr;": '\U0001D52E',
- "qint;": '\U00002A0C',
- "qopf;": '\U0001D562',
- "qprime;": '\U00002057',
- "qscr;": '\U0001D4C6',
- "quaternions;": '\U0000210D',
- "quatint;": '\U00002A16',
- "quest;": '\U0000003F',
- "questeq;": '\U0000225F',
- "quot;": '\U00000022',
- "rAarr;": '\U000021DB',
- "rArr;": '\U000021D2',
- "rAtail;": '\U0000291C',
- "rBarr;": '\U0000290F',
- "rHar;": '\U00002964',
- "racute;": '\U00000155',
- "radic;": '\U0000221A',
- "raemptyv;": '\U000029B3',
- "rang;": '\U000027E9',
- "rangd;": '\U00002992',
- "range;": '\U000029A5',
- "rangle;": '\U000027E9',
- "raquo;": '\U000000BB',
- "rarr;": '\U00002192',
- "rarrap;": '\U00002975',
- "rarrb;": '\U000021E5',
- "rarrbfs;": '\U00002920',
- "rarrc;": '\U00002933',
- "rarrfs;": '\U0000291E',
- "rarrhk;": '\U000021AA',
- "rarrlp;": '\U000021AC',
- "rarrpl;": '\U00002945',
- "rarrsim;": '\U00002974',
- "rarrtl;": '\U000021A3',
- "rarrw;": '\U0000219D',
- "ratail;": '\U0000291A',
- "ratio;": '\U00002236',
- "rationals;": '\U0000211A',
- "rbarr;": '\U0000290D',
- "rbbrk;": '\U00002773',
- "rbrace;": '\U0000007D',
- "rbrack;": '\U0000005D',
- "rbrke;": '\U0000298C',
- "rbrksld;": '\U0000298E',
- "rbrkslu;": '\U00002990',
- "rcaron;": '\U00000159',
- "rcedil;": '\U00000157',
- "rceil;": '\U00002309',
- "rcub;": '\U0000007D',
- "rcy;": '\U00000440',
- "rdca;": '\U00002937',
- "rdldhar;": '\U00002969',
- "rdquo;": '\U0000201D',
- "rdquor;": '\U0000201D',
- "rdsh;": '\U000021B3',
- "real;": '\U0000211C',
- "realine;": '\U0000211B',
- "realpart;": '\U0000211C',
- "reals;": '\U0000211D',
- "rect;": '\U000025AD',
- "reg;": '\U000000AE',
- "rfisht;": '\U0000297D',
- "rfloor;": '\U0000230B',
- "rfr;": '\U0001D52F',
- "rhard;": '\U000021C1',
- "rharu;": '\U000021C0',
- "rharul;": '\U0000296C',
- "rho;": '\U000003C1',
- "rhov;": '\U000003F1',
- "rightarrow;": '\U00002192',
- "rightarrowtail;": '\U000021A3',
- "rightharpoondown;": '\U000021C1',
- "rightharpoonup;": '\U000021C0',
- "rightleftarrows;": '\U000021C4',
- "rightleftharpoons;": '\U000021CC',
- "rightrightarrows;": '\U000021C9',
- "rightsquigarrow;": '\U0000219D',
- "rightthreetimes;": '\U000022CC',
- "ring;": '\U000002DA',
- "risingdotseq;": '\U00002253',
- "rlarr;": '\U000021C4',
- "rlhar;": '\U000021CC',
- "rlm;": '\U0000200F',
- "rmoust;": '\U000023B1',
- "rmoustache;": '\U000023B1',
- "rnmid;": '\U00002AEE',
- "roang;": '\U000027ED',
- "roarr;": '\U000021FE',
- "robrk;": '\U000027E7',
- "ropar;": '\U00002986',
- "ropf;": '\U0001D563',
- "roplus;": '\U00002A2E',
- "rotimes;": '\U00002A35',
- "rpar;": '\U00000029',
- "rpargt;": '\U00002994',
- "rppolint;": '\U00002A12',
- "rrarr;": '\U000021C9',
- "rsaquo;": '\U0000203A',
- "rscr;": '\U0001D4C7',
- "rsh;": '\U000021B1',
- "rsqb;": '\U0000005D',
- "rsquo;": '\U00002019',
- "rsquor;": '\U00002019',
- "rthree;": '\U000022CC',
- "rtimes;": '\U000022CA',
- "rtri;": '\U000025B9',
- "rtrie;": '\U000022B5',
- "rtrif;": '\U000025B8',
- "rtriltri;": '\U000029CE',
- "ruluhar;": '\U00002968',
- "rx;": '\U0000211E',
- "sacute;": '\U0000015B',
- "sbquo;": '\U0000201A',
- "sc;": '\U0000227B',
- "scE;": '\U00002AB4',
- "scap;": '\U00002AB8',
- "scaron;": '\U00000161',
- "sccue;": '\U0000227D',
- "sce;": '\U00002AB0',
- "scedil;": '\U0000015F',
- "scirc;": '\U0000015D',
- "scnE;": '\U00002AB6',
- "scnap;": '\U00002ABA',
- "scnsim;": '\U000022E9',
- "scpolint;": '\U00002A13',
- "scsim;": '\U0000227F',
- "scy;": '\U00000441',
- "sdot;": '\U000022C5',
- "sdotb;": '\U000022A1',
- "sdote;": '\U00002A66',
- "seArr;": '\U000021D8',
- "searhk;": '\U00002925',
- "searr;": '\U00002198',
- "searrow;": '\U00002198',
- "sect;": '\U000000A7',
- "semi;": '\U0000003B',
- "seswar;": '\U00002929',
- "setminus;": '\U00002216',
- "setmn;": '\U00002216',
- "sext;": '\U00002736',
- "sfr;": '\U0001D530',
- "sfrown;": '\U00002322',
- "sharp;": '\U0000266F',
- "shchcy;": '\U00000449',
- "shcy;": '\U00000448',
- "shortmid;": '\U00002223',
- "shortparallel;": '\U00002225',
- "shy;": '\U000000AD',
- "sigma;": '\U000003C3',
- "sigmaf;": '\U000003C2',
- "sigmav;": '\U000003C2',
- "sim;": '\U0000223C',
- "simdot;": '\U00002A6A',
- "sime;": '\U00002243',
- "simeq;": '\U00002243',
- "simg;": '\U00002A9E',
- "simgE;": '\U00002AA0',
- "siml;": '\U00002A9D',
- "simlE;": '\U00002A9F',
- "simne;": '\U00002246',
- "simplus;": '\U00002A24',
- "simrarr;": '\U00002972',
- "slarr;": '\U00002190',
- "smallsetminus;": '\U00002216',
- "smashp;": '\U00002A33',
- "smeparsl;": '\U000029E4',
- "smid;": '\U00002223',
- "smile;": '\U00002323',
- "smt;": '\U00002AAA',
- "smte;": '\U00002AAC',
- "softcy;": '\U0000044C',
- "sol;": '\U0000002F',
- "solb;": '\U000029C4',
- "solbar;": '\U0000233F',
- "sopf;": '\U0001D564',
- "spades;": '\U00002660',
- "spadesuit;": '\U00002660',
- "spar;": '\U00002225',
- "sqcap;": '\U00002293',
- "sqcup;": '\U00002294',
- "sqsub;": '\U0000228F',
- "sqsube;": '\U00002291',
- "sqsubset;": '\U0000228F',
- "sqsubseteq;": '\U00002291',
- "sqsup;": '\U00002290',
- "sqsupe;": '\U00002292',
- "sqsupset;": '\U00002290',
- "sqsupseteq;": '\U00002292',
- "squ;": '\U000025A1',
- "square;": '\U000025A1',
- "squarf;": '\U000025AA',
- "squf;": '\U000025AA',
- "srarr;": '\U00002192',
- "sscr;": '\U0001D4C8',
- "ssetmn;": '\U00002216',
- "ssmile;": '\U00002323',
- "sstarf;": '\U000022C6',
- "star;": '\U00002606',
- "starf;": '\U00002605',
- "straightepsilon;": '\U000003F5',
- "straightphi;": '\U000003D5',
- "strns;": '\U000000AF',
- "sub;": '\U00002282',
- "subE;": '\U00002AC5',
- "subdot;": '\U00002ABD',
- "sube;": '\U00002286',
- "subedot;": '\U00002AC3',
- "submult;": '\U00002AC1',
- "subnE;": '\U00002ACB',
- "subne;": '\U0000228A',
- "subplus;": '\U00002ABF',
- "subrarr;": '\U00002979',
- "subset;": '\U00002282',
- "subseteq;": '\U00002286',
- "subseteqq;": '\U00002AC5',
- "subsetneq;": '\U0000228A',
- "subsetneqq;": '\U00002ACB',
- "subsim;": '\U00002AC7',
- "subsub;": '\U00002AD5',
- "subsup;": '\U00002AD3',
- "succ;": '\U0000227B',
- "succapprox;": '\U00002AB8',
- "succcurlyeq;": '\U0000227D',
- "succeq;": '\U00002AB0',
- "succnapprox;": '\U00002ABA',
- "succneqq;": '\U00002AB6',
- "succnsim;": '\U000022E9',
- "succsim;": '\U0000227F',
- "sum;": '\U00002211',
- "sung;": '\U0000266A',
- "sup;": '\U00002283',
- "sup1;": '\U000000B9',
- "sup2;": '\U000000B2',
- "sup3;": '\U000000B3',
- "supE;": '\U00002AC6',
- "supdot;": '\U00002ABE',
- "supdsub;": '\U00002AD8',
- "supe;": '\U00002287',
- "supedot;": '\U00002AC4',
- "suphsol;": '\U000027C9',
- "suphsub;": '\U00002AD7',
- "suplarr;": '\U0000297B',
- "supmult;": '\U00002AC2',
- "supnE;": '\U00002ACC',
- "supne;": '\U0000228B',
- "supplus;": '\U00002AC0',
- "supset;": '\U00002283',
- "supseteq;": '\U00002287',
- "supseteqq;": '\U00002AC6',
- "supsetneq;": '\U0000228B',
- "supsetneqq;": '\U00002ACC',
- "supsim;": '\U00002AC8',
- "supsub;": '\U00002AD4',
- "supsup;": '\U00002AD6',
- "swArr;": '\U000021D9',
- "swarhk;": '\U00002926',
- "swarr;": '\U00002199',
- "swarrow;": '\U00002199',
- "swnwar;": '\U0000292A',
- "szlig;": '\U000000DF',
- "target;": '\U00002316',
- "tau;": '\U000003C4',
- "tbrk;": '\U000023B4',
- "tcaron;": '\U00000165',
- "tcedil;": '\U00000163',
- "tcy;": '\U00000442',
- "tdot;": '\U000020DB',
- "telrec;": '\U00002315',
- "tfr;": '\U0001D531',
- "there4;": '\U00002234',
- "therefore;": '\U00002234',
- "theta;": '\U000003B8',
- "thetasym;": '\U000003D1',
- "thetav;": '\U000003D1',
- "thickapprox;": '\U00002248',
- "thicksim;": '\U0000223C',
- "thinsp;": '\U00002009',
- "thkap;": '\U00002248',
- "thksim;": '\U0000223C',
- "thorn;": '\U000000FE',
- "tilde;": '\U000002DC',
- "times;": '\U000000D7',
- "timesb;": '\U000022A0',
- "timesbar;": '\U00002A31',
- "timesd;": '\U00002A30',
- "tint;": '\U0000222D',
- "toea;": '\U00002928',
- "top;": '\U000022A4',
- "topbot;": '\U00002336',
- "topcir;": '\U00002AF1',
- "topf;": '\U0001D565',
- "topfork;": '\U00002ADA',
- "tosa;": '\U00002929',
- "tprime;": '\U00002034',
- "trade;": '\U00002122',
- "triangle;": '\U000025B5',
- "triangledown;": '\U000025BF',
- "triangleleft;": '\U000025C3',
- "trianglelefteq;": '\U000022B4',
- "triangleq;": '\U0000225C',
- "triangleright;": '\U000025B9',
- "trianglerighteq;": '\U000022B5',
- "tridot;": '\U000025EC',
- "trie;": '\U0000225C',
- "triminus;": '\U00002A3A',
- "triplus;": '\U00002A39',
- "trisb;": '\U000029CD',
- "tritime;": '\U00002A3B',
- "trpezium;": '\U000023E2',
- "tscr;": '\U0001D4C9',
- "tscy;": '\U00000446',
- "tshcy;": '\U0000045B',
- "tstrok;": '\U00000167',
- "twixt;": '\U0000226C',
- "twoheadleftarrow;": '\U0000219E',
- "twoheadrightarrow;": '\U000021A0',
- "uArr;": '\U000021D1',
- "uHar;": '\U00002963',
- "uacute;": '\U000000FA',
- "uarr;": '\U00002191',
- "ubrcy;": '\U0000045E',
- "ubreve;": '\U0000016D',
- "ucirc;": '\U000000FB',
- "ucy;": '\U00000443',
- "udarr;": '\U000021C5',
- "udblac;": '\U00000171',
- "udhar;": '\U0000296E',
- "ufisht;": '\U0000297E',
- "ufr;": '\U0001D532',
- "ugrave;": '\U000000F9',
- "uharl;": '\U000021BF',
- "uharr;": '\U000021BE',
- "uhblk;": '\U00002580',
- "ulcorn;": '\U0000231C',
- "ulcorner;": '\U0000231C',
- "ulcrop;": '\U0000230F',
- "ultri;": '\U000025F8',
- "umacr;": '\U0000016B',
- "uml;": '\U000000A8',
- "uogon;": '\U00000173',
- "uopf;": '\U0001D566',
- "uparrow;": '\U00002191',
- "updownarrow;": '\U00002195',
- "upharpoonleft;": '\U000021BF',
- "upharpoonright;": '\U000021BE',
- "uplus;": '\U0000228E',
- "upsi;": '\U000003C5',
- "upsih;": '\U000003D2',
- "upsilon;": '\U000003C5',
- "upuparrows;": '\U000021C8',
- "urcorn;": '\U0000231D',
- "urcorner;": '\U0000231D',
- "urcrop;": '\U0000230E',
- "uring;": '\U0000016F',
- "urtri;": '\U000025F9',
- "uscr;": '\U0001D4CA',
- "utdot;": '\U000022F0',
- "utilde;": '\U00000169',
- "utri;": '\U000025B5',
- "utrif;": '\U000025B4',
- "uuarr;": '\U000021C8',
- "uuml;": '\U000000FC',
- "uwangle;": '\U000029A7',
- "vArr;": '\U000021D5',
- "vBar;": '\U00002AE8',
- "vBarv;": '\U00002AE9',
- "vDash;": '\U000022A8',
- "vangrt;": '\U0000299C',
- "varepsilon;": '\U000003F5',
- "varkappa;": '\U000003F0',
- "varnothing;": '\U00002205',
- "varphi;": '\U000003D5',
- "varpi;": '\U000003D6',
- "varpropto;": '\U0000221D',
- "varr;": '\U00002195',
- "varrho;": '\U000003F1',
- "varsigma;": '\U000003C2',
- "vartheta;": '\U000003D1',
- "vartriangleleft;": '\U000022B2',
- "vartriangleright;": '\U000022B3',
- "vcy;": '\U00000432',
- "vdash;": '\U000022A2',
- "vee;": '\U00002228',
- "veebar;": '\U000022BB',
- "veeeq;": '\U0000225A',
- "vellip;": '\U000022EE',
- "verbar;": '\U0000007C',
- "vert;": '\U0000007C',
- "vfr;": '\U0001D533',
- "vltri;": '\U000022B2',
- "vopf;": '\U0001D567',
- "vprop;": '\U0000221D',
- "vrtri;": '\U000022B3',
- "vscr;": '\U0001D4CB',
- "vzigzag;": '\U0000299A',
- "wcirc;": '\U00000175',
- "wedbar;": '\U00002A5F',
- "wedge;": '\U00002227',
- "wedgeq;": '\U00002259',
- "weierp;": '\U00002118',
- "wfr;": '\U0001D534',
- "wopf;": '\U0001D568',
- "wp;": '\U00002118',
- "wr;": '\U00002240',
- "wreath;": '\U00002240',
- "wscr;": '\U0001D4CC',
- "xcap;": '\U000022C2',
- "xcirc;": '\U000025EF',
- "xcup;": '\U000022C3',
- "xdtri;": '\U000025BD',
- "xfr;": '\U0001D535',
- "xhArr;": '\U000027FA',
- "xharr;": '\U000027F7',
- "xi;": '\U000003BE',
- "xlArr;": '\U000027F8',
- "xlarr;": '\U000027F5',
- "xmap;": '\U000027FC',
- "xnis;": '\U000022FB',
- "xodot;": '\U00002A00',
- "xopf;": '\U0001D569',
- "xoplus;": '\U00002A01',
- "xotime;": '\U00002A02',
- "xrArr;": '\U000027F9',
- "xrarr;": '\U000027F6',
- "xscr;": '\U0001D4CD',
- "xsqcup;": '\U00002A06',
- "xuplus;": '\U00002A04',
- "xutri;": '\U000025B3',
- "xvee;": '\U000022C1',
- "xwedge;": '\U000022C0',
- "yacute;": '\U000000FD',
- "yacy;": '\U0000044F',
- "ycirc;": '\U00000177',
- "ycy;": '\U0000044B',
- "yen;": '\U000000A5',
- "yfr;": '\U0001D536',
- "yicy;": '\U00000457',
- "yopf;": '\U0001D56A',
- "yscr;": '\U0001D4CE',
- "yucy;": '\U0000044E',
- "yuml;": '\U000000FF',
- "zacute;": '\U0000017A',
- "zcaron;": '\U0000017E',
- "zcy;": '\U00000437',
- "zdot;": '\U0000017C',
- "zeetrf;": '\U00002128',
- "zeta;": '\U000003B6',
- "zfr;": '\U0001D537',
- "zhcy;": '\U00000436',
- "zigrarr;": '\U000021DD',
- "zopf;": '\U0001D56B',
- "zscr;": '\U0001D4CF',
- "zwj;": '\U0000200D',
- "zwnj;": '\U0000200C',
- "AElig": '\U000000C6',
- "AMP": '\U00000026',
- "Aacute": '\U000000C1',
- "Acirc": '\U000000C2',
- "Agrave": '\U000000C0',
- "Aring": '\U000000C5',
- "Atilde": '\U000000C3',
- "Auml": '\U000000C4',
- "COPY": '\U000000A9',
- "Ccedil": '\U000000C7',
- "ETH": '\U000000D0',
- "Eacute": '\U000000C9',
- "Ecirc": '\U000000CA',
- "Egrave": '\U000000C8',
- "Euml": '\U000000CB',
- "GT": '\U0000003E',
- "Iacute": '\U000000CD',
- "Icirc": '\U000000CE',
- "Igrave": '\U000000CC',
- "Iuml": '\U000000CF',
- "LT": '\U0000003C',
- "Ntilde": '\U000000D1',
- "Oacute": '\U000000D3',
- "Ocirc": '\U000000D4',
- "Ograve": '\U000000D2',
- "Oslash": '\U000000D8',
- "Otilde": '\U000000D5',
- "Ouml": '\U000000D6',
- "QUOT": '\U00000022',
- "REG": '\U000000AE',
- "THORN": '\U000000DE',
- "Uacute": '\U000000DA',
- "Ucirc": '\U000000DB',
- "Ugrave": '\U000000D9',
- "Uuml": '\U000000DC',
- "Yacute": '\U000000DD',
- "aacute": '\U000000E1',
- "acirc": '\U000000E2',
- "acute": '\U000000B4',
- "aelig": '\U000000E6',
- "agrave": '\U000000E0',
- "amp": '\U00000026',
- "aring": '\U000000E5',
- "atilde": '\U000000E3',
- "auml": '\U000000E4',
- "brvbar": '\U000000A6',
- "ccedil": '\U000000E7',
- "cedil": '\U000000B8',
- "cent": '\U000000A2',
- "copy": '\U000000A9',
- "curren": '\U000000A4',
- "deg": '\U000000B0',
- "divide": '\U000000F7',
- "eacute": '\U000000E9',
- "ecirc": '\U000000EA',
- "egrave": '\U000000E8',
- "eth": '\U000000F0',
- "euml": '\U000000EB',
- "frac12": '\U000000BD',
- "frac14": '\U000000BC',
- "frac34": '\U000000BE',
- "gt": '\U0000003E',
- "iacute": '\U000000ED',
- "icirc": '\U000000EE',
- "iexcl": '\U000000A1',
- "igrave": '\U000000EC',
- "iquest": '\U000000BF',
- "iuml": '\U000000EF',
- "laquo": '\U000000AB',
- "lt": '\U0000003C',
- "macr": '\U000000AF',
- "micro": '\U000000B5',
- "middot": '\U000000B7',
- "nbsp": '\U000000A0',
- "not": '\U000000AC',
- "ntilde": '\U000000F1',
- "oacute": '\U000000F3',
- "ocirc": '\U000000F4',
- "ograve": '\U000000F2',
- "ordf": '\U000000AA',
- "ordm": '\U000000BA',
- "oslash": '\U000000F8',
- "otilde": '\U000000F5',
- "ouml": '\U000000F6',
- "para": '\U000000B6',
- "plusmn": '\U000000B1',
- "pound": '\U000000A3',
- "quot": '\U00000022',
- "raquo": '\U000000BB',
- "reg": '\U000000AE',
- "sect": '\U000000A7',
- "shy": '\U000000AD',
- "sup1": '\U000000B9',
- "sup2": '\U000000B2',
- "sup3": '\U000000B3',
- "szlig": '\U000000DF',
- "thorn": '\U000000FE',
- "times": '\U000000D7',
- "uacute": '\U000000FA',
- "ucirc": '\U000000FB',
- "ugrave": '\U000000F9',
- "uml": '\U000000A8',
- "uuml": '\U000000FC',
- "yacute": '\U000000FD',
- "yen": '\U000000A5',
- "yuml": '\U000000FF',
-}
-
-// HTML entities that are two unicode codepoints.
-var entity2 = map[string][2]rune{
- // TODO(nigeltao): Handle replacements that are wider than their names.
- // "nLt;": {'\u226A', '\u20D2'},
- // "nGt;": {'\u226B', '\u20D2'},
- "NotEqualTilde;": {'\u2242', '\u0338'},
- "NotGreaterFullEqual;": {'\u2267', '\u0338'},
- "NotGreaterGreater;": {'\u226B', '\u0338'},
- "NotGreaterSlantEqual;": {'\u2A7E', '\u0338'},
- "NotHumpDownHump;": {'\u224E', '\u0338'},
- "NotHumpEqual;": {'\u224F', '\u0338'},
- "NotLeftTriangleBar;": {'\u29CF', '\u0338'},
- "NotLessLess;": {'\u226A', '\u0338'},
- "NotLessSlantEqual;": {'\u2A7D', '\u0338'},
- "NotNestedGreaterGreater;": {'\u2AA2', '\u0338'},
- "NotNestedLessLess;": {'\u2AA1', '\u0338'},
- "NotPrecedesEqual;": {'\u2AAF', '\u0338'},
- "NotRightTriangleBar;": {'\u29D0', '\u0338'},
- "NotSquareSubset;": {'\u228F', '\u0338'},
- "NotSquareSuperset;": {'\u2290', '\u0338'},
- "NotSubset;": {'\u2282', '\u20D2'},
- "NotSucceedsEqual;": {'\u2AB0', '\u0338'},
- "NotSucceedsTilde;": {'\u227F', '\u0338'},
- "NotSuperset;": {'\u2283', '\u20D2'},
- "ThickSpace;": {'\u205F', '\u200A'},
- "acE;": {'\u223E', '\u0333'},
- "bne;": {'\u003D', '\u20E5'},
- "bnequiv;": {'\u2261', '\u20E5'},
- "caps;": {'\u2229', '\uFE00'},
- "cups;": {'\u222A', '\uFE00'},
- "fjlig;": {'\u0066', '\u006A'},
- "gesl;": {'\u22DB', '\uFE00'},
- "gvertneqq;": {'\u2269', '\uFE00'},
- "gvnE;": {'\u2269', '\uFE00'},
- "lates;": {'\u2AAD', '\uFE00'},
- "lesg;": {'\u22DA', '\uFE00'},
- "lvertneqq;": {'\u2268', '\uFE00'},
- "lvnE;": {'\u2268', '\uFE00'},
- "nGg;": {'\u22D9', '\u0338'},
- "nGtv;": {'\u226B', '\u0338'},
- "nLl;": {'\u22D8', '\u0338'},
- "nLtv;": {'\u226A', '\u0338'},
- "nang;": {'\u2220', '\u20D2'},
- "napE;": {'\u2A70', '\u0338'},
- "napid;": {'\u224B', '\u0338'},
- "nbump;": {'\u224E', '\u0338'},
- "nbumpe;": {'\u224F', '\u0338'},
- "ncongdot;": {'\u2A6D', '\u0338'},
- "nedot;": {'\u2250', '\u0338'},
- "nesim;": {'\u2242', '\u0338'},
- "ngE;": {'\u2267', '\u0338'},
- "ngeqq;": {'\u2267', '\u0338'},
- "ngeqslant;": {'\u2A7E', '\u0338'},
- "nges;": {'\u2A7E', '\u0338'},
- "nlE;": {'\u2266', '\u0338'},
- "nleqq;": {'\u2266', '\u0338'},
- "nleqslant;": {'\u2A7D', '\u0338'},
- "nles;": {'\u2A7D', '\u0338'},
- "notinE;": {'\u22F9', '\u0338'},
- "notindot;": {'\u22F5', '\u0338'},
- "nparsl;": {'\u2AFD', '\u20E5'},
- "npart;": {'\u2202', '\u0338'},
- "npre;": {'\u2AAF', '\u0338'},
- "npreceq;": {'\u2AAF', '\u0338'},
- "nrarrc;": {'\u2933', '\u0338'},
- "nrarrw;": {'\u219D', '\u0338'},
- "nsce;": {'\u2AB0', '\u0338'},
- "nsubE;": {'\u2AC5', '\u0338'},
- "nsubset;": {'\u2282', '\u20D2'},
- "nsubseteqq;": {'\u2AC5', '\u0338'},
- "nsucceq;": {'\u2AB0', '\u0338'},
- "nsupE;": {'\u2AC6', '\u0338'},
- "nsupset;": {'\u2283', '\u20D2'},
- "nsupseteqq;": {'\u2AC6', '\u0338'},
- "nvap;": {'\u224D', '\u20D2'},
- "nvge;": {'\u2265', '\u20D2'},
- "nvgt;": {'\u003E', '\u20D2'},
- "nvle;": {'\u2264', '\u20D2'},
- "nvlt;": {'\u003C', '\u20D2'},
- "nvltrie;": {'\u22B4', '\u20D2'},
- "nvrtrie;": {'\u22B5', '\u20D2'},
- "nvsim;": {'\u223C', '\u20D2'},
- "race;": {'\u223D', '\u0331'},
- "smtes;": {'\u2AAC', '\uFE00'},
- "sqcaps;": {'\u2293', '\uFE00'},
- "sqcups;": {'\u2294', '\uFE00'},
- "varsubsetneq;": {'\u228A', '\uFE00'},
- "varsubsetneqq;": {'\u2ACB', '\uFE00'},
- "varsupsetneq;": {'\u228B', '\uFE00'},
- "varsupsetneqq;": {'\u2ACC', '\uFE00'},
- "vnsub;": {'\u2282', '\u20D2'},
- "vnsup;": {'\u2283', '\u20D2'},
- "vsubnE;": {'\u2ACB', '\uFE00'},
- "vsubne;": {'\u228A', '\uFE00'},
- "vsupnE;": {'\u2ACC', '\uFE00'},
- "vsupne;": {'\u228B', '\uFE00'},
-}
diff --git a/libgo/go/exp/html/entity_test.go b/libgo/go/exp/html/entity_test.go
deleted file mode 100644
index b53f866fa2d..00000000000
--- a/libgo/go/exp/html/entity_test.go
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package html
-
-import (
- "testing"
- "unicode/utf8"
-)
-
-func TestEntityLength(t *testing.T) {
- // We verify that the length of UTF-8 encoding of each value is <= 1 + len(key).
- // The +1 comes from the leading "&". This property implies that the length of
- // unescaped text is <= the length of escaped text.
- for k, v := range entity {
- if 1+len(k) < utf8.RuneLen(v) {
- t.Error("escaped entity &" + k + " is shorter than its UTF-8 encoding " + string(v))
- }
- if len(k) > longestEntityWithoutSemicolon && k[len(k)-1] != ';' {
- t.Errorf("entity name %s is %d characters, but longestEntityWithoutSemicolon=%d", k, len(k), longestEntityWithoutSemicolon)
- }
- }
- for k, v := range entity2 {
- if 1+len(k) < utf8.RuneLen(v[0])+utf8.RuneLen(v[1]) {
- t.Error("escaped entity &" + k + " is shorter than its UTF-8 encoding " + string(v[0]) + string(v[1]))
- }
- }
-}
diff --git a/libgo/go/exp/html/escape.go b/libgo/go/exp/html/escape.go
deleted file mode 100644
index 75bddff094f..00000000000
--- a/libgo/go/exp/html/escape.go
+++ /dev/null
@@ -1,258 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package html
-
-import (
- "bytes"
- "strings"
- "unicode/utf8"
-)
-
-// These replacements permit compatibility with old numeric entities that
-// assumed Windows-1252 encoding.
-// http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#consume-a-character-reference
-var replacementTable = [...]rune{
- '\u20AC', // First entry is what 0x80 should be replaced with.
- '\u0081',
- '\u201A',
- '\u0192',
- '\u201E',
- '\u2026',
- '\u2020',
- '\u2021',
- '\u02C6',
- '\u2030',
- '\u0160',
- '\u2039',
- '\u0152',
- '\u008D',
- '\u017D',
- '\u008F',
- '\u0090',
- '\u2018',
- '\u2019',
- '\u201C',
- '\u201D',
- '\u2022',
- '\u2013',
- '\u2014',
- '\u02DC',
- '\u2122',
- '\u0161',
- '\u203A',
- '\u0153',
- '\u009D',
- '\u017E',
- '\u0178', // Last entry is 0x9F.
- // 0x00->'\uFFFD' is handled programmatically.
- // 0x0D->'\u000D' is a no-op.
-}
-
-// unescapeEntity reads an entity like "<" from b[src:] and writes the
-// corresponding "<" to b[dst:], returning the incremented dst and src cursors.
-// Precondition: b[src] == '&' && dst <= src.
-// attribute should be true if parsing an attribute value.
-func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) {
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#consume-a-character-reference
-
- // i starts at 1 because we already know that s[0] == '&'.
- i, s := 1, b[src:]
-
- if len(s) <= 1 {
- b[dst] = b[src]
- return dst + 1, src + 1
- }
-
- if s[i] == '#' {
- if len(s) <= 3 { // We need to have at least ".".
- b[dst] = b[src]
- return dst + 1, src + 1
- }
- i++
- c := s[i]
- hex := false
- if c == 'x' || c == 'X' {
- hex = true
- i++
- }
-
- x := '\x00'
- for i < len(s) {
- c = s[i]
- i++
- if hex {
- if '0' <= c && c <= '9' {
- x = 16*x + rune(c) - '0'
- continue
- } else if 'a' <= c && c <= 'f' {
- x = 16*x + rune(c) - 'a' + 10
- continue
- } else if 'A' <= c && c <= 'F' {
- x = 16*x + rune(c) - 'A' + 10
- continue
- }
- } else if '0' <= c && c <= '9' {
- x = 10*x + rune(c) - '0'
- continue
- }
- if c != ';' {
- i--
- }
- break
- }
-
- if i <= 3 { // No characters matched.
- b[dst] = b[src]
- return dst + 1, src + 1
- }
-
- if 0x80 <= x && x <= 0x9F {
- // Replace characters from Windows-1252 with UTF-8 equivalents.
- x = replacementTable[x-0x80]
- } else if x == 0 || (0xD800 <= x && x <= 0xDFFF) || x > 0x10FFFF {
- // Replace invalid characters with the replacement character.
- x = '\uFFFD'
- }
-
- return dst + utf8.EncodeRune(b[dst:], x), src + i
- }
-
- // Consume the maximum number of characters possible, with the
- // consumed characters matching one of the named references.
-
- for i < len(s) {
- c := s[i]
- i++
- // Lower-cased characters are more common in entities, so we check for them first.
- if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' {
- continue
- }
- if c != ';' {
- i--
- }
- break
- }
-
- entityName := string(s[1:i])
- if entityName == "" {
- // No-op.
- } else if attribute && entityName[len(entityName)-1] != ';' && len(s) > i && s[i] == '=' {
- // No-op.
- } else if x := entity[entityName]; x != 0 {
- return dst + utf8.EncodeRune(b[dst:], x), src + i
- } else if x := entity2[entityName]; x[0] != 0 {
- dst1 := dst + utf8.EncodeRune(b[dst:], x[0])
- return dst1 + utf8.EncodeRune(b[dst1:], x[1]), src + i
- } else if !attribute {
- maxLen := len(entityName) - 1
- if maxLen > longestEntityWithoutSemicolon {
- maxLen = longestEntityWithoutSemicolon
- }
- for j := maxLen; j > 1; j-- {
- if x := entity[entityName[:j]]; x != 0 {
- return dst + utf8.EncodeRune(b[dst:], x), src + j + 1
- }
- }
- }
-
- dst1, src1 = dst+i, src+i
- copy(b[dst:dst1], b[src:src1])
- return dst1, src1
-}
-
-// unescape unescapes b's entities in-place, so that "a<b" becomes "a':
- esc = ">"
- case '"':
- // """ is shorter than """.
- esc = """
- case '\r':
- esc = "
"
- default:
- panic("unrecognized escape character")
- }
- s = s[i+1:]
- if _, err := w.WriteString(esc); err != nil {
- return err
- }
- i = strings.IndexAny(s, escapedChars)
- }
- _, err := w.WriteString(s)
- return err
-}
-
-// EscapeString escapes special characters like "<" to become "<". It
-// escapes only five such characters: <, >, &, ' and ".
-// UnescapeString(EscapeString(s)) == s always holds, but the converse isn't
-// always true.
-func EscapeString(s string) string {
- if strings.IndexAny(s, escapedChars) == -1 {
- return s
- }
- var buf bytes.Buffer
- escape(&buf, s)
- return buf.String()
-}
-
-// UnescapeString unescapes entities like "<" to become "<". It unescapes a
-// larger range of entities than EscapeString escapes. For example, "á"
-// unescapes to "á", as does "á" and "&xE1;".
-// UnescapeString(EscapeString(s)) == s always holds, but the converse isn't
-// always true.
-func UnescapeString(s string) string {
- for _, c := range s {
- if c == '&' {
- return string(unescape([]byte(s), false))
- }
- }
- return s
-}
diff --git a/libgo/go/exp/html/foreign.go b/libgo/go/exp/html/foreign.go
deleted file mode 100644
index d3b3844099b..00000000000
--- a/libgo/go/exp/html/foreign.go
+++ /dev/null
@@ -1,226 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package html
-
-import (
- "strings"
-)
-
-func adjustAttributeNames(aa []Attribute, nameMap map[string]string) {
- for i := range aa {
- if newName, ok := nameMap[aa[i].Key]; ok {
- aa[i].Key = newName
- }
- }
-}
-
-func adjustForeignAttributes(aa []Attribute) {
- for i, a := range aa {
- if a.Key == "" || a.Key[0] != 'x' {
- continue
- }
- switch a.Key {
- case "xlink:actuate", "xlink:arcrole", "xlink:href", "xlink:role", "xlink:show",
- "xlink:title", "xlink:type", "xml:base", "xml:lang", "xml:space", "xmlns:xlink":
- j := strings.Index(a.Key, ":")
- aa[i].Namespace = a.Key[:j]
- aa[i].Key = a.Key[j+1:]
- }
- }
-}
-
-func htmlIntegrationPoint(n *Node) bool {
- if n.Type != ElementNode {
- return false
- }
- switch n.Namespace {
- case "math":
- if n.Data == "annotation-xml" {
- for _, a := range n.Attr {
- if a.Key == "encoding" {
- val := strings.ToLower(a.Val)
- if val == "text/html" || val == "application/xhtml+xml" {
- return true
- }
- }
- }
- }
- case "svg":
- switch n.Data {
- case "desc", "foreignObject", "title":
- return true
- }
- }
- return false
-}
-
-func mathMLTextIntegrationPoint(n *Node) bool {
- if n.Namespace != "math" {
- return false
- }
- switch n.Data {
- case "mi", "mo", "mn", "ms", "mtext":
- return true
- }
- return false
-}
-
-// Section 12.2.5.5.
-var breakout = map[string]bool{
- "b": true,
- "big": true,
- "blockquote": true,
- "body": true,
- "br": true,
- "center": true,
- "code": true,
- "dd": true,
- "div": true,
- "dl": true,
- "dt": true,
- "em": true,
- "embed": true,
- "h1": true,
- "h2": true,
- "h3": true,
- "h4": true,
- "h5": true,
- "h6": true,
- "head": true,
- "hr": true,
- "i": true,
- "img": true,
- "li": true,
- "listing": true,
- "menu": true,
- "meta": true,
- "nobr": true,
- "ol": true,
- "p": true,
- "pre": true,
- "ruby": true,
- "s": true,
- "small": true,
- "span": true,
- "strong": true,
- "strike": true,
- "sub": true,
- "sup": true,
- "table": true,
- "tt": true,
- "u": true,
- "ul": true,
- "var": true,
-}
-
-// Section 12.2.5.5.
-var svgTagNameAdjustments = map[string]string{
- "altglyph": "altGlyph",
- "altglyphdef": "altGlyphDef",
- "altglyphitem": "altGlyphItem",
- "animatecolor": "animateColor",
- "animatemotion": "animateMotion",
- "animatetransform": "animateTransform",
- "clippath": "clipPath",
- "feblend": "feBlend",
- "fecolormatrix": "feColorMatrix",
- "fecomponenttransfer": "feComponentTransfer",
- "fecomposite": "feComposite",
- "feconvolvematrix": "feConvolveMatrix",
- "fediffuselighting": "feDiffuseLighting",
- "fedisplacementmap": "feDisplacementMap",
- "fedistantlight": "feDistantLight",
- "feflood": "feFlood",
- "fefunca": "feFuncA",
- "fefuncb": "feFuncB",
- "fefuncg": "feFuncG",
- "fefuncr": "feFuncR",
- "fegaussianblur": "feGaussianBlur",
- "feimage": "feImage",
- "femerge": "feMerge",
- "femergenode": "feMergeNode",
- "femorphology": "feMorphology",
- "feoffset": "feOffset",
- "fepointlight": "fePointLight",
- "fespecularlighting": "feSpecularLighting",
- "fespotlight": "feSpotLight",
- "fetile": "feTile",
- "feturbulence": "feTurbulence",
- "foreignobject": "foreignObject",
- "glyphref": "glyphRef",
- "lineargradient": "linearGradient",
- "radialgradient": "radialGradient",
- "textpath": "textPath",
-}
-
-// Section 12.2.5.1
-var mathMLAttributeAdjustments = map[string]string{
- "definitionurl": "definitionURL",
-}
-
-var svgAttributeAdjustments = map[string]string{
- "attributename": "attributeName",
- "attributetype": "attributeType",
- "basefrequency": "baseFrequency",
- "baseprofile": "baseProfile",
- "calcmode": "calcMode",
- "clippathunits": "clipPathUnits",
- "contentscripttype": "contentScriptType",
- "contentstyletype": "contentStyleType",
- "diffuseconstant": "diffuseConstant",
- "edgemode": "edgeMode",
- "externalresourcesrequired": "externalResourcesRequired",
- "filterres": "filterRes",
- "filterunits": "filterUnits",
- "glyphref": "glyphRef",
- "gradienttransform": "gradientTransform",
- "gradientunits": "gradientUnits",
- "kernelmatrix": "kernelMatrix",
- "kernelunitlength": "kernelUnitLength",
- "keypoints": "keyPoints",
- "keysplines": "keySplines",
- "keytimes": "keyTimes",
- "lengthadjust": "lengthAdjust",
- "limitingconeangle": "limitingConeAngle",
- "markerheight": "markerHeight",
- "markerunits": "markerUnits",
- "markerwidth": "markerWidth",
- "maskcontentunits": "maskContentUnits",
- "maskunits": "maskUnits",
- "numoctaves": "numOctaves",
- "pathlength": "pathLength",
- "patterncontentunits": "patternContentUnits",
- "patterntransform": "patternTransform",
- "patternunits": "patternUnits",
- "pointsatx": "pointsAtX",
- "pointsaty": "pointsAtY",
- "pointsatz": "pointsAtZ",
- "preservealpha": "preserveAlpha",
- "preserveaspectratio": "preserveAspectRatio",
- "primitiveunits": "primitiveUnits",
- "refx": "refX",
- "refy": "refY",
- "repeatcount": "repeatCount",
- "repeatdur": "repeatDur",
- "requiredextensions": "requiredExtensions",
- "requiredfeatures": "requiredFeatures",
- "specularconstant": "specularConstant",
- "specularexponent": "specularExponent",
- "spreadmethod": "spreadMethod",
- "startoffset": "startOffset",
- "stddeviation": "stdDeviation",
- "stitchtiles": "stitchTiles",
- "surfacescale": "surfaceScale",
- "systemlanguage": "systemLanguage",
- "tablevalues": "tableValues",
- "targetx": "targetX",
- "targety": "targetY",
- "textlength": "textLength",
- "viewbox": "viewBox",
- "viewtarget": "viewTarget",
- "xchannelselector": "xChannelSelector",
- "ychannelselector": "yChannelSelector",
- "zoomandpan": "zoomAndPan",
-}
diff --git a/libgo/go/exp/html/node.go b/libgo/go/exp/html/node.go
deleted file mode 100644
index 01f8c42ce3a..00000000000
--- a/libgo/go/exp/html/node.go
+++ /dev/null
@@ -1,193 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package html
-
-import (
- "exp/html/atom"
-)
-
-// A NodeType is the type of a Node.
-type NodeType uint32
-
-const (
- ErrorNode NodeType = iota
- TextNode
- DocumentNode
- ElementNode
- CommentNode
- DoctypeNode
- scopeMarkerNode
-)
-
-// Section 12.2.3.3 says "scope markers are inserted when entering applet
-// elements, buttons, object elements, marquees, table cells, and table
-// captions, and are used to prevent formatting from 'leaking'".
-var scopeMarker = Node{Type: scopeMarkerNode}
-
-// A Node consists of a NodeType and some Data (tag name for element nodes,
-// content for text) and are part of a tree of Nodes. Element nodes may also
-// have a Namespace and contain a slice of Attributes. Data is unescaped, so
-// that it looks like "a 0 {
- return (*s)[i-1]
- }
- return nil
-}
-
-// index returns the index of the top-most occurrence of n in the stack, or -1
-// if n is not present.
-func (s *nodeStack) index(n *Node) int {
- for i := len(*s) - 1; i >= 0; i-- {
- if (*s)[i] == n {
- return i
- }
- }
- return -1
-}
-
-// insert inserts a node at the given index.
-func (s *nodeStack) insert(i int, n *Node) {
- (*s) = append(*s, nil)
- copy((*s)[i+1:], (*s)[i:])
- (*s)[i] = n
-}
-
-// remove removes a node from the stack. It is a no-op if n is not present.
-func (s *nodeStack) remove(n *Node) {
- i := s.index(n)
- if i == -1 {
- return
- }
- copy((*s)[i:], (*s)[i+1:])
- j := len(*s) - 1
- (*s)[j] = nil
- *s = (*s)[:j]
-}
diff --git a/libgo/go/exp/html/node_test.go b/libgo/go/exp/html/node_test.go
deleted file mode 100644
index 471102f3a22..00000000000
--- a/libgo/go/exp/html/node_test.go
+++ /dev/null
@@ -1,146 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package html
-
-import (
- "fmt"
-)
-
-// checkTreeConsistency checks that a node and its descendants are all
-// consistent in their parent/child/sibling relationships.
-func checkTreeConsistency(n *Node) error {
- return checkTreeConsistency1(n, 0)
-}
-
-func checkTreeConsistency1(n *Node, depth int) error {
- if depth == 1e4 {
- return fmt.Errorf("html: tree looks like it contains a cycle")
- }
- if err := checkNodeConsistency(n); err != nil {
- return err
- }
- for c := n.FirstChild; c != nil; c = c.NextSibling {
- if err := checkTreeConsistency1(c, depth+1); err != nil {
- return err
- }
- }
- return nil
-}
-
-// checkNodeConsistency checks that a node's parent/child/sibling relationships
-// are consistent.
-func checkNodeConsistency(n *Node) error {
- if n == nil {
- return nil
- }
-
- nParent := 0
- for p := n.Parent; p != nil; p = p.Parent {
- nParent++
- if nParent == 1e4 {
- return fmt.Errorf("html: parent list looks like an infinite loop")
- }
- }
-
- nForward := 0
- for c := n.FirstChild; c != nil; c = c.NextSibling {
- nForward++
- if nForward == 1e6 {
- return fmt.Errorf("html: forward list of children looks like an infinite loop")
- }
- if c.Parent != n {
- return fmt.Errorf("html: inconsistent child/parent relationship")
- }
- }
-
- nBackward := 0
- for c := n.LastChild; c != nil; c = c.PrevSibling {
- nBackward++
- if nBackward == 1e6 {
- return fmt.Errorf("html: backward list of children looks like an infinite loop")
- }
- if c.Parent != n {
- return fmt.Errorf("html: inconsistent child/parent relationship")
- }
- }
-
- if n.Parent != nil {
- if n.Parent == n {
- return fmt.Errorf("html: inconsistent parent relationship")
- }
- if n.Parent == n.FirstChild {
- return fmt.Errorf("html: inconsistent parent/first relationship")
- }
- if n.Parent == n.LastChild {
- return fmt.Errorf("html: inconsistent parent/last relationship")
- }
- if n.Parent == n.PrevSibling {
- return fmt.Errorf("html: inconsistent parent/prev relationship")
- }
- if n.Parent == n.NextSibling {
- return fmt.Errorf("html: inconsistent parent/next relationship")
- }
-
- parentHasNAsAChild := false
- for c := n.Parent.FirstChild; c != nil; c = c.NextSibling {
- if c == n {
- parentHasNAsAChild = true
- break
- }
- }
- if !parentHasNAsAChild {
- return fmt.Errorf("html: inconsistent parent/child relationship")
- }
- }
-
- if n.PrevSibling != nil && n.PrevSibling.NextSibling != n {
- return fmt.Errorf("html: inconsistent prev/next relationship")
- }
- if n.NextSibling != nil && n.NextSibling.PrevSibling != n {
- return fmt.Errorf("html: inconsistent next/prev relationship")
- }
-
- if (n.FirstChild == nil) != (n.LastChild == nil) {
- return fmt.Errorf("html: inconsistent first/last relationship")
- }
- if n.FirstChild != nil && n.FirstChild == n.LastChild {
- // We have a sole child.
- if n.FirstChild.PrevSibling != nil || n.FirstChild.NextSibling != nil {
- return fmt.Errorf("html: inconsistent sole child's sibling relationship")
- }
- }
-
- seen := map[*Node]bool{}
-
- var last *Node
- for c := n.FirstChild; c != nil; c = c.NextSibling {
- if seen[c] {
- return fmt.Errorf("html: inconsistent repeated child")
- }
- seen[c] = true
- last = c
- }
- if last != n.LastChild {
- return fmt.Errorf("html: inconsistent last relationship")
- }
-
- var first *Node
- for c := n.LastChild; c != nil; c = c.PrevSibling {
- if !seen[c] {
- return fmt.Errorf("html: inconsistent missing child")
- }
- delete(seen, c)
- first = c
- }
- if first != n.FirstChild {
- return fmt.Errorf("html: inconsistent first relationship")
- }
-
- if len(seen) != 0 {
- return fmt.Errorf("html: inconsistent forwards/backwards child list")
- }
-
- return nil
-}
diff --git a/libgo/go/exp/html/parse.go b/libgo/go/exp/html/parse.go
deleted file mode 100644
index 0ff15746f21..00000000000
--- a/libgo/go/exp/html/parse.go
+++ /dev/null
@@ -1,2091 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package html
-
-import (
- "errors"
- a "exp/html/atom"
- "fmt"
- "io"
- "strings"
-)
-
-// A parser implements the HTML5 parsing algorithm:
-// http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#tree-construction
-type parser struct {
- // tokenizer provides the tokens for the parser.
- tokenizer *Tokenizer
- // tok is the most recently read token.
- tok Token
- // Self-closing tags like
are treated as start tags, except that
- // hasSelfClosingToken is set while they are being processed.
- hasSelfClosingToken bool
- // doc is the document root element.
- doc *Node
- // The stack of open elements (section 12.2.3.2) and active formatting
- // elements (section 12.2.3.3).
- oe, afe nodeStack
- // Element pointers (section 12.2.3.4).
- head, form *Node
- // Other parsing state flags (section 12.2.3.5).
- scripting, framesetOK bool
- // im is the current insertion mode.
- im insertionMode
- // originalIM is the insertion mode to go back to after completing a text
- // or inTableText insertion mode.
- originalIM insertionMode
- // fosterParenting is whether new elements should be inserted according to
- // the foster parenting rules (section 12.2.5.3).
- fosterParenting bool
- // quirks is whether the parser is operating in "quirks mode."
- quirks bool
- // fragment is whether the parser is parsing an HTML fragment.
- fragment bool
- // context is the context element when parsing an HTML fragment
- // (section 12.4).
- context *Node
-}
-
-func (p *parser) top() *Node {
- if n := p.oe.top(); n != nil {
- return n
- }
- return p.doc
-}
-
-// Stop tags for use in popUntil. These come from section 12.2.3.2.
-var (
- defaultScopeStopTags = map[string][]a.Atom{
- "": {a.Applet, a.Caption, a.Html, a.Table, a.Td, a.Th, a.Marquee, a.Object},
- "math": {a.AnnotationXml, a.Mi, a.Mn, a.Mo, a.Ms, a.Mtext},
- "svg": {a.Desc, a.ForeignObject, a.Title},
- }
-)
-
-type scope int
-
-const (
- defaultScope scope = iota
- listItemScope
- buttonScope
- tableScope
- tableRowScope
- tableBodyScope
- selectScope
-)
-
-// popUntil pops the stack of open elements at the highest element whose tag
-// is in matchTags, provided there is no higher element in the scope's stop
-// tags (as defined in section 12.2.3.2). It returns whether or not there was
-// such an element. If there was not, popUntil leaves the stack unchanged.
-//
-// For example, the set of stop tags for table scope is: "html", "table". If
-// the stack was:
-// ["html", "body", "font", "table", "b", "i", "u"]
-// then popUntil(tableScope, "font") would return false, but
-// popUntil(tableScope, "i") would return true and the stack would become:
-// ["html", "body", "font", "table", "b"]
-//
-// If an element's tag is in both the stop tags and matchTags, then the stack
-// will be popped and the function returns true (provided, of course, there was
-// no higher element in the stack that was also in the stop tags). For example,
-// popUntil(tableScope, "table") returns true and leaves:
-// ["html", "body", "font"]
-func (p *parser) popUntil(s scope, matchTags ...a.Atom) bool {
- if i := p.indexOfElementInScope(s, matchTags...); i != -1 {
- p.oe = p.oe[:i]
- return true
- }
- return false
-}
-
-// indexOfElementInScope returns the index in p.oe of the highest element whose
-// tag is in matchTags that is in scope. If no matching element is in scope, it
-// returns -1.
-func (p *parser) indexOfElementInScope(s scope, matchTags ...a.Atom) int {
- for i := len(p.oe) - 1; i >= 0; i-- {
- tagAtom := p.oe[i].DataAtom
- if p.oe[i].Namespace == "" {
- for _, t := range matchTags {
- if t == tagAtom {
- return i
- }
- }
- switch s {
- case defaultScope:
- // No-op.
- case listItemScope:
- if tagAtom == a.Ol || tagAtom == a.Ul {
- return -1
- }
- case buttonScope:
- if tagAtom == a.Button {
- return -1
- }
- case tableScope:
- if tagAtom == a.Html || tagAtom == a.Table {
- return -1
- }
- case selectScope:
- if tagAtom != a.Optgroup && tagAtom != a.Option {
- return -1
- }
- default:
- panic("unreachable")
- }
- }
- switch s {
- case defaultScope, listItemScope, buttonScope:
- for _, t := range defaultScopeStopTags[p.oe[i].Namespace] {
- if t == tagAtom {
- return -1
- }
- }
- }
- }
- return -1
-}
-
-// elementInScope is like popUntil, except that it doesn't modify the stack of
-// open elements.
-func (p *parser) elementInScope(s scope, matchTags ...a.Atom) bool {
- return p.indexOfElementInScope(s, matchTags...) != -1
-}
-
-// clearStackToContext pops elements off the stack of open elements until a
-// scope-defined element is found.
-func (p *parser) clearStackToContext(s scope) {
- for i := len(p.oe) - 1; i >= 0; i-- {
- tagAtom := p.oe[i].DataAtom
- switch s {
- case tableScope:
- if tagAtom == a.Html || tagAtom == a.Table {
- p.oe = p.oe[:i+1]
- return
- }
- case tableRowScope:
- if tagAtom == a.Html || tagAtom == a.Tr {
- p.oe = p.oe[:i+1]
- return
- }
- case tableBodyScope:
- if tagAtom == a.Html || tagAtom == a.Tbody || tagAtom == a.Tfoot || tagAtom == a.Thead {
- p.oe = p.oe[:i+1]
- return
- }
- default:
- panic("unreachable")
- }
- }
-}
-
-// generateImpliedEndTags pops nodes off the stack of open elements as long as
-// the top node has a tag name of dd, dt, li, option, optgroup, p, rp, or rt.
-// If exceptions are specified, nodes with that name will not be popped off.
-func (p *parser) generateImpliedEndTags(exceptions ...string) {
- var i int
-loop:
- for i = len(p.oe) - 1; i >= 0; i-- {
- n := p.oe[i]
- if n.Type == ElementNode {
- switch n.DataAtom {
- case a.Dd, a.Dt, a.Li, a.Option, a.Optgroup, a.P, a.Rp, a.Rt:
- for _, except := range exceptions {
- if n.Data == except {
- break loop
- }
- }
- continue
- }
- }
- break
- }
-
- p.oe = p.oe[:i+1]
-}
-
-// addChild adds a child node n to the top element, and pushes n onto the stack
-// of open elements if it is an element node.
-func (p *parser) addChild(n *Node) {
- if p.shouldFosterParent() {
- p.fosterParent(n)
- } else {
- p.top().AppendChild(n)
- }
-
- if n.Type == ElementNode {
- p.oe = append(p.oe, n)
- }
-}
-
-// shouldFosterParent returns whether the next node to be added should be
-// foster parented.
-func (p *parser) shouldFosterParent() bool {
- if p.fosterParenting {
- switch p.top().DataAtom {
- case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr:
- return true
- }
- }
- return false
-}
-
-// fosterParent adds a child node according to the foster parenting rules.
-// Section 12.2.5.3, "foster parenting".
-func (p *parser) fosterParent(n *Node) {
- var table, parent, prev *Node
- var i int
- for i = len(p.oe) - 1; i >= 0; i-- {
- if p.oe[i].DataAtom == a.Table {
- table = p.oe[i]
- break
- }
- }
-
- if table == nil {
- // The foster parent is the html element.
- parent = p.oe[0]
- } else {
- parent = table.Parent
- }
- if parent == nil {
- parent = p.oe[i-1]
- }
-
- if table != nil {
- prev = table.PrevSibling
- } else {
- prev = parent.LastChild
- }
- if prev != nil && prev.Type == TextNode && n.Type == TextNode {
- prev.Data += n.Data
- return
- }
-
- parent.InsertBefore(n, table)
-}
-
-// addText adds text to the preceding node if it is a text node, or else it
-// calls addChild with a new text node.
-func (p *parser) addText(text string) {
- if text == "" {
- return
- }
-
- if p.shouldFosterParent() {
- p.fosterParent(&Node{
- Type: TextNode,
- Data: text,
- })
- return
- }
-
- t := p.top()
- if n := t.LastChild; n != nil && n.Type == TextNode {
- n.Data += text
- return
- }
- p.addChild(&Node{
- Type: TextNode,
- Data: text,
- })
-}
-
-// addElement adds a child element based on the current token.
-func (p *parser) addElement() {
- p.addChild(&Node{
- Type: ElementNode,
- DataAtom: p.tok.DataAtom,
- Data: p.tok.Data,
- Attr: p.tok.Attr,
- })
-}
-
-// Section 12.2.3.3.
-func (p *parser) addFormattingElement() {
- tagAtom, attr := p.tok.DataAtom, p.tok.Attr
- p.addElement()
-
- // Implement the Noah's Ark clause, but with three per family instead of two.
- identicalElements := 0
-findIdenticalElements:
- for i := len(p.afe) - 1; i >= 0; i-- {
- n := p.afe[i]
- if n.Type == scopeMarkerNode {
- break
- }
- if n.Type != ElementNode {
- continue
- }
- if n.Namespace != "" {
- continue
- }
- if n.DataAtom != tagAtom {
- continue
- }
- if len(n.Attr) != len(attr) {
- continue
- }
- compareAttributes:
- for _, t0 := range n.Attr {
- for _, t1 := range attr {
- if t0.Key == t1.Key && t0.Namespace == t1.Namespace && t0.Val == t1.Val {
- // Found a match for this attribute, continue with the next attribute.
- continue compareAttributes
- }
- }
- // If we get here, there is no attribute that matches a.
- // Therefore the element is not identical to the new one.
- continue findIdenticalElements
- }
-
- identicalElements++
- if identicalElements >= 3 {
- p.afe.remove(n)
- }
- }
-
- p.afe = append(p.afe, p.top())
-}
-
-// Section 12.2.3.3.
-func (p *parser) clearActiveFormattingElements() {
- for {
- n := p.afe.pop()
- if len(p.afe) == 0 || n.Type == scopeMarkerNode {
- return
- }
- }
-}
-
-// Section 12.2.3.3.
-func (p *parser) reconstructActiveFormattingElements() {
- n := p.afe.top()
- if n == nil {
- return
- }
- if n.Type == scopeMarkerNode || p.oe.index(n) != -1 {
- return
- }
- i := len(p.afe) - 1
- for n.Type != scopeMarkerNode && p.oe.index(n) == -1 {
- if i == 0 {
- i = -1
- break
- }
- i--
- n = p.afe[i]
- }
- for {
- i++
- clone := p.afe[i].clone()
- p.addChild(clone)
- p.afe[i] = clone
- if i == len(p.afe)-1 {
- break
- }
- }
-}
-
-// Section 12.2.4.
-func (p *parser) acknowledgeSelfClosingTag() {
- p.hasSelfClosingToken = false
-}
-
-// An insertion mode (section 12.2.3.1) is the state transition function from
-// a particular state in the HTML5 parser's state machine. It updates the
-// parser's fields depending on parser.tok (where ErrorToken means EOF).
-// It returns whether the token was consumed.
-type insertionMode func(*parser) bool
-
-// setOriginalIM sets the insertion mode to return to after completing a text or
-// inTableText insertion mode.
-// Section 12.2.3.1, "using the rules for".
-func (p *parser) setOriginalIM() {
- if p.originalIM != nil {
- panic("html: bad parser state: originalIM was set twice")
- }
- p.originalIM = p.im
-}
-
-// Section 12.2.3.1, "reset the insertion mode".
-func (p *parser) resetInsertionMode() {
- for i := len(p.oe) - 1; i >= 0; i-- {
- n := p.oe[i]
- if i == 0 && p.context != nil {
- n = p.context
- }
-
- switch n.DataAtom {
- case a.Select:
- p.im = inSelectIM
- case a.Td, a.Th:
- p.im = inCellIM
- case a.Tr:
- p.im = inRowIM
- case a.Tbody, a.Thead, a.Tfoot:
- p.im = inTableBodyIM
- case a.Caption:
- p.im = inCaptionIM
- case a.Colgroup:
- p.im = inColumnGroupIM
- case a.Table:
- p.im = inTableIM
- case a.Head:
- p.im = inBodyIM
- case a.Body:
- p.im = inBodyIM
- case a.Frameset:
- p.im = inFramesetIM
- case a.Html:
- p.im = beforeHeadIM
- default:
- continue
- }
- return
- }
- p.im = inBodyIM
-}
-
-const whitespace = " \t\r\n\f"
-
-// Section 12.2.5.4.1.
-func initialIM(p *parser) bool {
- switch p.tok.Type {
- case TextToken:
- p.tok.Data = strings.TrimLeft(p.tok.Data, whitespace)
- if len(p.tok.Data) == 0 {
- // It was all whitespace, so ignore it.
- return true
- }
- case CommentToken:
- p.doc.AppendChild(&Node{
- Type: CommentNode,
- Data: p.tok.Data,
- })
- return true
- case DoctypeToken:
- n, quirks := parseDoctype(p.tok.Data)
- p.doc.AppendChild(n)
- p.quirks = quirks
- p.im = beforeHTMLIM
- return true
- }
- p.quirks = true
- p.im = beforeHTMLIM
- return false
-}
-
-// Section 12.2.5.4.2.
-func beforeHTMLIM(p *parser) bool {
- switch p.tok.Type {
- case DoctypeToken:
- // Ignore the token.
- return true
- case TextToken:
- p.tok.Data = strings.TrimLeft(p.tok.Data, whitespace)
- if len(p.tok.Data) == 0 {
- // It was all whitespace, so ignore it.
- return true
- }
- case StartTagToken:
- if p.tok.DataAtom == a.Html {
- p.addElement()
- p.im = beforeHeadIM
- return true
- }
- case EndTagToken:
- switch p.tok.DataAtom {
- case a.Head, a.Body, a.Html, a.Br:
- p.parseImpliedToken(StartTagToken, a.Html, a.Html.String())
- return false
- default:
- // Ignore the token.
- return true
- }
- case CommentToken:
- p.doc.AppendChild(&Node{
- Type: CommentNode,
- Data: p.tok.Data,
- })
- return true
- }
- p.parseImpliedToken(StartTagToken, a.Html, a.Html.String())
- return false
-}
-
-// Section 12.2.5.4.3.
-func beforeHeadIM(p *parser) bool {
- switch p.tok.Type {
- case TextToken:
- p.tok.Data = strings.TrimLeft(p.tok.Data, whitespace)
- if len(p.tok.Data) == 0 {
- // It was all whitespace, so ignore it.
- return true
- }
- case StartTagToken:
- switch p.tok.DataAtom {
- case a.Head:
- p.addElement()
- p.head = p.top()
- p.im = inHeadIM
- return true
- case a.Html:
- return inBodyIM(p)
- }
- case EndTagToken:
- switch p.tok.DataAtom {
- case a.Head, a.Body, a.Html, a.Br:
- p.parseImpliedToken(StartTagToken, a.Head, a.Head.String())
- return false
- default:
- // Ignore the token.
- return true
- }
- case CommentToken:
- p.addChild(&Node{
- Type: CommentNode,
- Data: p.tok.Data,
- })
- return true
- case DoctypeToken:
- // Ignore the token.
- return true
- }
-
- p.parseImpliedToken(StartTagToken, a.Head, a.Head.String())
- return false
-}
-
-// Section 12.2.5.4.4.
-func inHeadIM(p *parser) bool {
- switch p.tok.Type {
- case TextToken:
- s := strings.TrimLeft(p.tok.Data, whitespace)
- if len(s) < len(p.tok.Data) {
- // Add the initial whitespace to the current node.
- p.addText(p.tok.Data[:len(p.tok.Data)-len(s)])
- if s == "" {
- return true
- }
- p.tok.Data = s
- }
- case StartTagToken:
- switch p.tok.DataAtom {
- case a.Html:
- return inBodyIM(p)
- case a.Base, a.Basefont, a.Bgsound, a.Command, a.Link, a.Meta:
- p.addElement()
- p.oe.pop()
- p.acknowledgeSelfClosingTag()
- return true
- case a.Script, a.Title, a.Noscript, a.Noframes, a.Style:
- p.addElement()
- p.setOriginalIM()
- p.im = textIM
- return true
- case a.Head:
- // Ignore the token.
- return true
- }
- case EndTagToken:
- switch p.tok.DataAtom {
- case a.Head:
- n := p.oe.pop()
- if n.DataAtom != a.Head {
- panic("html: bad parser state: element not found, in the in-head insertion mode")
- }
- p.im = afterHeadIM
- return true
- case a.Body, a.Html, a.Br:
- p.parseImpliedToken(EndTagToken, a.Head, a.Head.String())
- return false
- default:
- // Ignore the token.
- return true
- }
- case CommentToken:
- p.addChild(&Node{
- Type: CommentNode,
- Data: p.tok.Data,
- })
- return true
- case DoctypeToken:
- // Ignore the token.
- return true
- }
-
- p.parseImpliedToken(EndTagToken, a.Head, a.Head.String())
- return false
-}
-
-// Section 12.2.5.4.6.
-func afterHeadIM(p *parser) bool {
- switch p.tok.Type {
- case TextToken:
- s := strings.TrimLeft(p.tok.Data, whitespace)
- if len(s) < len(p.tok.Data) {
- // Add the initial whitespace to the current node.
- p.addText(p.tok.Data[:len(p.tok.Data)-len(s)])
- if s == "" {
- return true
- }
- p.tok.Data = s
- }
- case StartTagToken:
- switch p.tok.DataAtom {
- case a.Html:
- return inBodyIM(p)
- case a.Body:
- p.addElement()
- p.framesetOK = false
- p.im = inBodyIM
- return true
- case a.Frameset:
- p.addElement()
- p.im = inFramesetIM
- return true
- case a.Base, a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Title:
- p.oe = append(p.oe, p.head)
- defer p.oe.remove(p.head)
- return inHeadIM(p)
- case a.Head:
- // Ignore the token.
- return true
- }
- case EndTagToken:
- switch p.tok.DataAtom {
- case a.Body, a.Html, a.Br:
- // Drop down to creating an implied tag.
- default:
- // Ignore the token.
- return true
- }
- case CommentToken:
- p.addChild(&Node{
- Type: CommentNode,
- Data: p.tok.Data,
- })
- return true
- case DoctypeToken:
- // Ignore the token.
- return true
- }
-
- p.parseImpliedToken(StartTagToken, a.Body, a.Body.String())
- p.framesetOK = true
- return false
-}
-
-// copyAttributes copies attributes of src not found on dst to dst.
-func copyAttributes(dst *Node, src Token) {
- if len(src.Attr) == 0 {
- return
- }
- attr := map[string]string{}
- for _, t := range dst.Attr {
- attr[t.Key] = t.Val
- }
- for _, t := range src.Attr {
- if _, ok := attr[t.Key]; !ok {
- dst.Attr = append(dst.Attr, t)
- attr[t.Key] = t.Val
- }
- }
-}
-
-// Section 12.2.5.4.7.
-func inBodyIM(p *parser) bool {
- switch p.tok.Type {
- case TextToken:
- d := p.tok.Data
- switch n := p.oe.top(); n.DataAtom {
- case a.Pre, a.Listing:
- if n.FirstChild == nil {
- // Ignore a newline at the start of a block.
- if d != "" && d[0] == '\r' {
- d = d[1:]
- }
- if d != "" && d[0] == '\n' {
- d = d[1:]
- }
- }
- }
- d = strings.Replace(d, "\x00", "", -1)
- if d == "" {
- return true
- }
- p.reconstructActiveFormattingElements()
- p.addText(d)
- if p.framesetOK && strings.TrimLeft(d, whitespace) != "" {
- // There were non-whitespace characters inserted.
- p.framesetOK = false
- }
- case StartTagToken:
- switch p.tok.DataAtom {
- case a.Html:
- copyAttributes(p.oe[0], p.tok)
- case a.Base, a.Basefont, a.Bgsound, a.Command, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Title:
- return inHeadIM(p)
- case a.Body:
- if len(p.oe) >= 2 {
- body := p.oe[1]
- if body.Type == ElementNode && body.DataAtom == a.Body {
- p.framesetOK = false
- copyAttributes(body, p.tok)
- }
- }
- case a.Frameset:
- if !p.framesetOK || len(p.oe) < 2 || p.oe[1].DataAtom != a.Body {
- // Ignore the token.
- return true
- }
- body := p.oe[1]
- if body.Parent != nil {
- body.Parent.RemoveChild(body)
- }
- p.oe = p.oe[:1]
- p.addElement()
- p.im = inFramesetIM
- return true
- case a.Address, a.Article, a.Aside, a.Blockquote, a.Center, a.Details, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Menu, a.Nav, a.Ol, a.P, a.Section, a.Summary, a.Ul:
- p.popUntil(buttonScope, a.P)
- p.addElement()
- case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6:
- p.popUntil(buttonScope, a.P)
- switch n := p.top(); n.DataAtom {
- case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6:
- p.oe.pop()
- }
- p.addElement()
- case a.Pre, a.Listing:
- p.popUntil(buttonScope, a.P)
- p.addElement()
- // The newline, if any, will be dealt with by the TextToken case.
- p.framesetOK = false
- case a.Form:
- if p.form == nil {
- p.popUntil(buttonScope, a.P)
- p.addElement()
- p.form = p.top()
- }
- case a.Li:
- p.framesetOK = false
- for i := len(p.oe) - 1; i >= 0; i-- {
- node := p.oe[i]
- switch node.DataAtom {
- case a.Li:
- p.oe = p.oe[:i]
- case a.Address, a.Div, a.P:
- continue
- default:
- if !isSpecialElement(node) {
- continue
- }
- }
- break
- }
- p.popUntil(buttonScope, a.P)
- p.addElement()
- case a.Dd, a.Dt:
- p.framesetOK = false
- for i := len(p.oe) - 1; i >= 0; i-- {
- node := p.oe[i]
- switch node.DataAtom {
- case a.Dd, a.Dt:
- p.oe = p.oe[:i]
- case a.Address, a.Div, a.P:
- continue
- default:
- if !isSpecialElement(node) {
- continue
- }
- }
- break
- }
- p.popUntil(buttonScope, a.P)
- p.addElement()
- case a.Plaintext:
- p.popUntil(buttonScope, a.P)
- p.addElement()
- case a.Button:
- p.popUntil(defaultScope, a.Button)
- p.reconstructActiveFormattingElements()
- p.addElement()
- p.framesetOK = false
- case a.A:
- for i := len(p.afe) - 1; i >= 0 && p.afe[i].Type != scopeMarkerNode; i-- {
- if n := p.afe[i]; n.Type == ElementNode && n.DataAtom == a.A {
- p.inBodyEndTagFormatting(a.A)
- p.oe.remove(n)
- p.afe.remove(n)
- break
- }
- }
- p.reconstructActiveFormattingElements()
- p.addFormattingElement()
- case a.B, a.Big, a.Code, a.Em, a.Font, a.I, a.S, a.Small, a.Strike, a.Strong, a.Tt, a.U:
- p.reconstructActiveFormattingElements()
- p.addFormattingElement()
- case a.Nobr:
- p.reconstructActiveFormattingElements()
- if p.elementInScope(defaultScope, a.Nobr) {
- p.inBodyEndTagFormatting(a.Nobr)
- p.reconstructActiveFormattingElements()
- }
- p.addFormattingElement()
- case a.Applet, a.Marquee, a.Object:
- p.reconstructActiveFormattingElements()
- p.addElement()
- p.afe = append(p.afe, &scopeMarker)
- p.framesetOK = false
- case a.Table:
- if !p.quirks {
- p.popUntil(buttonScope, a.P)
- }
- p.addElement()
- p.framesetOK = false
- p.im = inTableIM
- return true
- case a.Area, a.Br, a.Embed, a.Img, a.Input, a.Keygen, a.Wbr:
- p.reconstructActiveFormattingElements()
- p.addElement()
- p.oe.pop()
- p.acknowledgeSelfClosingTag()
- if p.tok.DataAtom == a.Input {
- for _, t := range p.tok.Attr {
- if t.Key == "type" {
- if strings.ToLower(t.Val) == "hidden" {
- // Skip setting framesetOK = false
- return true
- }
- }
- }
- }
- p.framesetOK = false
- case a.Param, a.Source, a.Track:
- p.addElement()
- p.oe.pop()
- p.acknowledgeSelfClosingTag()
- case a.Hr:
- p.popUntil(buttonScope, a.P)
- p.addElement()
- p.oe.pop()
- p.acknowledgeSelfClosingTag()
- p.framesetOK = false
- case a.Image:
- p.tok.DataAtom = a.Img
- p.tok.Data = a.Img.String()
- return false
- case a.Isindex:
- if p.form != nil {
- // Ignore the token.
- return true
- }
- action := ""
- prompt := "This is a searchable index. Enter search keywords: "
- attr := []Attribute{{Key: "name", Val: "isindex"}}
- for _, t := range p.tok.Attr {
- switch t.Key {
- case "action":
- action = t.Val
- case "name":
- // Ignore the attribute.
- case "prompt":
- prompt = t.Val
- default:
- attr = append(attr, t)
- }
- }
- p.acknowledgeSelfClosingTag()
- p.popUntil(buttonScope, a.P)
- p.parseImpliedToken(StartTagToken, a.Form, a.Form.String())
- if action != "" {
- p.form.Attr = []Attribute{{Key: "action", Val: action}}
- }
- p.parseImpliedToken(StartTagToken, a.Hr, a.Hr.String())
- p.parseImpliedToken(StartTagToken, a.Label, a.Label.String())
- p.addText(prompt)
- p.addChild(&Node{
- Type: ElementNode,
- DataAtom: a.Input,
- Data: a.Input.String(),
- Attr: attr,
- })
- p.oe.pop()
- p.parseImpliedToken(EndTagToken, a.Label, a.Label.String())
- p.parseImpliedToken(StartTagToken, a.Hr, a.Hr.String())
- p.parseImpliedToken(EndTagToken, a.Form, a.Form.String())
- case a.Textarea:
- p.addElement()
- p.setOriginalIM()
- p.framesetOK = false
- p.im = textIM
- case a.Xmp:
- p.popUntil(buttonScope, a.P)
- p.reconstructActiveFormattingElements()
- p.framesetOK = false
- p.addElement()
- p.setOriginalIM()
- p.im = textIM
- case a.Iframe:
- p.framesetOK = false
- p.addElement()
- p.setOriginalIM()
- p.im = textIM
- case a.Noembed, a.Noscript:
- p.addElement()
- p.setOriginalIM()
- p.im = textIM
- case a.Select:
- p.reconstructActiveFormattingElements()
- p.addElement()
- p.framesetOK = false
- p.im = inSelectIM
- return true
- case a.Optgroup, a.Option:
- if p.top().DataAtom == a.Option {
- p.oe.pop()
- }
- p.reconstructActiveFormattingElements()
- p.addElement()
- case a.Rp, a.Rt:
- if p.elementInScope(defaultScope, a.Ruby) {
- p.generateImpliedEndTags()
- }
- p.addElement()
- case a.Math, a.Svg:
- p.reconstructActiveFormattingElements()
- if p.tok.DataAtom == a.Math {
- adjustAttributeNames(p.tok.Attr, mathMLAttributeAdjustments)
- } else {
- adjustAttributeNames(p.tok.Attr, svgAttributeAdjustments)
- }
- adjustForeignAttributes(p.tok.Attr)
- p.addElement()
- p.top().Namespace = p.tok.Data
- if p.hasSelfClosingToken {
- p.oe.pop()
- p.acknowledgeSelfClosingTag()
- }
- return true
- case a.Caption, a.Col, a.Colgroup, a.Frame, a.Head, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
- // Ignore the token.
- default:
- p.reconstructActiveFormattingElements()
- p.addElement()
- }
- case EndTagToken:
- switch p.tok.DataAtom {
- case a.Body:
- if p.elementInScope(defaultScope, a.Body) {
- p.im = afterBodyIM
- }
- case a.Html:
- if p.elementInScope(defaultScope, a.Body) {
- p.parseImpliedToken(EndTagToken, a.Body, a.Body.String())
- return false
- }
- return true
- case a.Address, a.Article, a.Aside, a.Blockquote, a.Button, a.Center, a.Details, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Listing, a.Menu, a.Nav, a.Ol, a.Pre, a.Section, a.Summary, a.Ul:
- p.popUntil(defaultScope, p.tok.DataAtom)
- case a.Form:
- node := p.form
- p.form = nil
- i := p.indexOfElementInScope(defaultScope, a.Form)
- if node == nil || i == -1 || p.oe[i] != node {
- // Ignore the token.
- return true
- }
- p.generateImpliedEndTags()
- p.oe.remove(node)
- case a.P:
- if !p.elementInScope(buttonScope, a.P) {
- p.parseImpliedToken(StartTagToken, a.P, a.P.String())
- }
- p.popUntil(buttonScope, a.P)
- case a.Li:
- p.popUntil(listItemScope, a.Li)
- case a.Dd, a.Dt:
- p.popUntil(defaultScope, p.tok.DataAtom)
- case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6:
- p.popUntil(defaultScope, a.H1, a.H2, a.H3, a.H4, a.H5, a.H6)
- case a.A, a.B, a.Big, a.Code, a.Em, a.Font, a.I, a.Nobr, a.S, a.Small, a.Strike, a.Strong, a.Tt, a.U:
- p.inBodyEndTagFormatting(p.tok.DataAtom)
- case a.Applet, a.Marquee, a.Object:
- if p.popUntil(defaultScope, p.tok.DataAtom) {
- p.clearActiveFormattingElements()
- }
- case a.Br:
- p.tok.Type = StartTagToken
- return false
- default:
- p.inBodyEndTagOther(p.tok.DataAtom)
- }
- case CommentToken:
- p.addChild(&Node{
- Type: CommentNode,
- Data: p.tok.Data,
- })
- }
-
- return true
-}
-
-func (p *parser) inBodyEndTagFormatting(tagAtom a.Atom) {
- // This is the "adoption agency" algorithm, described at
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#adoptionAgency
-
- // TODO: this is a fairly literal line-by-line translation of that algorithm.
- // Once the code successfully parses the comprehensive test suite, we should
- // refactor this code to be more idiomatic.
-
- // Steps 1-3. The outer loop.
- for i := 0; i < 8; i++ {
- // Step 4. Find the formatting element.
- var formattingElement *Node
- for j := len(p.afe) - 1; j >= 0; j-- {
- if p.afe[j].Type == scopeMarkerNode {
- break
- }
- if p.afe[j].DataAtom == tagAtom {
- formattingElement = p.afe[j]
- break
- }
- }
- if formattingElement == nil {
- p.inBodyEndTagOther(tagAtom)
- return
- }
- feIndex := p.oe.index(formattingElement)
- if feIndex == -1 {
- p.afe.remove(formattingElement)
- return
- }
- if !p.elementInScope(defaultScope, tagAtom) {
- // Ignore the tag.
- return
- }
-
- // Steps 5-6. Find the furthest block.
- var furthestBlock *Node
- for _, e := range p.oe[feIndex:] {
- if isSpecialElement(e) {
- furthestBlock = e
- break
- }
- }
- if furthestBlock == nil {
- e := p.oe.pop()
- for e != formattingElement {
- e = p.oe.pop()
- }
- p.afe.remove(e)
- return
- }
-
- // Steps 7-8. Find the common ancestor and bookmark node.
- commonAncestor := p.oe[feIndex-1]
- bookmark := p.afe.index(formattingElement)
-
- // Step 9. The inner loop. Find the lastNode to reparent.
- lastNode := furthestBlock
- node := furthestBlock
- x := p.oe.index(node)
- // Steps 9.1-9.3.
- for j := 0; j < 3; j++ {
- // Step 9.4.
- x--
- node = p.oe[x]
- // Step 9.5.
- if p.afe.index(node) == -1 {
- p.oe.remove(node)
- continue
- }
- // Step 9.6.
- if node == formattingElement {
- break
- }
- // Step 9.7.
- clone := node.clone()
- p.afe[p.afe.index(node)] = clone
- p.oe[p.oe.index(node)] = clone
- node = clone
- // Step 9.8.
- if lastNode == furthestBlock {
- bookmark = p.afe.index(node) + 1
- }
- // Step 9.9.
- if lastNode.Parent != nil {
- lastNode.Parent.RemoveChild(lastNode)
- }
- node.AppendChild(lastNode)
- // Step 9.10.
- lastNode = node
- }
-
- // Step 10. Reparent lastNode to the common ancestor,
- // or for misnested table nodes, to the foster parent.
- if lastNode.Parent != nil {
- lastNode.Parent.RemoveChild(lastNode)
- }
- switch commonAncestor.DataAtom {
- case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr:
- p.fosterParent(lastNode)
- default:
- commonAncestor.AppendChild(lastNode)
- }
-
- // Steps 11-13. Reparent nodes from the furthest block's children
- // to a clone of the formatting element.
- clone := formattingElement.clone()
- reparentChildren(clone, furthestBlock)
- furthestBlock.AppendChild(clone)
-
- // Step 14. Fix up the list of active formatting elements.
- if oldLoc := p.afe.index(formattingElement); oldLoc != -1 && oldLoc < bookmark {
- // Move the bookmark with the rest of the list.
- bookmark--
- }
- p.afe.remove(formattingElement)
- p.afe.insert(bookmark, clone)
-
- // Step 15. Fix up the stack of open elements.
- p.oe.remove(formattingElement)
- p.oe.insert(p.oe.index(furthestBlock)+1, clone)
- }
-}
-
-// inBodyEndTagOther performs the "any other end tag" algorithm for inBodyIM.
-func (p *parser) inBodyEndTagOther(tagAtom a.Atom) {
- for i := len(p.oe) - 1; i >= 0; i-- {
- if p.oe[i].DataAtom == tagAtom {
- p.oe = p.oe[:i]
- break
- }
- if isSpecialElement(p.oe[i]) {
- break
- }
- }
-}
-
-// Section 12.2.5.4.8.
-func textIM(p *parser) bool {
- switch p.tok.Type {
- case ErrorToken:
- p.oe.pop()
- case TextToken:
- d := p.tok.Data
- if n := p.oe.top(); n.DataAtom == a.Textarea && n.FirstChild == nil {
- // Ignore a newline at the start of a