libgo: Update to weekly.2011-12-22.
From-SVN: r183150
This commit is contained in:
parent
f83fa0bf8f
commit
df4aa89a5e
195 changed files with 3634 additions and 1287 deletions
|
@ -12,9 +12,9 @@ func main() {
|
|||
var t testing.T
|
||||
|
||||
// make sure error mentions that
|
||||
// ch is unexported, not just "ch not found".
|
||||
// name is unexported, not just "name not found".
|
||||
|
||||
t.ch = nil // ERROR "unexported"
|
||||
t.name = nil // ERROR "unexported"
|
||||
|
||||
println(testing.anyLowercaseName("asdf")) // ERROR "unexported" "undefined: testing.anyLowercaseName"
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
82fdc445f2ff
|
||||
4a8268927758
|
||||
|
||||
The first line of this file holds the Mercurial revision number of the
|
||||
last merge done from the master library sources.
|
||||
|
|
|
@ -279,8 +279,7 @@ toolexeclibgoimage_DATA = \
|
|||
image/gif.gox \
|
||||
image/jpeg.gox \
|
||||
image/png.gox \
|
||||
image/tiff.gox \
|
||||
image/ycbcr.gox
|
||||
image/tiff.gox
|
||||
|
||||
toolexeclibgoindexdir = $(toolexeclibgodir)/index
|
||||
|
||||
|
@ -586,7 +585,8 @@ go_image_files = \
|
|||
go/image/format.go \
|
||||
go/image/geom.go \
|
||||
go/image/image.go \
|
||||
go/image/names.go
|
||||
go/image/names.go \
|
||||
go/image/ycbcr.go
|
||||
|
||||
go_io_files = \
|
||||
go/io/multi.go \
|
||||
|
@ -654,10 +654,15 @@ if LIBGO_IS_LINUX
|
|||
go_net_fd_os_file = go/net/fd_linux.go
|
||||
go_net_newpollserver_file = go/net/newpollserver.go
|
||||
else # !LIBGO_IS_LINUX && !LIBGO_IS_RTEMS
|
||||
if LIBGO_IS_NETBSD
|
||||
go_net_fd_os_file = go/net/fd_netbsd.go
|
||||
go_net_newpollserver_file = go/net/newpollserver.go
|
||||
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.go
|
||||
endif # !LIBGO_IS_NETBSD
|
||||
endif # !LIBGO_IS_LINUX
|
||||
endif # !LIBGO_IS_RTEMS
|
||||
|
||||
|
@ -688,8 +693,12 @@ endif
|
|||
if LIBGO_IS_LINUX
|
||||
go_net_interface_file = go/net/interface_linux.go
|
||||
else
|
||||
if LIBGO_IS_NETBSD
|
||||
go_net_interface_file = go/net/interface_netbsd.go
|
||||
else
|
||||
go_net_interface_file = go/net/interface_stub.go
|
||||
endif
|
||||
endif
|
||||
|
||||
go_net_files = \
|
||||
go/net/cgo_unix.go \
|
||||
|
@ -845,6 +854,7 @@ go_strconv_files = \
|
|||
go/strconv/atof.go \
|
||||
go/strconv/atoi.go \
|
||||
go/strconv/decimal.go \
|
||||
go/strconv/extfloat.go \
|
||||
go/strconv/ftoa.go \
|
||||
go/strconv/itoa.go \
|
||||
go/strconv/quote.go
|
||||
|
@ -880,7 +890,8 @@ go_syslog_c_files = \
|
|||
go_testing_files = \
|
||||
go/testing/benchmark.go \
|
||||
go/testing/example.go \
|
||||
go/testing/testing.go
|
||||
go/testing/testing.go \
|
||||
go/testing/wrapper.go
|
||||
|
||||
go_time_files = \
|
||||
go/time/format.go \
|
||||
|
@ -1197,7 +1208,9 @@ go_go_build_files = \
|
|||
go_go_doc_files = \
|
||||
go/go/doc/comment.go \
|
||||
go/go/doc/doc.go \
|
||||
go/go/doc/example.go
|
||||
go/go/doc/example.go \
|
||||
go/go/doc/exports.go \
|
||||
go/go/doc/filter.go
|
||||
go_go_parser_files = \
|
||||
go/go/parser/interface.go \
|
||||
go/go/parser/parser.go
|
||||
|
@ -1241,7 +1254,8 @@ go_image_bmp_files = \
|
|||
go/image/bmp/reader.go
|
||||
|
||||
go_image_color_files = \
|
||||
go/image/color/color.go
|
||||
go/image/color/color.go \
|
||||
go/image/color/ycbcr.go
|
||||
|
||||
go_image_draw_files = \
|
||||
go/image/draw/draw.go
|
||||
|
@ -1266,9 +1280,6 @@ go_image_tiff_files = \
|
|||
go/image/tiff/consts.go \
|
||||
go/image/tiff/reader.go
|
||||
|
||||
go_image_ycbcr_files = \
|
||||
go/image/ycbcr/ycbcr.go
|
||||
|
||||
go_index_suffixarray_files = \
|
||||
go/index/suffixarray/qsufsort.go \
|
||||
go/index/suffixarray/suffixarray.go
|
||||
|
@ -1318,6 +1329,7 @@ go_net_http_files = \
|
|||
go/net/http/filetransport.go \
|
||||
go/net/http/fs.go \
|
||||
go/net/http/header.go \
|
||||
go/net/http/jar.go \
|
||||
go/net/http/lex.go \
|
||||
go/net/http/request.go \
|
||||
go/net/http/response.go \
|
||||
|
@ -1761,7 +1773,6 @@ libgo_go_objs = \
|
|||
image/jpeg.lo \
|
||||
image/png.lo \
|
||||
image/tiff.lo \
|
||||
image/ycbcr.lo \
|
||||
index/suffixarray.lo \
|
||||
io/ioutil.lo \
|
||||
log/syslog.lo \
|
||||
|
@ -3066,16 +3077,6 @@ image/tiff/check: $(CHECK_DEPS)
|
|||
@$(CHECK)
|
||||
.PHONY: image/tiff/check
|
||||
|
||||
@go_include@ image/ycbcr.lo.dep
|
||||
image/ycbcr.lo.dep: $(go_image_ycbcr_files)
|
||||
$(BUILDDEPS)
|
||||
image/ycbcr.lo: $(go_image_ycbcr_files)
|
||||
$(BUILDPACKAGE)
|
||||
image/ycbcr/check: $(CHECK_DEPS)
|
||||
@$(MKDIR_P) image/ycbcr
|
||||
@$(CHECK)
|
||||
.PHONY: image/ycbcr/check
|
||||
|
||||
@go_include@ index/suffixarray.lo.dep
|
||||
index/suffixarray.lo.dep: $(go_index_suffixarray_files)
|
||||
$(BUILDDEPS)
|
||||
|
@ -3728,8 +3729,6 @@ image/png.gox: image/png.lo
|
|||
$(BUILDGOX)
|
||||
image/tiff.gox: image/tiff.lo
|
||||
$(BUILDGOX)
|
||||
image/ycbcr.gox: image/ycbcr.lo
|
||||
$(BUILDGOX)
|
||||
|
||||
index/suffixarray.gox: index/suffixarray.lo
|
||||
$(BUILDGOX)
|
||||
|
@ -3938,11 +3937,11 @@ TEST_PACKAGES = \
|
|||
hash/crc32/check \
|
||||
hash/crc64/check \
|
||||
hash/fnv/check \
|
||||
image/color/check \
|
||||
image/draw/check \
|
||||
image/jpeg/check \
|
||||
image/png/check \
|
||||
image/tiff/check \
|
||||
image/ycbcr/check \
|
||||
index/suffixarray/check \
|
||||
io/ioutil/check \
|
||||
log/syslog/check \
|
||||
|
|
|
@ -167,20 +167,19 @@ am__DEPENDENCIES_2 = bufio/bufio.lo bytes/bytes.lo bytes/index.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/bmp.lo image/color.lo image/draw.lo image/gif.lo \
|
||||
image/jpeg.lo image/png.lo image/tiff.lo image/ycbcr.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/mime.lo mime/multipart.lo net/dict.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 \
|
||||
$(am__DEPENDENCIES_1) os/user.lo os/signal.lo path/filepath.lo \
|
||||
regexp/syntax.lo net/rpc/jsonrpc.lo runtime/debug.lo \
|
||||
runtime/pprof.lo sync/atomic.lo sync/atomic_c.lo \
|
||||
syscall/syscall.lo syscall/errno.lo syscall/wait.lo \
|
||||
text/scanner.lo text/tabwriter.lo text/template.lo \
|
||||
text/template/parse.lo testing/testing.lo testing/iotest.lo \
|
||||
testing/quick.lo testing/script.lo unicode/utf16.lo \
|
||||
unicode/utf8.lo
|
||||
image/jpeg.lo image/png.lo image/tiff.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/mime.lo mime/multipart.lo \
|
||||
net/dict.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 $(am__DEPENDENCIES_1) os/user.lo os/signal.lo \
|
||||
path/filepath.lo regexp/syntax.lo net/rpc/jsonrpc.lo \
|
||||
runtime/debug.lo runtime/pprof.lo sync/atomic.lo \
|
||||
sync/atomic_c.lo syscall/syscall.lo syscall/errno.lo \
|
||||
syscall/wait.lo text/scanner.lo text/tabwriter.lo \
|
||||
text/template.lo text/template/parse.lo testing/testing.lo \
|
||||
testing/iotest.lo testing/quick.lo testing/script.lo \
|
||||
unicode/utf16.lo unicode/utf8.lo
|
||||
libgo_la_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \
|
||||
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
|
||||
$(am__DEPENDENCIES_1)
|
||||
|
@ -732,8 +731,7 @@ toolexeclibgoimage_DATA = \
|
|||
image/gif.gox \
|
||||
image/jpeg.gox \
|
||||
image/png.gox \
|
||||
image/tiff.gox \
|
||||
image/ycbcr.gox
|
||||
image/tiff.gox
|
||||
|
||||
toolexeclibgoindexdir = $(toolexeclibgodir)/index
|
||||
toolexeclibgoindex_DATA = \
|
||||
|
@ -972,7 +970,8 @@ go_image_files = \
|
|||
go/image/format.go \
|
||||
go/image/geom.go \
|
||||
go/image/image.go \
|
||||
go/image/names.go
|
||||
go/image/names.go \
|
||||
go/image/ycbcr.go
|
||||
|
||||
go_io_files = \
|
||||
go/io/multi.go \
|
||||
|
@ -1034,10 +1033,12 @@ go_mime_files = \
|
|||
|
||||
# By default use select with pipes. Most systems should have
|
||||
# something better.
|
||||
@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_RTEMS_FALSE@go_net_fd_os_file = go/net/fd_select.go
|
||||
@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_netbsd.go
|
||||
@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_RTEMS_FALSE@go_net_fd_os_file = go/net/fd_linux.go
|
||||
@LIBGO_IS_RTEMS_TRUE@go_net_fd_os_file = go/net/fd_select.go
|
||||
@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_RTEMS_FALSE@go_net_newpollserver_file = go/net/newpollserver.go
|
||||
@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_RTEMS_FALSE@go_net_newpollserver_file = go/net/newpollserver.go
|
||||
@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_RTEMS_FALSE@go_net_newpollserver_file = go/net/newpollserver.go
|
||||
@LIBGO_IS_LINUX_TRUE@@LIBGO_IS_RTEMS_FALSE@go_net_newpollserver_file = go/net/newpollserver.go
|
||||
@LIBGO_IS_RTEMS_TRUE@go_net_newpollserver_file = go/net/newpollserver_rtems.go
|
||||
@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_cgo_file = go/net/cgo_bsd.go
|
||||
|
@ -1050,7 +1051,8 @@ go_mime_files = \
|
|||
@LIBGO_IS_LINUX_TRUE@go_net_sock_file = go/net/sock_linux.go
|
||||
@LIBGO_IS_LINUX_FALSE@go_net_sendfile_file = go/net/sendfile_stub.go
|
||||
@LIBGO_IS_LINUX_TRUE@go_net_sendfile_file = go/net/sendfile_linux.go
|
||||
@LIBGO_IS_LINUX_FALSE@go_net_interface_file = go/net/interface_stub.go
|
||||
@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@go_net_interface_file = go/net/interface_stub.go
|
||||
@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@go_net_interface_file = go/net/interface_netbsd.go
|
||||
@LIBGO_IS_LINUX_TRUE@go_net_interface_file = go/net/interface_linux.go
|
||||
go_net_files = \
|
||||
go/net/cgo_unix.go \
|
||||
|
@ -1165,6 +1167,7 @@ go_strconv_files = \
|
|||
go/strconv/atof.go \
|
||||
go/strconv/atoi.go \
|
||||
go/strconv/decimal.go \
|
||||
go/strconv/extfloat.go \
|
||||
go/strconv/ftoa.go \
|
||||
go/strconv/itoa.go \
|
||||
go/strconv/quote.go
|
||||
|
@ -1194,7 +1197,8 @@ go_syslog_c_files = \
|
|||
go_testing_files = \
|
||||
go/testing/benchmark.go \
|
||||
go/testing/example.go \
|
||||
go/testing/testing.go
|
||||
go/testing/testing.go \
|
||||
go/testing/wrapper.go
|
||||
|
||||
go_time_files = \
|
||||
go/time/format.go \
|
||||
|
@ -1563,7 +1567,9 @@ go_go_build_files = \
|
|||
go_go_doc_files = \
|
||||
go/go/doc/comment.go \
|
||||
go/go/doc/doc.go \
|
||||
go/go/doc/example.go
|
||||
go/go/doc/example.go \
|
||||
go/go/doc/exports.go \
|
||||
go/go/doc/filter.go
|
||||
|
||||
go_go_parser_files = \
|
||||
go/go/parser/interface.go \
|
||||
|
@ -1614,7 +1620,8 @@ go_image_bmp_files = \
|
|||
go/image/bmp/reader.go
|
||||
|
||||
go_image_color_files = \
|
||||
go/image/color/color.go
|
||||
go/image/color/color.go \
|
||||
go/image/color/ycbcr.go
|
||||
|
||||
go_image_draw_files = \
|
||||
go/image/draw/draw.go
|
||||
|
@ -1639,9 +1646,6 @@ go_image_tiff_files = \
|
|||
go/image/tiff/consts.go \
|
||||
go/image/tiff/reader.go
|
||||
|
||||
go_image_ycbcr_files = \
|
||||
go/image/ycbcr/ycbcr.go
|
||||
|
||||
go_index_suffixarray_files = \
|
||||
go/index/suffixarray/qsufsort.go \
|
||||
go/index/suffixarray/suffixarray.go
|
||||
|
@ -1694,6 +1698,7 @@ go_net_http_files = \
|
|||
go/net/http/filetransport.go \
|
||||
go/net/http/fs.go \
|
||||
go/net/http/header.go \
|
||||
go/net/http/jar.go \
|
||||
go/net/http/lex.go \
|
||||
go/net/http/request.go \
|
||||
go/net/http/response.go \
|
||||
|
@ -2043,7 +2048,6 @@ libgo_go_objs = \
|
|||
image/jpeg.lo \
|
||||
image/png.lo \
|
||||
image/tiff.lo \
|
||||
image/ycbcr.lo \
|
||||
index/suffixarray.lo \
|
||||
io/ioutil.lo \
|
||||
log/syslog.lo \
|
||||
|
@ -2299,11 +2303,11 @@ TEST_PACKAGES = \
|
|||
hash/crc32/check \
|
||||
hash/crc64/check \
|
||||
hash/fnv/check \
|
||||
image/color/check \
|
||||
image/draw/check \
|
||||
image/jpeg/check \
|
||||
image/png/check \
|
||||
image/tiff/check \
|
||||
image/ycbcr/check \
|
||||
index/suffixarray/check \
|
||||
io/ioutil/check \
|
||||
log/syslog/check \
|
||||
|
@ -5657,16 +5661,6 @@ image/tiff/check: $(CHECK_DEPS)
|
|||
@$(CHECK)
|
||||
.PHONY: image/tiff/check
|
||||
|
||||
@go_include@ image/ycbcr.lo.dep
|
||||
image/ycbcr.lo.dep: $(go_image_ycbcr_files)
|
||||
$(BUILDDEPS)
|
||||
image/ycbcr.lo: $(go_image_ycbcr_files)
|
||||
$(BUILDPACKAGE)
|
||||
image/ycbcr/check: $(CHECK_DEPS)
|
||||
@$(MKDIR_P) image/ycbcr
|
||||
@$(CHECK)
|
||||
.PHONY: image/ycbcr/check
|
||||
|
||||
@go_include@ index/suffixarray.lo.dep
|
||||
index/suffixarray.lo.dep: $(go_index_suffixarray_files)
|
||||
$(BUILDDEPS)
|
||||
|
@ -6314,8 +6308,6 @@ image/png.gox: image/png.lo
|
|||
$(BUILDGOX)
|
||||
image/tiff.gox: image/tiff.lo
|
||||
$(BUILDGOX)
|
||||
image/ycbcr.gox: image/ycbcr.lo
|
||||
$(BUILDGOX)
|
||||
|
||||
index/suffixarray.gox: index/suffixarray.lo
|
||||
$(BUILDGOX)
|
||||
|
|
19
libgo/configure
vendored
19
libgo/configure
vendored
|
@ -657,6 +657,8 @@ LIBGO_IS_SOLARIS_FALSE
|
|||
LIBGO_IS_SOLARIS_TRUE
|
||||
LIBGO_IS_RTEMS_FALSE
|
||||
LIBGO_IS_RTEMS_TRUE
|
||||
LIBGO_IS_NETBSD_FALSE
|
||||
LIBGO_IS_NETBSD_TRUE
|
||||
LIBGO_IS_LINUX_FALSE
|
||||
LIBGO_IS_LINUX_TRUE
|
||||
LIBGO_IS_IRIX_FALSE
|
||||
|
@ -11097,7 +11099,7 @@ else
|
|||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<_LT_EOF
|
||||
#line 11100 "configure"
|
||||
#line 11102 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
|
@ -11203,7 +11205,7 @@ else
|
|||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<_LT_EOF
|
||||
#line 11206 "configure"
|
||||
#line 11208 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
|
@ -13473,6 +13475,7 @@ case ${host} in
|
|||
*-*-freebsd*) is_freebsd=yes; GOOS=freebsd ;;
|
||||
*-*-irix6*) is_irix=yes; GOOS=irix ;;
|
||||
*-*-linux*) is_linux=yes; GOOS=linux ;;
|
||||
*-*-netbsd*) is_netbsd=yes; GOOS=netbsd ;;
|
||||
*-*-rtems*) is_rtems=yes; GOOS=rtems ;;
|
||||
*-*-solaris2*) is_solaris=yes; GOOS=solaris ;;
|
||||
esac
|
||||
|
@ -13508,6 +13511,14 @@ else
|
|||
LIBGO_IS_LINUX_FALSE=
|
||||
fi
|
||||
|
||||
if test $is_netbsd = yes; then
|
||||
LIBGO_IS_NETBSD_TRUE=
|
||||
LIBGO_IS_NETBSD_FALSE='#'
|
||||
else
|
||||
LIBGO_IS_NETBSD_TRUE='#'
|
||||
LIBGO_IS_NETBSD_FALSE=
|
||||
fi
|
||||
|
||||
if test $is_rtems = yes; then
|
||||
LIBGO_IS_RTEMS_TRUE=
|
||||
LIBGO_IS_RTEMS_FALSE='#'
|
||||
|
@ -14938,6 +14949,10 @@ if test -z "${LIBGO_IS_LINUX_TRUE}" && test -z "${LIBGO_IS_LINUX_FALSE}"; then
|
|||
as_fn_error "conditional \"LIBGO_IS_LINUX\" was never defined.
|
||||
Usually this means the macro was only invoked conditionally." "$LINENO" 5
|
||||
fi
|
||||
if test -z "${LIBGO_IS_NETBSD_TRUE}" && test -z "${LIBGO_IS_NETBSD_FALSE}"; then
|
||||
as_fn_error "conditional \"LIBGO_IS_NETBSD\" was never defined.
|
||||
Usually this means the macro was only invoked conditionally." "$LINENO" 5
|
||||
fi
|
||||
if test -z "${LIBGO_IS_RTEMS_TRUE}" && test -z "${LIBGO_IS_RTEMS_FALSE}"; then
|
||||
as_fn_error "conditional \"LIBGO_IS_RTEMS\" was never defined.
|
||||
Usually this means the macro was only invoked conditionally." "$LINENO" 5
|
||||
|
|
|
@ -134,6 +134,7 @@ case ${host} in
|
|||
*-*-freebsd*) is_freebsd=yes; GOOS=freebsd ;;
|
||||
*-*-irix6*) is_irix=yes; GOOS=irix ;;
|
||||
*-*-linux*) is_linux=yes; GOOS=linux ;;
|
||||
*-*-netbsd*) is_netbsd=yes; GOOS=netbsd ;;
|
||||
*-*-rtems*) is_rtems=yes; GOOS=rtems ;;
|
||||
*-*-solaris2*) is_solaris=yes; GOOS=solaris ;;
|
||||
esac
|
||||
|
@ -141,6 +142,7 @@ AM_CONDITIONAL(LIBGO_IS_DARWIN, test $is_darwin = yes)
|
|||
AM_CONDITIONAL(LIBGO_IS_FREEBSD, test $is_freebsd = yes)
|
||||
AM_CONDITIONAL(LIBGO_IS_IRIX, test $is_irix = yes)
|
||||
AM_CONDITIONAL(LIBGO_IS_LINUX, test $is_linux = yes)
|
||||
AM_CONDITIONAL(LIBGO_IS_NETBSD, test $is_netbsd = yes)
|
||||
AM_CONDITIONAL(LIBGO_IS_RTEMS, test $is_rtems = yes)
|
||||
AM_CONDITIONAL(LIBGO_IS_SOLARIS, test $is_solaris = yes)
|
||||
AC_SUBST(GOOS)
|
||||
|
|
|
@ -163,10 +163,10 @@ func readTestZip(t *testing.T, zt ZipTest) {
|
|||
done := make(chan bool)
|
||||
for i := 0; i < 5; i++ {
|
||||
for j, ft := range zt.File {
|
||||
go func() {
|
||||
go func(j int, ft ZipTestFile) {
|
||||
readTestFile(t, ft, z.File[j])
|
||||
done <- true
|
||||
}()
|
||||
}(j, ft)
|
||||
n++
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,12 +96,28 @@ func msDosTimeToTime(dosDate, dosTime uint16) time.Time {
|
|||
)
|
||||
}
|
||||
|
||||
// timeToMsDosTime converts a time.Time to an MS-DOS date and time.
|
||||
// The resolution is 2s.
|
||||
// See: http://msdn.microsoft.com/en-us/library/ms724274(v=VS.85).aspx
|
||||
func timeToMsDosTime(t time.Time) (fDate uint16, fTime uint16) {
|
||||
t = t.In(time.UTC)
|
||||
fDate = uint16(t.Day() + int(t.Month())<<5 + (t.Year()-1980)<<9)
|
||||
fTime = uint16(t.Second()/2 + t.Minute()<<5 + t.Hour()<<11)
|
||||
return
|
||||
}
|
||||
|
||||
// ModTime returns the modification time.
|
||||
// The resolution is 2s.
|
||||
func (h *FileHeader) ModTime() time.Time {
|
||||
return msDosTimeToTime(h.ModifiedDate, h.ModifiedTime)
|
||||
}
|
||||
|
||||
// SetModTime sets the ModifiedTime and ModifiedDate fields to the given time.
|
||||
// The resolution is 2s.
|
||||
func (h *FileHeader) SetModTime(t time.Time) {
|
||||
h.ModifiedDate, h.ModifiedTime = timeToMsDosTime(t)
|
||||
}
|
||||
|
||||
// traditional names for Unix constants
|
||||
const (
|
||||
s_IFMT = 0xf000
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type stringReaderAt string
|
||||
|
@ -55,3 +56,13 @@ func TestOver65kFiles(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestModTime(t *testing.T) {
|
||||
var testTime = time.Date(2009, time.November, 10, 23, 45, 58, 0, time.UTC)
|
||||
fh := new(FileHeader)
|
||||
fh.SetModTime(testTime)
|
||||
outTime := fh.ModTime()
|
||||
if !outTime.Equal(testTime) {
|
||||
t.Errorf("times don't match: got %s, want %s", outTime, testTime)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@ const N = 10000 // make this bigger for a larger (and slower) test
|
|||
var data string // test data for write tests
|
||||
var bytes []byte // test data; same as data but as a slice.
|
||||
|
||||
|
||||
func init() {
|
||||
bytes = make([]byte, N)
|
||||
for i := 0; i < N; i++ {
|
||||
|
|
|
@ -289,8 +289,7 @@ func bmIndexByte(b *testing.B, index func([]byte, byte) int, n int) {
|
|||
for i := 0; i < b.N; i++ {
|
||||
j := index(buf, 'x')
|
||||
if j != n-1 {
|
||||
println("bad index", j)
|
||||
panic("bad index")
|
||||
b.Fatal("bad index", j)
|
||||
}
|
||||
}
|
||||
buf[n-1] = '\x00'
|
||||
|
@ -317,7 +316,7 @@ func bmEqual(b *testing.B, equal func([]byte, []byte) bool, n int) {
|
|||
for i := 0; i < b.N; i++ {
|
||||
eq := equal(buf1, buf2)
|
||||
if !eq {
|
||||
panic("bad equal")
|
||||
b.Fatal("bad equal")
|
||||
}
|
||||
}
|
||||
buf1[n-1] = '\x00'
|
||||
|
@ -339,8 +338,7 @@ func bmIndex(b *testing.B, index func([]byte, []byte) int, n int) {
|
|||
for i := 0; i < b.N; i++ {
|
||||
j := index(buf, buf[n-7:])
|
||||
if j != n-7 {
|
||||
println("bad index", j)
|
||||
panic("bad index")
|
||||
b.Fatal("bad index", j)
|
||||
}
|
||||
}
|
||||
buf[n-1] = '\x00'
|
||||
|
@ -362,8 +360,7 @@ func bmIndexEasy(b *testing.B, index func([]byte, []byte) int, n int) {
|
|||
for i := 0; i < b.N; i++ {
|
||||
j := index(buf, buf[n-7:])
|
||||
if j != n-7 {
|
||||
println("bad index", j)
|
||||
panic("bad index")
|
||||
b.Fatal("bad index", j)
|
||||
}
|
||||
}
|
||||
buf[n-1] = '\x00'
|
||||
|
@ -385,8 +382,7 @@ func bmCount(b *testing.B, count func([]byte, []byte) int, n int) {
|
|||
for i := 0; i < b.N; i++ {
|
||||
j := count(buf, buf[n-7:])
|
||||
if j != 1 {
|
||||
println("bad count", j)
|
||||
panic("bad count")
|
||||
b.Fatal("bad count", j)
|
||||
}
|
||||
}
|
||||
buf[n-1] = '\x00'
|
||||
|
@ -408,8 +404,7 @@ func bmCountEasy(b *testing.B, count func([]byte, []byte) int, n int) {
|
|||
for i := 0; i < b.N; i++ {
|
||||
j := count(buf, buf[n-7:])
|
||||
if j != 1 {
|
||||
println("bad count", j)
|
||||
panic("bad count")
|
||||
b.Fatal("bad count", j)
|
||||
}
|
||||
}
|
||||
buf[n-1] = '\x00'
|
||||
|
|
24
libgo/go/bytes/example_test.go
Normal file
24
libgo/go/bytes/example_test.go
Normal file
|
@ -0,0 +1,24 @@
|
|||
package bytes_test
|
||||
|
||||
import (
|
||||
. "bytes"
|
||||
"encoding/base64"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Hello world!
|
||||
func ExampleBuffer() {
|
||||
var b Buffer // A Buffer needs no initialization.
|
||||
b.Write([]byte("Hello "))
|
||||
b.Write([]byte("world!"))
|
||||
b.WriteTo(os.Stdout)
|
||||
}
|
||||
|
||||
// Gophers rule!
|
||||
func ExampleBuffer_reader() {
|
||||
// A Buffer can turn a string or a []byte into an io.Reader.
|
||||
buf := NewBufferString("R29waGVycyBydWxlIQ==")
|
||||
dec := base64.NewDecoder(base64.StdEncoding, buf)
|
||||
io.Copy(os.Stdout, dec)
|
||||
}
|
|
@ -356,7 +356,7 @@ func BenchmarkEncrypt(b *testing.B) {
|
|||
tt := encryptTests[0]
|
||||
c, err := NewCipher(tt.key)
|
||||
if err != nil {
|
||||
panic("NewCipher")
|
||||
b.Fatal("NewCipher:", err)
|
||||
}
|
||||
out := make([]byte, len(tt.in))
|
||||
b.StartTimer()
|
||||
|
|
|
@ -71,3 +71,6 @@ func RegisterHash(h Hash, f func() hash.Hash) {
|
|||
}
|
||||
hashes[h] = f
|
||||
}
|
||||
|
||||
// PrivateKey represents a private key using an unspecified algorithm.
|
||||
type PrivateKey interface{}
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
|
||||
// PublicKeyType is the armor type for a PGP public key.
|
||||
var PublicKeyType = "PGP PUBLIC KEY BLOCK"
|
||||
|
||||
// PrivateKeyType is the armor type for a PGP private key.
|
||||
var PrivateKeyType = "PGP PRIVATE KEY BLOCK"
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build darwin freebsd linux openbsd
|
||||
// +build darwin freebsd linux netbsd openbsd
|
||||
|
||||
// Unix cryptographically secure pseudorandom number
|
||||
// generator.
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
package tls
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"io"
|
||||
"strings"
|
||||
|
@ -255,7 +255,7 @@ func (c *Config) BuildNameToCertificate() {
|
|||
// A Certificate is a chain of one or more certificates, leaf first.
|
||||
type Certificate struct {
|
||||
Certificate [][]byte
|
||||
PrivateKey *rsa.PrivateKey
|
||||
PrivateKey crypto.PrivateKey // supported types: *rsa.PrivateKey
|
||||
// OCSPStaple contains an optional OCSP response which will be served
|
||||
// to clients that request it.
|
||||
OCSPStaple []byte
|
||||
|
|
|
@ -234,7 +234,7 @@ func (c *Conn) clientHandshake() error {
|
|||
digest := make([]byte, 0, 36)
|
||||
digest = finishedHash.serverMD5.Sum(digest)
|
||||
digest = finishedHash.serverSHA1.Sum(digest)
|
||||
signed, err := rsa.SignPKCS1v15(c.config.rand(), c.config.Certificates[0].PrivateKey, crypto.MD5SHA1, digest)
|
||||
signed, err := rsa.SignPKCS1v15(c.config.rand(), c.config.Certificates[0].PrivateKey.(*rsa.PrivateKey), crypto.MD5SHA1, digest)
|
||||
if err != nil {
|
||||
return c.sendAlert(alertInternalError)
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, ckx *clientKe
|
|||
ciphertext = ckx.ciphertext[2:]
|
||||
}
|
||||
|
||||
err = rsa.DecryptPKCS1v15SessionKey(config.rand(), config.Certificates[0].PrivateKey, ciphertext, preMasterSecret)
|
||||
err = rsa.DecryptPKCS1v15SessionKey(config.rand(), config.Certificates[0].PrivateKey.(*rsa.PrivateKey), ciphertext, preMasterSecret)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -147,7 +147,7 @@ Curve:
|
|||
copy(serverECDHParams[4:], ecdhePublic)
|
||||
|
||||
md5sha1 := md5SHA1Hash(clientHello.random, hello.random, serverECDHParams)
|
||||
sig, err := rsa.SignPKCS1v15(config.rand(), config.Certificates[0].PrivateKey, crypto.MD5SHA1, md5sha1)
|
||||
sig, err := rsa.SignPKCS1v15(config.rand(), config.Certificates[0].PrivateKey.(*rsa.PrivateKey), crypto.MD5SHA1, md5sha1)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to sign ECDHE parameters: " + err.Error())
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ package tls
|
|||
// Note: We disable -Werror here because the code in this file uses a deprecated API to stay
|
||||
// compatible with both Mac OS X 10.6 and 10.7. Using a deprecated function on Darwin generates
|
||||
// a warning.
|
||||
#cgo CFLAGS: -Wno-error
|
||||
#cgo CFLAGS: -Wno-error -Wno-deprecated-declarations
|
||||
#cgo LDFLAGS: -framework CoreFoundation -framework Security
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <Security/Security.h>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build plan9
|
||||
// +build plan9 darwin/nocgo
|
||||
|
||||
package tls
|
||||
|
||||
|
|
|
@ -28,6 +28,9 @@ func NewCertPool() *CertPool {
|
|||
// given certificate. If no such certificate can be found or the signature
|
||||
// doesn't match, it returns nil.
|
||||
func (s *CertPool) findVerifiedParents(cert *Certificate) (parents []int) {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
var candidates []int
|
||||
|
||||
if len(cert.AuthorityKeyId) > 0 {
|
||||
|
|
|
@ -19,6 +19,7 @@ type verifyTest struct {
|
|||
roots []string
|
||||
currentTime int64
|
||||
dnsName string
|
||||
nilRoots bool
|
||||
|
||||
errorCallback func(*testing.T, int, error) bool
|
||||
expectedChains [][]string
|
||||
|
@ -45,6 +46,14 @@ var verifyTests = []verifyTest{
|
|||
|
||||
errorCallback: expectHostnameError,
|
||||
},
|
||||
{
|
||||
leaf: googleLeaf,
|
||||
intermediates: []string{thawteIntermediate},
|
||||
nilRoots: true, // verifies that we don't crash
|
||||
currentTime: 1302726541,
|
||||
dnsName: "www.google.com",
|
||||
errorCallback: expectAuthorityUnknown,
|
||||
},
|
||||
{
|
||||
leaf: googleLeaf,
|
||||
intermediates: []string{thawteIntermediate},
|
||||
|
@ -136,6 +145,9 @@ func TestVerify(t *testing.T) {
|
|||
DNSName: test.dnsName,
|
||||
CurrentTime: time.Unix(test.currentTime, 0),
|
||||
}
|
||||
if test.nilRoots {
|
||||
opts.Roots = nil
|
||||
}
|
||||
|
||||
for j, root := range test.roots {
|
||||
ok := opts.Roots.AppendCertsFromPEM([]byte(root))
|
||||
|
|
|
@ -981,6 +981,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub *rsa.P
|
|||
// pemCRLPrefix is the magic string that indicates that we have a PEM encoded
|
||||
// CRL.
|
||||
var pemCRLPrefix = []byte("-----BEGIN X509 CRL")
|
||||
|
||||
// pemType is the type of a PEM encoded CRL.
|
||||
var pemType = "X509 CRL"
|
||||
|
||||
|
|
|
@ -13,7 +13,8 @@ import (
|
|||
|
||||
func dotest() bool {
|
||||
// For now, only works on ELF platforms.
|
||||
return syscall.OS == "linux" && os.Getenv("GOARCH") == "amd64"
|
||||
// TODO: convert to work with new go tool
|
||||
return false && syscall.OS == "linux" && os.Getenv("GOARCH") == "amd64"
|
||||
}
|
||||
|
||||
func getTable(t *testing.T) *Table {
|
||||
|
|
|
@ -171,11 +171,42 @@ func (br *byteSliceReader) Read(p []byte) (int, error) {
|
|||
return n, nil
|
||||
}
|
||||
|
||||
func BenchmarkRead(b *testing.B) {
|
||||
func BenchmarkReadSlice1000Int32s(b *testing.B) {
|
||||
bsr := &byteSliceReader{}
|
||||
slice := make([]int32, 1000)
|
||||
buf := make([]byte, len(slice)*4)
|
||||
b.SetBytes(int64(len(buf)))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
bsr.remain = buf
|
||||
Read(bsr, BigEndian, slice)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkReadStruct(b *testing.B) {
|
||||
bsr := &byteSliceReader{}
|
||||
var buf bytes.Buffer
|
||||
Write(&buf, BigEndian, &s)
|
||||
n := TotalSize(reflect.ValueOf(s))
|
||||
b.SetBytes(int64(n))
|
||||
t := s
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
bsr.remain = buf.Bytes()
|
||||
Read(bsr, BigEndian, &t)
|
||||
}
|
||||
b.StopTimer()
|
||||
if !reflect.DeepEqual(s, t) {
|
||||
b.Fatal("no match")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkReadInts(b *testing.B) {
|
||||
var ls Struct
|
||||
bsr := &byteSliceReader{}
|
||||
var r io.Reader = bsr
|
||||
|
||||
b.SetBytes(2 * (1 + 2 + 4 + 8))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
bsr.remain = big
|
||||
Read(r, BigEndian, &ls.Int8)
|
||||
|
@ -196,25 +227,19 @@ func BenchmarkRead(b *testing.B) {
|
|||
for i := range want.Array {
|
||||
want.Array[i] = 0
|
||||
}
|
||||
b.StopTimer()
|
||||
if !reflect.DeepEqual(ls, want) {
|
||||
panic("no match")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkWrite(b *testing.B) {
|
||||
func BenchmarkWriteInts(b *testing.B) {
|
||||
buf := new(bytes.Buffer)
|
||||
var w io.Writer = buf
|
||||
|
||||
b.SetBytes(2 * (1 + 2 + 4 + 8))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
buf.Reset()
|
||||
Write(w, BigEndian, &s.Int8)
|
||||
Write(w, BigEndian, &s.Int16)
|
||||
Write(w, BigEndian, &s.Int32)
|
||||
Write(w, BigEndian, &s.Int64)
|
||||
Write(w, BigEndian, &s.Uint8)
|
||||
Write(w, BigEndian, &s.Uint16)
|
||||
Write(w, BigEndian, &s.Uint32)
|
||||
Write(w, BigEndian, &s.Uint64)
|
||||
Write(w, BigEndian, s.Int8)
|
||||
Write(w, BigEndian, s.Int16)
|
||||
Write(w, BigEndian, s.Int32)
|
||||
|
@ -224,11 +249,8 @@ func BenchmarkWrite(b *testing.B) {
|
|||
Write(w, BigEndian, s.Uint32)
|
||||
Write(w, BigEndian, s.Uint64)
|
||||
}
|
||||
|
||||
if !bytes.Equal(buf.Bytes()[:30], big[:30]) {
|
||||
panic("first half doesn't match")
|
||||
}
|
||||
if !bytes.Equal(buf.Bytes()[30:], big[:30]) {
|
||||
panic("second half doesn't match")
|
||||
b.StopTimer()
|
||||
if !bytes.Equal(buf.Bytes(), big[:30]) {
|
||||
b.Fatalf("first half doesn't match: %x %x", buf.Bytes(), big[:30])
|
||||
}
|
||||
}
|
||||
|
|
|
@ -165,6 +165,7 @@ func TestNonCanonicalZero(t *testing.T) {
|
|||
|
||||
func BenchmarkPutUvarint32(b *testing.B) {
|
||||
buf := make([]byte, MaxVarintLen32)
|
||||
b.SetBytes(4)
|
||||
for i := 0; i < b.N; i++ {
|
||||
for j := uint(0); j < MaxVarintLen32; j++ {
|
||||
PutUvarint(buf, 1<<(j*7))
|
||||
|
@ -174,6 +175,7 @@ func BenchmarkPutUvarint32(b *testing.B) {
|
|||
|
||||
func BenchmarkPutUvarint64(b *testing.B) {
|
||||
buf := make([]byte, MaxVarintLen64)
|
||||
b.SetBytes(8)
|
||||
for i := 0; i < b.N; i++ {
|
||||
for j := uint(0); j < MaxVarintLen64; j++ {
|
||||
PutUvarint(buf, 1<<(j*7))
|
||||
|
|
|
@ -102,12 +102,15 @@ func TestIntCodec(t *testing.T) {
|
|||
|
||||
// The result of encoding a true boolean with field number 7
|
||||
var boolResult = []byte{0x07, 0x01}
|
||||
|
||||
// The result of encoding a number 17 with field number 7
|
||||
var signedResult = []byte{0x07, 2 * 17}
|
||||
var unsignedResult = []byte{0x07, 17}
|
||||
var floatResult = []byte{0x07, 0xFE, 0x31, 0x40}
|
||||
|
||||
// The result of encoding a number 17+19i with field number 7
|
||||
var complexResult = []byte{0x07, 0xFE, 0x31, 0x40, 0xFE, 0x33, 0x40}
|
||||
|
||||
// The result of encoding "hello" with field number 7
|
||||
var bytesResult = []byte{0x07, 0x05, 'h', 'e', 'l', 'l', 'o'}
|
||||
|
||||
|
|
|
@ -469,7 +469,14 @@ func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv reflect.Value) {
|
|||
// isZero returns whether the value is the zero of its type.
|
||||
func isZero(val reflect.Value) bool {
|
||||
switch val.Kind() {
|
||||
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
|
||||
case reflect.Array:
|
||||
for i := 0; i < val.Len(); i++ {
|
||||
if !isZero(val.Index(i)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
case reflect.Map, reflect.Slice, reflect.String:
|
||||
return val.Len() == 0
|
||||
case reflect.Bool:
|
||||
return !val.Bool()
|
||||
|
@ -483,6 +490,13 @@ func isZero(val reflect.Value) bool {
|
|||
return val.Float() == 0
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
return val.Uint() == 0
|
||||
case reflect.Struct:
|
||||
for i := 0; i < val.NumField(); i++ {
|
||||
if !isZero(val.Field(i)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
panic("unknown type in isZero " + val.Type().String())
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"io"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Types that implement the GobEncoder/Decoder interfaces.
|
||||
|
@ -526,3 +527,50 @@ func TestGobEncoderExtraIndirect(t *testing.T) {
|
|||
t.Errorf("got = %q, want %q", got, gdb)
|
||||
}
|
||||
}
|
||||
|
||||
// Another bug: this caused a crash with the new Go1 Time type.
|
||||
// We throw in a gob-encoding array, to test another case of isZero
|
||||
|
||||
type isZeroBug struct {
|
||||
T time.Time
|
||||
S string
|
||||
I int
|
||||
A isZeroBugArray
|
||||
}
|
||||
|
||||
type isZeroBugArray [2]uint8
|
||||
|
||||
// Receiver is value, not pointer, to test isZero of array.
|
||||
func (a isZeroBugArray) GobEncode() (b []byte, e error) {
|
||||
b = append(b, a[:]...)
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (a *isZeroBugArray) GobDecode(data []byte) error {
|
||||
println("DECODE")
|
||||
if len(data) != len(a) {
|
||||
return io.EOF
|
||||
}
|
||||
a[0] = data[0]
|
||||
a[1] = data[1]
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestGobEncodeIsZero(t *testing.T) {
|
||||
x := isZeroBug{time.Now(), "hello", -55, isZeroBugArray{1, 2}}
|
||||
b := new(bytes.Buffer)
|
||||
enc := NewEncoder(b)
|
||||
err := enc.Encode(x)
|
||||
if err != nil {
|
||||
t.Fatal("encode:", err)
|
||||
}
|
||||
var y isZeroBug
|
||||
dec := NewDecoder(b)
|
||||
err = dec.Decode(&y)
|
||||
if err != nil {
|
||||
t.Fatal("decode:", err)
|
||||
}
|
||||
if x != y {
|
||||
t.Fatalf("%v != %v", x, y)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ func benchmarkEndToEnd(r io.Reader, w io.Writer, b *testing.B) {
|
|||
func BenchmarkEndToEndPipe(b *testing.B) {
|
||||
r, w, err := os.Pipe()
|
||||
if err != nil {
|
||||
panic("can't get pipe:" + err.Error())
|
||||
b.Fatal("can't get pipe:", err)
|
||||
}
|
||||
benchmarkEndToEnd(r, w, b)
|
||||
}
|
||||
|
|
|
@ -130,6 +130,7 @@ func userType(rt reflect.Type) *userTypeInfo {
|
|||
}
|
||||
return ut
|
||||
}
|
||||
|
||||
// A typeId represents a gob Type as an integer that can be passed on the wire.
|
||||
// Internally, typeIds are used as keys to a map to recover the underlying type info.
|
||||
type typeId int32
|
||||
|
|
|
@ -84,7 +84,7 @@ func BenchmarkCodeEncoder(b *testing.B) {
|
|||
enc := NewEncoder(ioutil.Discard)
|
||||
for i := 0; i < b.N; i++ {
|
||||
if err := enc.Encode(&codeStruct); err != nil {
|
||||
panic(err)
|
||||
b.Fatal("Encode:", err)
|
||||
}
|
||||
}
|
||||
b.SetBytes(int64(len(codeJSON)))
|
||||
|
@ -98,7 +98,7 @@ func BenchmarkCodeMarshal(b *testing.B) {
|
|||
}
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := Marshal(&codeStruct); err != nil {
|
||||
panic(err)
|
||||
b.Fatal("Marshal:", err)
|
||||
}
|
||||
}
|
||||
b.SetBytes(int64(len(codeJSON)))
|
||||
|
@ -120,7 +120,7 @@ func BenchmarkCodeDecoder(b *testing.B) {
|
|||
buf.WriteByte('\n')
|
||||
buf.WriteByte('\n')
|
||||
if err := dec.Decode(&r); err != nil {
|
||||
panic(err)
|
||||
b.Fatal("Decode:", err)
|
||||
}
|
||||
}
|
||||
b.SetBytes(int64(len(codeJSON)))
|
||||
|
@ -135,7 +135,7 @@ func BenchmarkCodeUnmarshal(b *testing.B) {
|
|||
for i := 0; i < b.N; i++ {
|
||||
var r codeResponse
|
||||
if err := Unmarshal(codeJSON, &r); err != nil {
|
||||
panic(err)
|
||||
b.Fatal("Unmmarshal:", err)
|
||||
}
|
||||
}
|
||||
b.SetBytes(int64(len(codeJSON)))
|
||||
|
@ -150,7 +150,7 @@ func BenchmarkCodeUnmarshalReuse(b *testing.B) {
|
|||
var r codeResponse
|
||||
for i := 0; i < b.N; i++ {
|
||||
if err := Unmarshal(codeJSON, &r); err != nil {
|
||||
panic(err)
|
||||
b.Fatal("Unmmarshal:", err)
|
||||
}
|
||||
}
|
||||
b.SetBytes(int64(len(codeJSON)))
|
||||
|
|
|
@ -228,7 +228,9 @@ func (d *decodeState) value(v reflect.Value) {
|
|||
// Feed in an empty string - the shortest, simplest value -
|
||||
// so that it knows we got to the end of the value.
|
||||
if d.scan.redo {
|
||||
panic("redo")
|
||||
// rewind.
|
||||
d.scan.redo = false
|
||||
d.scan.step = stateBeginValue
|
||||
}
|
||||
d.scan.step(&d.scan, '"')
|
||||
d.scan.step(&d.scan, '"')
|
||||
|
@ -317,25 +319,22 @@ func (d *decodeState) array(v reflect.Value) {
|
|||
}
|
||||
v = pv
|
||||
|
||||
// Decoding into nil interface? Switch to non-reflect code.
|
||||
iv := v
|
||||
ok := iv.Kind() == reflect.Interface
|
||||
if ok {
|
||||
iv.Set(reflect.ValueOf(d.arrayInterface()))
|
||||
return
|
||||
}
|
||||
|
||||
// Check type of target.
|
||||
av := v
|
||||
if av.Kind() != reflect.Array && av.Kind() != reflect.Slice {
|
||||
switch v.Kind() {
|
||||
default:
|
||||
d.saveError(&UnmarshalTypeError{"array", v.Type()})
|
||||
d.off--
|
||||
d.next()
|
||||
return
|
||||
case reflect.Interface:
|
||||
// Decoding into nil interface? Switch to non-reflect code.
|
||||
v.Set(reflect.ValueOf(d.arrayInterface()))
|
||||
return
|
||||
case reflect.Array:
|
||||
case reflect.Slice:
|
||||
break
|
||||
}
|
||||
|
||||
sv := v
|
||||
|
||||
i := 0
|
||||
for {
|
||||
// Look ahead for ] - can only happen on first iteration.
|
||||
|
@ -349,23 +348,25 @@ func (d *decodeState) array(v reflect.Value) {
|
|||
d.scan.undo(op)
|
||||
|
||||
// Get element of array, growing if necessary.
|
||||
if i >= av.Cap() && sv.IsValid() {
|
||||
newcap := sv.Cap() + sv.Cap()/2
|
||||
if newcap < 4 {
|
||||
newcap = 4
|
||||
if v.Kind() == reflect.Slice {
|
||||
// Grow slice if necessary
|
||||
if i >= v.Cap() {
|
||||
newcap := v.Cap() + v.Cap()/2
|
||||
if newcap < 4 {
|
||||
newcap = 4
|
||||
}
|
||||
newv := reflect.MakeSlice(v.Type(), v.Len(), newcap)
|
||||
reflect.Copy(newv, v)
|
||||
v.Set(newv)
|
||||
}
|
||||
if i >= v.Len() {
|
||||
v.SetLen(i + 1)
|
||||
}
|
||||
newv := reflect.MakeSlice(sv.Type(), sv.Len(), newcap)
|
||||
reflect.Copy(newv, sv)
|
||||
sv.Set(newv)
|
||||
}
|
||||
if i >= av.Len() && sv.IsValid() {
|
||||
// Must be slice; gave up on array during i >= av.Cap().
|
||||
sv.SetLen(i + 1)
|
||||
}
|
||||
|
||||
// Decode into element.
|
||||
if i < av.Len() {
|
||||
d.value(av.Index(i))
|
||||
if i < v.Len() {
|
||||
// Decode into element.
|
||||
d.value(v.Index(i))
|
||||
} else {
|
||||
// Ran out of fixed array: skip.
|
||||
d.value(reflect.Value{})
|
||||
|
@ -382,19 +383,19 @@ func (d *decodeState) array(v reflect.Value) {
|
|||
}
|
||||
}
|
||||
|
||||
if i < av.Len() {
|
||||
if !sv.IsValid() {
|
||||
if i < v.Len() {
|
||||
if v.Kind() == reflect.Array {
|
||||
// Array. Zero the rest.
|
||||
z := reflect.Zero(av.Type().Elem())
|
||||
for ; i < av.Len(); i++ {
|
||||
av.Index(i).Set(z)
|
||||
z := reflect.Zero(v.Type().Elem())
|
||||
for ; i < v.Len(); i++ {
|
||||
v.Index(i).Set(z)
|
||||
}
|
||||
} else {
|
||||
sv.SetLen(i)
|
||||
v.SetLen(i)
|
||||
}
|
||||
}
|
||||
if i == 0 && av.Kind() == reflect.Slice && sv.IsNil() {
|
||||
sv.Set(reflect.MakeSlice(sv.Type(), 0, 0))
|
||||
if i == 0 && v.Kind() == reflect.Slice {
|
||||
v.Set(reflect.MakeSlice(v.Type(), 0, 0))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ package json
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
@ -73,6 +74,12 @@ var unmarshalTests = []unmarshalTest{
|
|||
|
||||
// syntax errors
|
||||
{`{"X": "foo", "Y"}`, nil, nil, &SyntaxError{"invalid character '}' after object key", 17}},
|
||||
{`[1, 2, 3+]`, nil, nil, &SyntaxError{"invalid character '+' after array element", 9}},
|
||||
|
||||
// array tests
|
||||
{`[1, 2, 3]`, new([3]int), [3]int{1, 2, 3}, nil},
|
||||
{`[1, 2, 3]`, new([1]int), [1]int{1}, nil},
|
||||
{`[1, 2, 3]`, new([5]int), [5]int{1, 2, 3, 0, 0}, nil},
|
||||
|
||||
// composite tests
|
||||
{allValueIndent, new(All), allValue, nil},
|
||||
|
@ -242,6 +249,38 @@ func TestHTMLEscape(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// WrongString is a struct that's misusing the ,string modifier.
|
||||
type WrongString struct {
|
||||
Message string `json:"result,string"`
|
||||
}
|
||||
|
||||
type wrongStringTest struct {
|
||||
in, err string
|
||||
}
|
||||
|
||||
// TODO(bradfitz): as part of Issue 2331, fix these tests' expected
|
||||
// error values to be helpful, rather than the confusing messages they
|
||||
// are now.
|
||||
var wrongStringTests = []wrongStringTest{
|
||||
{`{"result":"x"}`, "JSON decoder out of sync - data changing underfoot?"},
|
||||
{`{"result":"foo"}`, "json: cannot unmarshal bool into Go value of type string"},
|
||||
{`{"result":"123"}`, "json: cannot unmarshal number into Go value of type string"},
|
||||
}
|
||||
|
||||
// If people misuse the ,string modifier, the error message should be
|
||||
// helpful, telling the user that they're doing it wrong.
|
||||
func TestErrorMessageFromMisusedString(t *testing.T) {
|
||||
for n, tt := range wrongStringTests {
|
||||
r := strings.NewReader(tt.in)
|
||||
var s WrongString
|
||||
err := NewDecoder(r).Decode(&s)
|
||||
got := fmt.Sprintf("%v", err)
|
||||
if got != tt.err {
|
||||
t.Errorf("%d. got err = %q, want %q", n, got, tt.err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func noSpace(c rune) rune {
|
||||
if isSpace(c) {
|
||||
return -1
|
||||
|
|
|
@ -197,6 +197,7 @@ var hex = "0123456789abcdef"
|
|||
// An encodeState encodes JSON into a bytes.Buffer.
|
||||
type encodeState struct {
|
||||
bytes.Buffer // accumulated output
|
||||
scratch [64]byte
|
||||
}
|
||||
|
||||
func (e *encodeState) marshal(v interface{}) (err error) {
|
||||
|
@ -275,14 +276,26 @@ func (e *encodeState) reflectValueQuoted(v reflect.Value, quoted bool) {
|
|||
}
|
||||
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
writeString(e, strconv.FormatInt(v.Int(), 10))
|
||||
|
||||
b := strconv.AppendInt(e.scratch[:0], v.Int(), 10)
|
||||
if quoted {
|
||||
writeString(e, string(b))
|
||||
} else {
|
||||
e.Write(b)
|
||||
}
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
writeString(e, strconv.FormatUint(v.Uint(), 10))
|
||||
|
||||
b := strconv.AppendUint(e.scratch[:0], v.Uint(), 10)
|
||||
if quoted {
|
||||
writeString(e, string(b))
|
||||
} else {
|
||||
e.Write(b)
|
||||
}
|
||||
case reflect.Float32, reflect.Float64:
|
||||
writeString(e, strconv.FormatFloat(v.Float(), 'g', -1, v.Type().Bits()))
|
||||
|
||||
b := strconv.AppendFloat(e.scratch[:0], v.Float(), 'g', -1, v.Type().Bits())
|
||||
if quoted {
|
||||
writeString(e, string(b))
|
||||
} else {
|
||||
e.Write(b)
|
||||
}
|
||||
case reflect.String:
|
||||
if quoted {
|
||||
sb, err := Marshal(v.String())
|
||||
|
|
|
@ -394,7 +394,7 @@ func TestUnmarshal(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Errorf("#%d: unexpected error: %#v", i, err)
|
||||
} else if got, want := dest, test.Value; !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("#%d: unmarshal(%#s) = %#v, want %#v", i, test.ExpectXML, got, want)
|
||||
t.Errorf("#%d: unmarshal(%q) = %#v, want %#v", i, test.ExpectXML, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 linux
|
||||
|
||||
package inotify
|
||||
|
||||
import (
|
||||
|
@ -17,6 +19,9 @@ func TestInotifyEvents(t *testing.T) {
|
|||
t.Fatalf("NewWatcher() failed: %s", err)
|
||||
}
|
||||
|
||||
t.Logf("NEEDS TO BE CONVERTED TO NEW GO TOOL") // TODO
|
||||
return
|
||||
|
||||
// Add a watch for "_test"
|
||||
err = watcher.Watch("_test")
|
||||
if err != nil {
|
||||
|
|
|
@ -22,10 +22,10 @@ var drivers = make(map[string]driver.Driver)
|
|||
// it panics.
|
||||
func Register(name string, driver driver.Driver) {
|
||||
if driver == nil {
|
||||
panic("db: Register driver is nil")
|
||||
panic("sql: Register driver is nil")
|
||||
}
|
||||
if _, dup := drivers[name]; dup {
|
||||
panic("db: Register called twice for driver " + name)
|
||||
panic("sql: Register called twice for driver " + name)
|
||||
}
|
||||
drivers[name] = driver
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ type ScannerInto interface {
|
|||
// ErrNoRows is returned by Scan when QueryRow doesn't return a
|
||||
// row. In such a case, QueryRow returns a placeholder *Row value that
|
||||
// defers this error until a Scan.
|
||||
var ErrNoRows = errors.New("db: no rows in result set")
|
||||
var ErrNoRows = errors.New("sql: no rows in result set")
|
||||
|
||||
// DB is a database handle. It's safe for concurrent use by multiple
|
||||
// goroutines.
|
||||
|
@ -102,7 +102,7 @@ type DB struct {
|
|||
func Open(driverName, dataSourceName string) (*DB, error) {
|
||||
driver, ok := drivers[driverName]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("db: unknown driver %q (forgotten import?)", driverName)
|
||||
return nil, fmt.Errorf("sql: unknown driver %q (forgotten import?)", driverName)
|
||||
}
|
||||
return &DB{driver: driver, dsn: dataSourceName}, nil
|
||||
}
|
||||
|
@ -514,7 +514,7 @@ func (s *Stmt) Exec(args ...interface{}) (Result, error) {
|
|||
// 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("db: expected %d arguments, got %d", want, len(args))
|
||||
return nil, fmt.Errorf("sql: expected %d arguments, got %d", want, len(args))
|
||||
}
|
||||
|
||||
// Convert args to subset types.
|
||||
|
@ -522,10 +522,10 @@ func (s *Stmt) Exec(args ...interface{}) (Result, error) {
|
|||
for n, arg := range args {
|
||||
args[n], err = cc.ColumnConverter(n).ConvertValue(arg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("db: converting Exec argument #%d's type: %v", n, err)
|
||||
return nil, fmt.Errorf("sql: converting Exec argument #%d's type: %v", n, err)
|
||||
}
|
||||
if !driver.IsParameterSubsetType(args[n]) {
|
||||
return nil, fmt.Errorf("db: driver ColumnConverter error converted %T to unsupported type %T",
|
||||
return nil, fmt.Errorf("sql: driver ColumnConverter error converted %T to unsupported type %T",
|
||||
arg, args[n])
|
||||
}
|
||||
}
|
||||
|
@ -533,7 +533,7 @@ func (s *Stmt) Exec(args ...interface{}) (Result, error) {
|
|||
for n, arg := range args {
|
||||
args[n], err = driver.DefaultParameterConverter.ConvertValue(arg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("db: converting Exec argument #%d's type: %v", n, err)
|
||||
return nil, fmt.Errorf("sql: converting Exec argument #%d's type: %v", n, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -555,7 +555,7 @@ func (s *Stmt) connStmt() (ci driver.Conn, releaseConn func(), si driver.Stmt, e
|
|||
s.mu.Lock()
|
||||
if s.closed {
|
||||
s.mu.Unlock()
|
||||
err = errors.New("db: statement is closed")
|
||||
err = errors.New("sql: statement is closed")
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -617,7 +617,7 @@ func (s *Stmt) Query(args ...interface{}) (*Rows, error) {
|
|||
// 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("db: statement expects %d inputs; got %d", si.NumInput(), len(args))
|
||||
return nil, fmt.Errorf("sql: statement expects %d inputs; got %d", si.NumInput(), len(args))
|
||||
}
|
||||
sargs, err := subsetTypeArgs(args)
|
||||
if err != nil {
|
||||
|
@ -737,27 +737,40 @@ func (rs *Rows) Err() error {
|
|||
return rs.lasterr
|
||||
}
|
||||
|
||||
// Columns returns the column names.
|
||||
// Columns returns an error if the rows are closed, or if the rows
|
||||
// are from QueryRow and there was a deferred error.
|
||||
func (rs *Rows) Columns() ([]string, error) {
|
||||
if rs.closed {
|
||||
return nil, errors.New("sql: Rows are closed")
|
||||
}
|
||||
if rs.rowsi == nil {
|
||||
return nil, errors.New("sql: no Rows available")
|
||||
}
|
||||
return rs.rowsi.Columns(), nil
|
||||
}
|
||||
|
||||
// Scan copies the columns in the current row into the values pointed
|
||||
// at by dest. If dest contains pointers to []byte, the slices should
|
||||
// not be modified and should only be considered valid until the next
|
||||
// call to Next or Scan.
|
||||
func (rs *Rows) Scan(dest ...interface{}) error {
|
||||
if rs.closed {
|
||||
return errors.New("db: Rows closed")
|
||||
return errors.New("sql: Rows closed")
|
||||
}
|
||||
if rs.lasterr != nil {
|
||||
return rs.lasterr
|
||||
}
|
||||
if rs.lastcols == nil {
|
||||
return errors.New("db: Scan called without calling Next")
|
||||
return errors.New("sql: Scan called without calling Next")
|
||||
}
|
||||
if len(dest) != len(rs.lastcols) {
|
||||
return fmt.Errorf("db: expected %d destination arguments in Scan, not %d", len(rs.lastcols), len(dest))
|
||||
return fmt.Errorf("sql: expected %d destination arguments in Scan, not %d", len(rs.lastcols), len(dest))
|
||||
}
|
||||
for i, sv := range rs.lastcols {
|
||||
err := convertAssign(dest[i], sv)
|
||||
if err != nil {
|
||||
return fmt.Errorf("db: Scan error on column index %d: %v", i, err)
|
||||
return fmt.Errorf("sql: Scan error on column index %d: %v", i, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -75,6 +75,23 @@ func TestQuery(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestRowsColumns(t *testing.T) {
|
||||
db := newTestDB(t, "people")
|
||||
defer closeDB(t, db)
|
||||
rows, err := db.Query("SELECT|people|age,name|")
|
||||
if err != nil {
|
||||
t.Fatalf("Query: %v", err)
|
||||
}
|
||||
cols, err := rows.Columns()
|
||||
if err != nil {
|
||||
t.Fatalf("Columns: %v", err)
|
||||
}
|
||||
want := []string{"age", "name"}
|
||||
if !reflect.DeepEqual(cols, want) {
|
||||
t.Errorf("got %#v; want %#v", cols, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestQueryRow(t *testing.T) {
|
||||
db := newTestDB(t, "people")
|
||||
defer closeDB(t, db)
|
||||
|
@ -187,12 +204,12 @@ func TestExec(t *testing.T) {
|
|||
{[]interface{}{7, 9}, ""},
|
||||
|
||||
// Invalid conversions:
|
||||
{[]interface{}{"Brad", int64(0xFFFFFFFF)}, "db: converting Exec argument #1's type: sql/driver: value 4294967295 overflows int32"},
|
||||
{[]interface{}{"Brad", "strconv fail"}, "db: converting Exec argument #1's type: sql/driver: value \"strconv fail\" can't be converted to int32"},
|
||||
{[]interface{}{"Brad", int64(0xFFFFFFFF)}, "sql: converting Exec argument #1's type: sql/driver: value 4294967295 overflows int32"},
|
||||
{[]interface{}{"Brad", "strconv fail"}, "sql: converting Exec argument #1's type: sql/driver: value \"strconv fail\" can't be converted to int32"},
|
||||
|
||||
// Wrong number of args:
|
||||
{[]interface{}{}, "db: expected 2 arguments, got 0"},
|
||||
{[]interface{}{1, 2, 3}, "db: expected 2 arguments, got 3"},
|
||||
{[]interface{}{}, "sql: expected 2 arguments, got 0"},
|
||||
{[]interface{}{1, 2, 3}, "sql: expected 2 arguments, got 3"},
|
||||
}
|
||||
for n, et := range execTests {
|
||||
_, err := stmt.Exec(et.args...)
|
||||
|
|
|
@ -283,8 +283,8 @@ func (p *publickeyAuth) method() string {
|
|||
return "publickey"
|
||||
}
|
||||
|
||||
// ClientAuthPublickey returns a ClientAuth using public key authentication.
|
||||
func ClientAuthPublickey(impl ClientKeyring) ClientAuth {
|
||||
// ClientAuthKeyring returns a ClientAuth using public key authentication.
|
||||
func ClientAuthKeyring(impl ClientKeyring) ClientAuth {
|
||||
return &publickeyAuth{impl}
|
||||
}
|
||||
|
||||
|
|
|
@ -122,7 +122,7 @@ var (
|
|||
PasswordCallback: func(user, pass string) bool {
|
||||
return user == "testuser" && pass == string(clientPassword)
|
||||
},
|
||||
PubKeyCallback: func(user, algo string, pubkey []byte) bool {
|
||||
PublicKeyCallback: func(user, algo string, pubkey []byte) bool {
|
||||
key := clientKeychain.keys[0].(*rsa.PrivateKey).PublicKey
|
||||
expected := []byte(serializePublickey(key))
|
||||
algoname := algoName(key)
|
||||
|
@ -179,7 +179,7 @@ func TestClientAuthPublickey(t *testing.T) {
|
|||
config := &ClientConfig{
|
||||
User: "testuser",
|
||||
Auth: []ClientAuth{
|
||||
ClientAuthPublickey(clientKeychain),
|
||||
ClientAuthKeyring(clientKeychain),
|
||||
},
|
||||
}
|
||||
c, err := Dial("tcp", newMockAuthServer(t), config)
|
||||
|
@ -210,7 +210,7 @@ func TestClientAuthWrongPassword(t *testing.T) {
|
|||
User: "testuser",
|
||||
Auth: []ClientAuth{
|
||||
ClientAuthPassword(wrongPw),
|
||||
ClientAuthPublickey(clientKeychain),
|
||||
ClientAuthKeyring(clientKeychain),
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -228,7 +228,7 @@ func TestClientAuthInvalidPublickey(t *testing.T) {
|
|||
config := &ClientConfig{
|
||||
User: "testuser",
|
||||
Auth: []ClientAuth{
|
||||
ClientAuthPublickey(kc),
|
||||
ClientAuthKeyring(kc),
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -246,7 +246,7 @@ func TestClientAuthRSAandDSA(t *testing.T) {
|
|||
config := &ClientConfig{
|
||||
User: "testuser",
|
||||
Auth: []ClientAuth{
|
||||
ClientAuthPublickey(kc),
|
||||
ClientAuthKeyring(kc),
|
||||
},
|
||||
}
|
||||
c, err := Dial("tcp", newMockAuthServer(t), config)
|
||||
|
|
|
@ -50,7 +50,7 @@ func TestFuncPublickeyAuth(t *testing.T) {
|
|||
config := &ClientConfig{
|
||||
User: *sshuser,
|
||||
Auth: []ClientAuth{
|
||||
ClientAuthPublickey(kc),
|
||||
ClientAuthKeyring(kc),
|
||||
},
|
||||
}
|
||||
conn, err := Dial("tcp", "localhost:22", config)
|
||||
|
|
|
@ -36,10 +36,10 @@ type ServerConfig struct {
|
|||
// several goroutines.
|
||||
PasswordCallback func(user, password string) bool
|
||||
|
||||
// PubKeyCallback, if non-nil, is called when a client attempts public
|
||||
// PublicKeyCallback, if non-nil, is called when a client attempts public
|
||||
// key authentication. It must return true iff the given public key is
|
||||
// valid for the given user.
|
||||
PubKeyCallback func(user, algo string, pubkey []byte) bool
|
||||
PublicKeyCallback func(user, algo string, pubkey []byte) bool
|
||||
|
||||
// Cryptographic-related configuration.
|
||||
Crypto CryptoConfig
|
||||
|
@ -359,7 +359,7 @@ func isAcceptableAlgo(algo string) bool {
|
|||
|
||||
// testPubKey returns true if the given public key is acceptable for the user.
|
||||
func (s *ServerConn) testPubKey(user, algo string, pubKey []byte) bool {
|
||||
if s.config.PubKeyCallback == nil || !isAcceptableAlgo(algo) {
|
||||
if s.config.PublicKeyCallback == nil || !isAcceptableAlgo(algo) {
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -369,7 +369,7 @@ func (s *ServerConn) testPubKey(user, algo string, pubKey []byte) bool {
|
|||
}
|
||||
}
|
||||
|
||||
result := s.config.PubKeyCallback(user, algo, pubKey)
|
||||
result := s.config.PublicKeyCallback(user, algo, pubKey)
|
||||
if len(s.cachedPubKeys) < maxCachedPubKeys {
|
||||
c := cachedPubKey{
|
||||
user: user,
|
||||
|
@ -425,7 +425,7 @@ userAuthLoop:
|
|||
break userAuthLoop
|
||||
}
|
||||
case "publickey":
|
||||
if s.config.PubKeyCallback == nil {
|
||||
if s.config.PublicKeyCallback == nil {
|
||||
break
|
||||
}
|
||||
payload := userAuthReq.Payload
|
||||
|
@ -499,7 +499,7 @@ userAuthLoop:
|
|||
if s.config.PasswordCallback != nil {
|
||||
failureMsg.Methods = append(failureMsg.Methods, "password")
|
||||
}
|
||||
if s.config.PubKeyCallback != nil {
|
||||
if s.config.PublicKeyCallback != nil {
|
||||
failureMsg.Methods = append(failureMsg.Methods, "publickey")
|
||||
}
|
||||
|
||||
|
|
|
@ -68,10 +68,12 @@ type Session struct {
|
|||
|
||||
*clientChan // the channel backing this session
|
||||
|
||||
started bool // true once Start, Run or Shell is invoked.
|
||||
closeAfterWait []io.Closer
|
||||
copyFuncs []func() error
|
||||
errch chan error // one send per copyFunc
|
||||
started bool // true once Start, Run or Shell is invoked.
|
||||
copyFuncs []func() error
|
||||
errch chan error // one send per copyFunc
|
||||
|
||||
// true if pipe method is active
|
||||
stdinpipe, stdoutpipe, stderrpipe bool
|
||||
}
|
||||
|
||||
// RFC 4254 Section 6.4.
|
||||
|
@ -237,11 +239,9 @@ func (s *Session) waitForResponse() error {
|
|||
func (s *Session) start() error {
|
||||
s.started = true
|
||||
|
||||
type F func(*Session) error
|
||||
type F func(*Session)
|
||||
for _, setupFd := range []F{(*Session).stdin, (*Session).stdout, (*Session).stderr} {
|
||||
if err := setupFd(s); err != nil {
|
||||
return err
|
||||
}
|
||||
setupFd(s)
|
||||
}
|
||||
|
||||
s.errch = make(chan error, len(s.copyFuncs))
|
||||
|
@ -274,9 +274,6 @@ func (s *Session) Wait() error {
|
|||
copyError = err
|
||||
}
|
||||
}
|
||||
for _, fd := range s.closeAfterWait {
|
||||
fd.Close()
|
||||
}
|
||||
if waitErr != nil {
|
||||
return waitErr
|
||||
}
|
||||
|
@ -341,7 +338,10 @@ func (s *Session) wait() error {
|
|||
return &ExitError{wm}
|
||||
}
|
||||
|
||||
func (s *Session) stdin() error {
|
||||
func (s *Session) stdin() {
|
||||
if s.stdinpipe {
|
||||
return
|
||||
}
|
||||
if s.Stdin == nil {
|
||||
s.Stdin = new(bytes.Buffer)
|
||||
}
|
||||
|
@ -352,10 +352,12 @@ func (s *Session) stdin() error {
|
|||
}
|
||||
return err
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Session) stdout() error {
|
||||
func (s *Session) stdout() {
|
||||
if s.stdoutpipe {
|
||||
return
|
||||
}
|
||||
if s.Stdout == nil {
|
||||
s.Stdout = ioutil.Discard
|
||||
}
|
||||
|
@ -363,10 +365,12 @@ func (s *Session) stdout() error {
|
|||
_, err := io.Copy(s.Stdout, s.clientChan.stdout)
|
||||
return err
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Session) stderr() error {
|
||||
func (s *Session) stderr() {
|
||||
if s.stderrpipe {
|
||||
return
|
||||
}
|
||||
if s.Stderr == nil {
|
||||
s.Stderr = ioutil.Discard
|
||||
}
|
||||
|
@ -374,7 +378,6 @@ func (s *Session) stderr() error {
|
|||
_, err := io.Copy(s.Stderr, s.clientChan.stderr)
|
||||
return err
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
// StdinPipe returns a pipe that will be connected to the
|
||||
|
@ -386,10 +389,8 @@ func (s *Session) StdinPipe() (io.WriteCloser, error) {
|
|||
if s.started {
|
||||
return nil, errors.New("ssh: StdinPipe after process started")
|
||||
}
|
||||
pr, pw := io.Pipe()
|
||||
s.Stdin = pr
|
||||
s.closeAfterWait = append(s.closeAfterWait, pr)
|
||||
return pw, nil
|
||||
s.stdinpipe = true
|
||||
return s.clientChan.stdin, nil
|
||||
}
|
||||
|
||||
// StdoutPipe returns a pipe that will be connected to the
|
||||
|
@ -398,17 +399,15 @@ func (s *Session) StdinPipe() (io.WriteCloser, error) {
|
|||
// stdout and stderr streams. If the StdoutPipe reader is
|
||||
// not serviced fast enought it may eventually cause the
|
||||
// remote command to block.
|
||||
func (s *Session) StdoutPipe() (io.ReadCloser, error) {
|
||||
func (s *Session) StdoutPipe() (io.Reader, error) {
|
||||
if s.Stdout != nil {
|
||||
return nil, errors.New("ssh: Stdout already set")
|
||||
}
|
||||
if s.started {
|
||||
return nil, errors.New("ssh: StdoutPipe after process started")
|
||||
}
|
||||
pr, pw := io.Pipe()
|
||||
s.Stdout = pw
|
||||
s.closeAfterWait = append(s.closeAfterWait, pw)
|
||||
return pr, nil
|
||||
s.stdoutpipe = true
|
||||
return s.clientChan.stdout, nil
|
||||
}
|
||||
|
||||
// StderrPipe returns a pipe that will be connected to the
|
||||
|
@ -417,17 +416,15 @@ func (s *Session) StdoutPipe() (io.ReadCloser, error) {
|
|||
// stdout and stderr streams. If the StderrPipe reader is
|
||||
// not serviced fast enought it may eventually cause the
|
||||
// remote command to block.
|
||||
func (s *Session) StderrPipe() (io.ReadCloser, error) {
|
||||
func (s *Session) StderrPipe() (io.Reader, error) {
|
||||
if s.Stderr != nil {
|
||||
return nil, errors.New("ssh: Stderr already set")
|
||||
}
|
||||
if s.started {
|
||||
return nil, errors.New("ssh: StderrPipe after process started")
|
||||
}
|
||||
pr, pw := io.Pipe()
|
||||
s.Stderr = pw
|
||||
s.closeAfterWait = append(s.closeAfterWait, pw)
|
||||
return pr, nil
|
||||
s.stderrpipe = true
|
||||
return s.clientChan.stderr, nil
|
||||
}
|
||||
|
||||
// TODO(dfc) add Output and CombinedOutput helpers
|
||||
|
|
|
@ -20,7 +20,7 @@ func dial(handler serverType, t *testing.T) *ClientConn {
|
|||
serverConfig.PasswordCallback = func(user, pass string) bool {
|
||||
return user == "testuser" && pass == string(pw)
|
||||
}
|
||||
serverConfig.PubKeyCallback = nil
|
||||
serverConfig.PublicKeyCallback = nil
|
||||
|
||||
l, err := Listen("tcp", "127.0.0.1:0", serverConfig)
|
||||
if err != nil {
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"io"
|
||||
"net"
|
||||
)
|
||||
|
||||
// Dial initiates a connection to the addr from the remote host.
|
||||
// addr is resolved using net.ResolveTCPAddr before connection.
|
||||
// This could allow an observer to observe the DNS name of the
|
||||
|
|
|
@ -2,13 +2,56 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build linux
|
||||
|
||||
package terminal
|
||||
|
||||
import "io"
|
||||
import (
|
||||
"io"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// EscapeCodes contains escape sequences that can be written to the terminal in
|
||||
// order to achieve different styles of text.
|
||||
type EscapeCodes struct {
|
||||
// Foreground colors
|
||||
Black, Red, Green, Yellow, Blue, Magenta, Cyan, White []byte
|
||||
|
||||
// Reset all attributes
|
||||
Reset []byte
|
||||
}
|
||||
|
||||
var vt100EscapeCodes = EscapeCodes{
|
||||
Black: []byte{keyEscape, '[', '3', '0', 'm'},
|
||||
Red: []byte{keyEscape, '[', '3', '1', 'm'},
|
||||
Green: []byte{keyEscape, '[', '3', '2', 'm'},
|
||||
Yellow: []byte{keyEscape, '[', '3', '3', 'm'},
|
||||
Blue: []byte{keyEscape, '[', '3', '4', 'm'},
|
||||
Magenta: []byte{keyEscape, '[', '3', '5', 'm'},
|
||||
Cyan: []byte{keyEscape, '[', '3', '6', 'm'},
|
||||
White: []byte{keyEscape, '[', '3', '7', 'm'},
|
||||
|
||||
Reset: []byte{keyEscape, '[', '0', 'm'},
|
||||
}
|
||||
|
||||
// Terminal contains the state for running a VT100 terminal that is capable of
|
||||
// reading lines of input.
|
||||
type Terminal struct {
|
||||
// AutoCompleteCallback, if non-null, is called for each keypress
|
||||
// with the full input line and the current position of the cursor.
|
||||
// If it returns a nil newLine, the key press is processed normally.
|
||||
// Otherwise it returns a replacement line and the new cursor position.
|
||||
AutoCompleteCallback func(line []byte, pos, key int) (newLine []byte, newPos int)
|
||||
|
||||
// Escape contains a pointer to the escape codes for this terminal.
|
||||
// It's always a valid pointer, although the escape codes themselves
|
||||
// may be empty if the terminal doesn't support them.
|
||||
Escape *EscapeCodes
|
||||
|
||||
// lock protects the terminal and the state in this object from
|
||||
// concurrent processing of a key press and a Write() call.
|
||||
lock sync.Mutex
|
||||
|
||||
c io.ReadWriter
|
||||
prompt string
|
||||
|
||||
|
@ -16,6 +59,8 @@ type Terminal struct {
|
|||
line []byte
|
||||
// pos is the logical position of the cursor in line
|
||||
pos int
|
||||
// echo is true if local echo is enabled
|
||||
echo bool
|
||||
|
||||
// cursorX contains the current X value of the cursor where the left
|
||||
// edge is 0. cursorY contains the row number where the first row of
|
||||
|
@ -40,10 +85,12 @@ type Terminal struct {
|
|||
// "> ").
|
||||
func NewTerminal(c io.ReadWriter, prompt string) *Terminal {
|
||||
return &Terminal{
|
||||
Escape: &vt100EscapeCodes,
|
||||
c: c,
|
||||
prompt: prompt,
|
||||
termWidth: 80,
|
||||
termHeight: 24,
|
||||
echo: true,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,18 +156,11 @@ func bytesToKey(b []byte) (int, []byte) {
|
|||
|
||||
// queue appends data to the end of t.outBuf
|
||||
func (t *Terminal) queue(data []byte) {
|
||||
if len(t.outBuf)+len(data) > cap(t.outBuf) {
|
||||
newOutBuf := make([]byte, len(t.outBuf), 2*(len(t.outBuf)+len(data)))
|
||||
copy(newOutBuf, t.outBuf)
|
||||
t.outBuf = newOutBuf
|
||||
}
|
||||
|
||||
oldLen := len(t.outBuf)
|
||||
t.outBuf = t.outBuf[:len(t.outBuf)+len(data)]
|
||||
copy(t.outBuf[oldLen:], data)
|
||||
t.outBuf = append(t.outBuf, data...)
|
||||
}
|
||||
|
||||
var eraseUnderCursor = []byte{' ', keyEscape, '[', 'D'}
|
||||
var space = []byte{' '}
|
||||
|
||||
func isPrintable(key int) bool {
|
||||
return key >= 32 && key < 127
|
||||
|
@ -129,6 +169,10 @@ func isPrintable(key int) bool {
|
|||
// moveCursorToPos appends data to t.outBuf which will move the cursor to the
|
||||
// given, logical position in the text.
|
||||
func (t *Terminal) moveCursorToPos(pos int) {
|
||||
if !t.echo {
|
||||
return
|
||||
}
|
||||
|
||||
x := len(t.prompt) + pos
|
||||
y := x / t.termWidth
|
||||
x = x % t.termWidth
|
||||
|
@ -153,6 +197,12 @@ func (t *Terminal) moveCursorToPos(pos int) {
|
|||
right = x - t.cursorX
|
||||
}
|
||||
|
||||
t.cursorX = x
|
||||
t.cursorY = y
|
||||
t.move(up, down, left, right)
|
||||
}
|
||||
|
||||
func (t *Terminal) move(up, down, left, right int) {
|
||||
movement := make([]byte, 3*(up+down+left+right))
|
||||
m := movement
|
||||
for i := 0; i < up; i++ {
|
||||
|
@ -180,11 +230,14 @@ func (t *Terminal) moveCursorToPos(pos int) {
|
|||
m = m[3:]
|
||||
}
|
||||
|
||||
t.cursorX = x
|
||||
t.cursorY = y
|
||||
t.queue(movement)
|
||||
}
|
||||
|
||||
func (t *Terminal) clearLineToRight() {
|
||||
op := []byte{keyEscape, '[', 'K'}
|
||||
t.queue(op)
|
||||
}
|
||||
|
||||
const maxLineLength = 4096
|
||||
|
||||
// handleKey processes the given key and, optionally, returns a line of text
|
||||
|
@ -196,12 +249,15 @@ func (t *Terminal) handleKey(key int) (line string, ok bool) {
|
|||
return
|
||||
}
|
||||
t.pos--
|
||||
t.moveCursorToPos(t.pos)
|
||||
|
||||
copy(t.line[t.pos:], t.line[1+t.pos:])
|
||||
t.line = t.line[:len(t.line)-1]
|
||||
t.writeLine(t.line[t.pos:])
|
||||
t.moveCursorToPos(t.pos)
|
||||
if t.echo {
|
||||
t.writeLine(t.line[t.pos:])
|
||||
}
|
||||
t.queue(eraseUnderCursor)
|
||||
t.moveCursorToPos(t.pos)
|
||||
case keyAltLeft:
|
||||
// move left by a word.
|
||||
if t.pos == 0 {
|
||||
|
@ -260,6 +316,25 @@ func (t *Terminal) handleKey(key int) (line string, ok bool) {
|
|||
t.cursorY = 0
|
||||
t.maxLine = 0
|
||||
default:
|
||||
if t.AutoCompleteCallback != nil {
|
||||
t.lock.Unlock()
|
||||
newLine, newPos := t.AutoCompleteCallback(t.line, t.pos, key)
|
||||
t.lock.Lock()
|
||||
|
||||
if newLine != nil {
|
||||
if t.echo {
|
||||
t.moveCursorToPos(0)
|
||||
t.writeLine(newLine)
|
||||
for i := len(newLine); i < len(t.line); i++ {
|
||||
t.writeLine(space)
|
||||
}
|
||||
t.moveCursorToPos(newPos)
|
||||
}
|
||||
t.line = newLine
|
||||
t.pos = newPos
|
||||
return
|
||||
}
|
||||
}
|
||||
if !isPrintable(key) {
|
||||
return
|
||||
}
|
||||
|
@ -274,7 +349,9 @@ func (t *Terminal) handleKey(key int) (line string, ok bool) {
|
|||
t.line = t.line[:len(t.line)+1]
|
||||
copy(t.line[t.pos+1:], t.line[t.pos:])
|
||||
t.line[t.pos] = byte(key)
|
||||
t.writeLine(t.line[t.pos:])
|
||||
if t.echo {
|
||||
t.writeLine(t.line[t.pos:])
|
||||
}
|
||||
t.pos++
|
||||
t.moveCursorToPos(t.pos)
|
||||
}
|
||||
|
@ -283,15 +360,6 @@ func (t *Terminal) handleKey(key int) (line string, ok bool) {
|
|||
|
||||
func (t *Terminal) writeLine(line []byte) {
|
||||
for len(line) != 0 {
|
||||
if t.cursorX == t.termWidth {
|
||||
t.queue([]byte("\r\n"))
|
||||
t.cursorX = 0
|
||||
t.cursorY++
|
||||
if t.cursorY > t.maxLine {
|
||||
t.maxLine = t.cursorY
|
||||
}
|
||||
}
|
||||
|
||||
remainingOnLine := t.termWidth - t.cursorX
|
||||
todo := len(line)
|
||||
if todo > remainingOnLine {
|
||||
|
@ -300,16 +368,95 @@ func (t *Terminal) writeLine(line []byte) {
|
|||
t.queue(line[:todo])
|
||||
t.cursorX += todo
|
||||
line = line[todo:]
|
||||
|
||||
if t.cursorX == t.termWidth {
|
||||
t.cursorX = 0
|
||||
t.cursorY++
|
||||
if t.cursorY > t.maxLine {
|
||||
t.maxLine = t.cursorY
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Terminal) Write(buf []byte) (n int, err error) {
|
||||
return t.c.Write(buf)
|
||||
t.lock.Lock()
|
||||
defer t.lock.Unlock()
|
||||
|
||||
if t.cursorX == 0 && t.cursorY == 0 {
|
||||
// This is the easy case: there's nothing on the screen that we
|
||||
// have to move out of the way.
|
||||
return t.c.Write(buf)
|
||||
}
|
||||
|
||||
// We have a prompt and possibly user input on the screen. We
|
||||
// have to clear it first.
|
||||
t.move(0, /* up */ 0, /* down */ t.cursorX, /* left */ 0 /* right */ )
|
||||
t.cursorX = 0
|
||||
t.clearLineToRight()
|
||||
|
||||
for t.cursorY > 0 {
|
||||
t.move(1, /* up */ 0, 0, 0)
|
||||
t.cursorY--
|
||||
t.clearLineToRight()
|
||||
}
|
||||
|
||||
if _, err = t.c.Write(t.outBuf); err != nil {
|
||||
return
|
||||
}
|
||||
t.outBuf = t.outBuf[:0]
|
||||
|
||||
if n, err = t.c.Write(buf); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
t.queue([]byte(t.prompt))
|
||||
chars := len(t.prompt)
|
||||
if t.echo {
|
||||
t.queue(t.line)
|
||||
chars += len(t.line)
|
||||
}
|
||||
t.cursorX = chars % t.termWidth
|
||||
t.cursorY = chars / t.termWidth
|
||||
t.moveCursorToPos(t.pos)
|
||||
|
||||
if _, err = t.c.Write(t.outBuf); err != nil {
|
||||
return
|
||||
}
|
||||
t.outBuf = t.outBuf[:0]
|
||||
return
|
||||
}
|
||||
|
||||
// ReadPassword temporarily changes the prompt and reads a password, without
|
||||
// echo, from the terminal.
|
||||
func (t *Terminal) ReadPassword(prompt string) (line string, err error) {
|
||||
t.lock.Lock()
|
||||
defer t.lock.Unlock()
|
||||
|
||||
oldPrompt := t.prompt
|
||||
t.prompt = prompt
|
||||
t.echo = false
|
||||
|
||||
line, err = t.readLine()
|
||||
|
||||
t.prompt = oldPrompt
|
||||
t.echo = true
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ReadLine returns a line of input from the terminal.
|
||||
func (t *Terminal) ReadLine() (line string, err error) {
|
||||
if t.cursorX == 0 {
|
||||
t.lock.Lock()
|
||||
defer t.lock.Unlock()
|
||||
|
||||
return t.readLine()
|
||||
}
|
||||
|
||||
func (t *Terminal) readLine() (line string, err error) {
|
||||
// t.lock must be held at this point
|
||||
|
||||
if t.cursorX == 0 && t.cursorY == 0 {
|
||||
t.writeLine([]byte(t.prompt))
|
||||
t.c.Write(t.outBuf)
|
||||
t.outBuf = t.outBuf[:0]
|
||||
|
@ -320,7 +467,11 @@ func (t *Terminal) ReadLine() (line string, err error) {
|
|||
// containing a partial key sequence
|
||||
readBuf := t.inBuf[len(t.remainder):]
|
||||
var n int
|
||||
|
||||
t.lock.Unlock()
|
||||
n, err = t.c.Read(readBuf)
|
||||
t.lock.Lock()
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -358,5 +509,8 @@ func (t *Terminal) ReadLine() (line string, err error) {
|
|||
}
|
||||
|
||||
func (t *Terminal) SetSize(width, height int) {
|
||||
t.lock.Lock()
|
||||
defer t.lock.Unlock()
|
||||
|
||||
t.termWidth, t.termHeight = width, height
|
||||
}
|
||||
|
|
|
@ -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 linux
|
||||
|
||||
package terminal
|
||||
|
||||
import (
|
||||
|
|
|
@ -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 linux
|
||||
|
||||
// Package terminal provides support functions for dealing with terminals, as
|
||||
// commonly found on UNIX systems.
|
||||
//
|
||||
|
@ -9,7 +11,7 @@
|
|||
//
|
||||
// oldState, err := terminal.MakeRaw(0)
|
||||
// if err != nil {
|
||||
// panic(err.String())
|
||||
// panic(err)
|
||||
// }
|
||||
// defer terminal.Restore(0, oldState)
|
||||
package terminal
|
||||
|
@ -17,6 +19,7 @@ package terminal
|
|||
import (
|
||||
"io"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// State contains the state of a terminal.
|
||||
|
@ -57,6 +60,18 @@ func Restore(fd int, state *State) error {
|
|||
return err
|
||||
}
|
||||
|
||||
func ioctl(int, int, unsafe.Pointer) int __asm__("ioctl")
|
||||
|
||||
// GetSize returns the dimensions of the given terminal.
|
||||
func GetSize(fd int) (width, height int, err error) {
|
||||
var dimensions [4]uint16
|
||||
|
||||
if ioctl(fd, syscall.TIOCGWINSZ, unsafe.Pointer(&dimensions)) < 0 {
|
||||
return -1, -1, syscall.GetErrno()
|
||||
}
|
||||
return int(dimensions[1]), int(dimensions[0]), nil
|
||||
}
|
||||
|
||||
// ReadPassword reads a line of input from a terminal without local echo. This
|
||||
// is commonly used for inputting passwords and other sensitive data. The slice
|
||||
// returned does not include the \n.
|
||||
|
|
|
@ -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 windows
|
||||
|
||||
// Package winfsnotify allows the user to receive
|
||||
// file system event notifications on Windows.
|
||||
package winfsnotify
|
||||
|
|
|
@ -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 windows
|
||||
|
||||
package winfsnotify
|
||||
|
||||
import (
|
||||
|
|
|
@ -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 windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
|
|
|
@ -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 windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// +build windows
|
||||
// mksyscall_windows.pl winapi.go
|
||||
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
|
||||
|
||||
|
|
|
@ -506,78 +506,42 @@ func BenchmarkSprintfFloat(b *testing.B) {
|
|||
}
|
||||
}
|
||||
|
||||
var mallocBuf bytes.Buffer
|
||||
|
||||
var mallocTest = []struct {
|
||||
count int
|
||||
desc string
|
||||
fn func()
|
||||
}{
|
||||
{0, `Sprintf("")`, func() { Sprintf("") }},
|
||||
{1, `Sprintf("xxx")`, func() { Sprintf("xxx") }},
|
||||
{1, `Sprintf("%x")`, func() { Sprintf("%x", 7) }},
|
||||
{2, `Sprintf("%s")`, func() { Sprintf("%s", "hello") }},
|
||||
{1, `Sprintf("%x %x")`, func() { Sprintf("%x", 7, 112) }},
|
||||
{1, `Sprintf("%g")`, func() { Sprintf("%g", 3.14159) }},
|
||||
{0, `Fprintf(buf, "%x %x %x")`, func() { mallocBuf.Reset(); Fprintf(&mallocBuf, "%x %x %x", 7, 8, 9) }},
|
||||
{1, `Fprintf(buf, "%s")`, func() { mallocBuf.Reset(); Fprintf(&mallocBuf, "%s", "hello") }},
|
||||
}
|
||||
|
||||
var _ bytes.Buffer
|
||||
|
||||
func TestCountMallocs(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
const N = 100
|
||||
runtime.UpdateMemStats()
|
||||
mallocs := 0 - runtime.MemStats.Mallocs
|
||||
for i := 0; i < N; i++ {
|
||||
Sprintf("")
|
||||
for _, mt := range mallocTest {
|
||||
const N = 100
|
||||
runtime.UpdateMemStats()
|
||||
mallocs := 0 - runtime.MemStats.Mallocs
|
||||
for i := 0; i < N; i++ {
|
||||
mt.fn()
|
||||
}
|
||||
runtime.UpdateMemStats()
|
||||
mallocs += runtime.MemStats.Mallocs
|
||||
if mallocs/N != uint64(mt.count) {
|
||||
t.Errorf("%s: expected %d mallocs, got %d", mt.desc, mt.count, mallocs/N)
|
||||
}
|
||||
}
|
||||
runtime.UpdateMemStats()
|
||||
mallocs += runtime.MemStats.Mallocs
|
||||
Printf("mallocs per Sprintf(\"\"): %d\n", mallocs/N)
|
||||
runtime.UpdateMemStats()
|
||||
mallocs = 0 - runtime.MemStats.Mallocs
|
||||
for i := 0; i < N; i++ {
|
||||
Sprintf("xxx")
|
||||
}
|
||||
runtime.UpdateMemStats()
|
||||
mallocs += runtime.MemStats.Mallocs
|
||||
Printf("mallocs per Sprintf(\"xxx\"): %d\n", mallocs/N)
|
||||
runtime.UpdateMemStats()
|
||||
mallocs = 0 - runtime.MemStats.Mallocs
|
||||
for i := 0; i < N; i++ {
|
||||
Sprintf("%x", i)
|
||||
}
|
||||
runtime.UpdateMemStats()
|
||||
mallocs += runtime.MemStats.Mallocs
|
||||
Printf("mallocs per Sprintf(\"%%x\"): %d\n", mallocs/N)
|
||||
runtime.UpdateMemStats()
|
||||
mallocs = 0 - runtime.MemStats.Mallocs
|
||||
for i := 0; i < N; i++ {
|
||||
Sprintf("%s", "hello")
|
||||
}
|
||||
runtime.UpdateMemStats()
|
||||
mallocs += runtime.MemStats.Mallocs
|
||||
Printf("mallocs per Sprintf(\"%%s\"): %d\n", mallocs/N)
|
||||
runtime.UpdateMemStats()
|
||||
mallocs = 0 - runtime.MemStats.Mallocs
|
||||
for i := 0; i < N; i++ {
|
||||
Sprintf("%x %x", i, i)
|
||||
}
|
||||
runtime.UpdateMemStats()
|
||||
mallocs += runtime.MemStats.Mallocs
|
||||
Printf("mallocs per Sprintf(\"%%x %%x\"): %d\n", mallocs/N)
|
||||
runtime.UpdateMemStats()
|
||||
mallocs = 0 - runtime.MemStats.Mallocs
|
||||
for i := 0; i < N; i++ {
|
||||
Sprintf("%g", 3.14159)
|
||||
}
|
||||
runtime.UpdateMemStats()
|
||||
mallocs += runtime.MemStats.Mallocs
|
||||
Printf("mallocs per Sprintf(\"%%g\"): %d\n", mallocs/N)
|
||||
buf := new(bytes.Buffer)
|
||||
runtime.UpdateMemStats()
|
||||
mallocs = 0 - runtime.MemStats.Mallocs
|
||||
for i := 0; i < N; i++ {
|
||||
buf.Reset()
|
||||
Fprintf(buf, "%x %x %x", i, i, i)
|
||||
}
|
||||
runtime.UpdateMemStats()
|
||||
mallocs += runtime.MemStats.Mallocs
|
||||
Printf("mallocs per Fprintf(buf, \"%%x %%x %%x\"): %d\n", mallocs/N)
|
||||
runtime.UpdateMemStats()
|
||||
mallocs = 0 - runtime.MemStats.Mallocs
|
||||
for i := 0; i < N; i++ {
|
||||
buf.Reset()
|
||||
Fprintf(buf, "%s", "hello")
|
||||
}
|
||||
runtime.UpdateMemStats()
|
||||
mallocs += runtime.MemStats.Mallocs
|
||||
Printf("mallocs per Fprintf(buf, \"%%s\"): %d\n", mallocs/N)
|
||||
}
|
||||
|
||||
type flagPrinter struct{}
|
||||
|
|
|
@ -154,12 +154,17 @@ func putint(buf []byte, base, val uint64, digits string) int {
|
|||
return i - 1
|
||||
}
|
||||
|
||||
var (
|
||||
trueBytes = []byte("true")
|
||||
falseBytes = []byte("false")
|
||||
)
|
||||
|
||||
// fmt_boolean formats a boolean.
|
||||
func (f *fmt) fmt_boolean(v bool) {
|
||||
if v {
|
||||
f.padString("true")
|
||||
f.pad(trueBytes)
|
||||
} else {
|
||||
f.padString("false")
|
||||
f.pad(falseBytes)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -283,31 +288,18 @@ func (f *fmt) fmt_s(s string) {
|
|||
}
|
||||
|
||||
// fmt_sx formats a string as a hexadecimal encoding of its bytes.
|
||||
func (f *fmt) fmt_sx(s string) {
|
||||
t := ""
|
||||
func (f *fmt) fmt_sx(s, digits string) {
|
||||
// TODO: Avoid buffer by pre-padding.
|
||||
var b bytes.Buffer
|
||||
for i := 0; i < len(s); i++ {
|
||||
if i > 0 && f.space {
|
||||
t += " "
|
||||
b.WriteByte(' ')
|
||||
}
|
||||
v := s[i]
|
||||
t += string(ldigits[v>>4])
|
||||
t += string(ldigits[v&0xF])
|
||||
b.WriteByte(digits[v>>4])
|
||||
b.WriteByte(digits[v&0xF])
|
||||
}
|
||||
f.padString(t)
|
||||
}
|
||||
|
||||
// fmt_sX formats a string as an uppercase hexadecimal encoding of its bytes.
|
||||
func (f *fmt) fmt_sX(s string) {
|
||||
t := ""
|
||||
for i := 0; i < len(s); i++ {
|
||||
if i > 0 && f.space {
|
||||
t += " "
|
||||
}
|
||||
v := s[i]
|
||||
t += string(udigits[v>>4])
|
||||
t += string(udigits[v&0xF])
|
||||
}
|
||||
f.padString(t)
|
||||
f.pad(b.Bytes())
|
||||
}
|
||||
|
||||
// fmt_q formats a string as a double-quoted, escaped Go string constant.
|
||||
|
@ -329,13 +321,13 @@ func (f *fmt) fmt_q(s string) {
|
|||
// fmt_qc formats the integer as a single-quoted, escaped Go character constant.
|
||||
// If the character is not valid Unicode, it will print '\ufffd'.
|
||||
func (f *fmt) fmt_qc(c int64) {
|
||||
var quoted string
|
||||
var quoted []byte
|
||||
if f.plus {
|
||||
quoted = strconv.QuoteRuneToASCII(rune(c))
|
||||
quoted = strconv.AppendQuoteRuneToASCII(f.intbuf[0:0], rune(c))
|
||||
} else {
|
||||
quoted = strconv.QuoteRune(rune(c))
|
||||
quoted = strconv.AppendQuoteRune(f.intbuf[0:0], rune(c))
|
||||
}
|
||||
f.padString(quoted)
|
||||
f.pad(quoted)
|
||||
}
|
||||
|
||||
// floating-point
|
||||
|
@ -347,57 +339,70 @@ func doPrec(f *fmt, def int) int {
|
|||
return def
|
||||
}
|
||||
|
||||
// Add a plus sign or space to the floating-point string representation if missing and required.
|
||||
func (f *fmt) plusSpace(s string) {
|
||||
if s[0] != '-' {
|
||||
// formatFloat formats a float64; it is an efficient equivalent to f.pad(strconv.FormatFloat()...).
|
||||
func (f *fmt) formatFloat(v float64, verb byte, prec, n int) {
|
||||
// We leave one byte at the beginning of f.intbuf for a sign if needed,
|
||||
// and make it a space, which we might be able to use.
|
||||
f.intbuf[0] = ' '
|
||||
slice := strconv.AppendFloat(f.intbuf[0:1], v, verb, prec, n)
|
||||
// Add a plus sign or space to the floating-point string representation if missing and required.
|
||||
// The formatted number starts at slice[1].
|
||||
switch slice[1] {
|
||||
case '-', '+':
|
||||
// We're set; drop the leading space.
|
||||
slice = slice[1:]
|
||||
default:
|
||||
// There's no sign, but we might need one.
|
||||
if f.plus {
|
||||
s = "+" + s
|
||||
slice[0] = '+'
|
||||
} else if f.space {
|
||||
s = " " + s
|
||||
// space is already there
|
||||
} else {
|
||||
slice = slice[1:]
|
||||
}
|
||||
}
|
||||
f.padString(s)
|
||||
f.pad(slice)
|
||||
}
|
||||
|
||||
// fmt_e64 formats a float64 in the form -1.23e+12.
|
||||
func (f *fmt) fmt_e64(v float64) { f.plusSpace(strconv.FormatFloat(v, 'e', doPrec(f, 6), 64)) }
|
||||
func (f *fmt) fmt_e64(v float64) { f.formatFloat(v, 'e', doPrec(f, 6), 64) }
|
||||
|
||||
// fmt_E64 formats a float64 in the form -1.23E+12.
|
||||
func (f *fmt) fmt_E64(v float64) { f.plusSpace(strconv.FormatFloat(v, 'E', doPrec(f, 6), 64)) }
|
||||
func (f *fmt) fmt_E64(v float64) { f.formatFloat(v, 'E', doPrec(f, 6), 64) }
|
||||
|
||||
// fmt_f64 formats a float64 in the form -1.23.
|
||||
func (f *fmt) fmt_f64(v float64) { f.plusSpace(strconv.FormatFloat(v, 'f', doPrec(f, 6), 64)) }
|
||||
func (f *fmt) fmt_f64(v float64) { f.formatFloat(v, 'f', doPrec(f, 6), 64) }
|
||||
|
||||
// fmt_g64 formats a float64 in the 'f' or 'e' form according to size.
|
||||
func (f *fmt) fmt_g64(v float64) { f.plusSpace(strconv.FormatFloat(v, 'g', doPrec(f, -1), 64)) }
|
||||
func (f *fmt) fmt_g64(v float64) { f.formatFloat(v, 'g', doPrec(f, -1), 64) }
|
||||
|
||||
// fmt_g64 formats a float64 in the 'f' or 'E' form according to size.
|
||||
func (f *fmt) fmt_G64(v float64) { f.plusSpace(strconv.FormatFloat(v, 'G', doPrec(f, -1), 64)) }
|
||||
func (f *fmt) fmt_G64(v float64) { f.formatFloat(v, 'G', doPrec(f, -1), 64) }
|
||||
|
||||
// fmt_fb64 formats a float64 in the form -123p3 (exponent is power of 2).
|
||||
func (f *fmt) fmt_fb64(v float64) { f.plusSpace(strconv.FormatFloat(v, 'b', 0, 64)) }
|
||||
func (f *fmt) fmt_fb64(v float64) { f.formatFloat(v, 'b', 0, 64) }
|
||||
|
||||
// float32
|
||||
// cannot defer to float64 versions
|
||||
// because it will get rounding wrong in corner cases.
|
||||
|
||||
// fmt_e32 formats a float32 in the form -1.23e+12.
|
||||
func (f *fmt) fmt_e32(v float32) { f.plusSpace(strconv.FormatFloat(float64(v), 'e', doPrec(f, 6), 32)) }
|
||||
func (f *fmt) fmt_e32(v float32) { f.formatFloat(float64(v), 'e', doPrec(f, 6), 32) }
|
||||
|
||||
// fmt_E32 formats a float32 in the form -1.23E+12.
|
||||
func (f *fmt) fmt_E32(v float32) { f.plusSpace(strconv.FormatFloat(float64(v), 'E', doPrec(f, 6), 32)) }
|
||||
func (f *fmt) fmt_E32(v float32) { f.formatFloat(float64(v), 'E', doPrec(f, 6), 32) }
|
||||
|
||||
// fmt_f32 formats a float32 in the form -1.23.
|
||||
func (f *fmt) fmt_f32(v float32) { f.plusSpace(strconv.FormatFloat(float64(v), 'f', doPrec(f, 6), 32)) }
|
||||
func (f *fmt) fmt_f32(v float32) { f.formatFloat(float64(v), 'f', doPrec(f, 6), 32) }
|
||||
|
||||
// fmt_g32 formats a float32 in the 'f' or 'e' form according to size.
|
||||
func (f *fmt) fmt_g32(v float32) { f.plusSpace(strconv.FormatFloat(float64(v), 'g', doPrec(f, -1), 32)) }
|
||||
func (f *fmt) fmt_g32(v float32) { f.formatFloat(float64(v), 'g', doPrec(f, -1), 32) }
|
||||
|
||||
// fmt_G32 formats a float32 in the 'f' or 'E' form according to size.
|
||||
func (f *fmt) fmt_G32(v float32) { f.plusSpace(strconv.FormatFloat(float64(v), 'G', doPrec(f, -1), 32)) }
|
||||
func (f *fmt) fmt_G32(v float32) { f.formatFloat(float64(v), 'G', doPrec(f, -1), 32) }
|
||||
|
||||
// fmt_fb32 formats a float32 in the form -123p3 (exponent is power of 2).
|
||||
func (f *fmt) fmt_fb32(v float32) { f.padString(strconv.FormatFloat(float64(v), 'b', 0, 32)) }
|
||||
func (f *fmt) fmt_fb32(v float32) { f.formatFloat(float64(v), 'b', 0, 32) }
|
||||
|
||||
// fmt_c64 formats a complex64 according to the verb.
|
||||
func (f *fmt) fmt_c64(v complex64, verb rune) {
|
||||
|
|
|
@ -503,9 +503,9 @@ func (p *pp) fmtString(v string, verb rune, goSyntax bool) {
|
|||
case 's':
|
||||
p.fmt.fmt_s(v)
|
||||
case 'x':
|
||||
p.fmt.fmt_sx(v)
|
||||
p.fmt.fmt_sx(v, ldigits)
|
||||
case 'X':
|
||||
p.fmt.fmt_sX(v)
|
||||
p.fmt.fmt_sx(v, udigits)
|
||||
case 'q':
|
||||
p.fmt.fmt_q(v)
|
||||
default:
|
||||
|
@ -542,9 +542,9 @@ func (p *pp) fmtBytes(v []byte, verb rune, goSyntax bool, depth int) {
|
|||
case 's':
|
||||
p.fmt.fmt_s(s)
|
||||
case 'x':
|
||||
p.fmt.fmt_sx(s)
|
||||
p.fmt.fmt_sx(s, ldigits)
|
||||
case 'X':
|
||||
p.fmt.fmt_sX(s)
|
||||
p.fmt.fmt_sx(s, udigits)
|
||||
case 'q':
|
||||
p.fmt.fmt_q(s)
|
||||
default:
|
||||
|
|
|
@ -80,7 +80,7 @@ func (s *Scope) String() string {
|
|||
type Object struct {
|
||||
Kind ObjKind
|
||||
Name string // declared name
|
||||
Decl interface{} // corresponding Field, XxxSpec, FuncDecl, or LabeledStmt; or nil
|
||||
Decl interface{} // corresponding Field, XxxSpec, FuncDecl, LabeledStmt, or AssignStmt; or nil
|
||||
Data interface{} // object-specific data; or nil
|
||||
Type interface{} // place holder for type information; may be nil
|
||||
}
|
||||
|
@ -125,6 +125,12 @@ func (obj *Object) Pos() token.Pos {
|
|||
if d.Label.Name == name {
|
||||
return d.Label.Pos()
|
||||
}
|
||||
case *AssignStmt:
|
||||
for _, x := range d.Lhs {
|
||||
if ident, isIdent := x.(*Ident); isIdent && ident.Name == name {
|
||||
return ident.Pos()
|
||||
}
|
||||
}
|
||||
}
|
||||
return token.NoPos
|
||||
}
|
||||
|
|
|
@ -46,8 +46,9 @@ var buildPkgs = []struct {
|
|||
{
|
||||
"go/build/cgotest",
|
||||
&DirInfo{
|
||||
CgoFiles: []string{"cgotest.go"},
|
||||
CgoFiles: ifCgo([]string{"cgotest.go"}),
|
||||
CFiles: []string{"cgotest.c"},
|
||||
HFiles: []string{"cgotest.h"},
|
||||
Imports: []string{"C", "unsafe"},
|
||||
TestImports: []string{},
|
||||
Package: "cgotest",
|
||||
|
@ -55,6 +56,13 @@ var buildPkgs = []struct {
|
|||
},
|
||||
}
|
||||
|
||||
func ifCgo(x []string) []string {
|
||||
if DefaultContext.CgoEnabled {
|
||||
return x
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
const cmdtestOutput = "3"
|
||||
|
||||
func TestBuild(t *testing.T) {
|
||||
|
@ -71,6 +79,10 @@ func TestBuild(t *testing.T) {
|
|||
continue
|
||||
}
|
||||
|
||||
if tt.dir == "go/build/cgotest" && len(info.CgoFiles) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
s, err := Build(tree, tt.dir, info)
|
||||
if err != nil {
|
||||
t.Errorf("Build(%#q): %v", tt.dir, err)
|
||||
|
|
|
@ -26,9 +26,9 @@ import (
|
|||
|
||||
// A Context specifies the supporting context for a build.
|
||||
type Context struct {
|
||||
GOARCH string // target architecture
|
||||
GOOS string // target operating system
|
||||
// TODO(rsc,adg): GOPATH
|
||||
GOARCH string // target architecture
|
||||
GOOS string // target operating system
|
||||
CgoEnabled bool // whether cgo can be used
|
||||
|
||||
// By default, ScanDir uses the operating system's
|
||||
// file system calls to read directories and files.
|
||||
|
@ -75,9 +75,36 @@ func (ctxt *Context) readFile(dir, file string) (string, []byte, error) {
|
|||
// The DefaultContext is the default Context for builds.
|
||||
// It uses the GOARCH and GOOS environment variables
|
||||
// if set, or else the compiled code's GOARCH and GOOS.
|
||||
var DefaultContext = Context{
|
||||
GOARCH: envOr("GOARCH", runtime.GOARCH),
|
||||
GOOS: envOr("GOOS", runtime.GOOS),
|
||||
var DefaultContext = defaultContext()
|
||||
|
||||
var cgoEnabled = map[string]bool{
|
||||
"darwin/386": true,
|
||||
"darwin/amd64": true,
|
||||
"linux/386": true,
|
||||
"linux/amd64": true,
|
||||
"freebsd/386": true,
|
||||
"freebsd/amd64": true,
|
||||
"windows/386": true,
|
||||
"windows/amd64": true,
|
||||
}
|
||||
|
||||
func defaultContext() Context {
|
||||
var c Context
|
||||
|
||||
c.GOARCH = envOr("GOARCH", runtime.GOARCH)
|
||||
c.GOOS = envOr("GOOS", runtime.GOOS)
|
||||
|
||||
s := os.Getenv("CGO_ENABLED")
|
||||
switch s {
|
||||
case "1":
|
||||
c.CgoEnabled = true
|
||||
case "0":
|
||||
c.CgoEnabled = false
|
||||
default:
|
||||
c.CgoEnabled = cgoEnabled[c.GOOS+"/"+c.GOARCH]
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func envOr(name, def string) string {
|
||||
|
@ -96,8 +123,9 @@ type DirInfo struct {
|
|||
|
||||
// Source files
|
||||
GoFiles []string // .go files in dir (excluding CgoFiles)
|
||||
HFiles []string // .h files in dir
|
||||
CFiles []string // .c files in dir
|
||||
SFiles []string // .s files in dir
|
||||
SFiles []string // .s (and, when using cgo, .S files in dir)
|
||||
CgoFiles []string // .go files that import "C"
|
||||
|
||||
// Cgo directives
|
||||
|
@ -135,6 +163,7 @@ func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
var Sfiles []string // files with ".S" (capital S)
|
||||
var di DirInfo
|
||||
imported := make(map[string]bool)
|
||||
testImported := make(map[string]bool)
|
||||
|
@ -154,7 +183,7 @@ func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) {
|
|||
|
||||
ext := path.Ext(name)
|
||||
switch ext {
|
||||
case ".go", ".c", ".s":
|
||||
case ".go", ".c", ".s", ".h", ".S":
|
||||
// tentatively okay
|
||||
default:
|
||||
// skip
|
||||
|
@ -175,9 +204,15 @@ func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) {
|
|||
case ".c":
|
||||
di.CFiles = append(di.CFiles, name)
|
||||
continue
|
||||
case ".h":
|
||||
di.HFiles = append(di.HFiles, name)
|
||||
continue
|
||||
case ".s":
|
||||
di.SFiles = append(di.SFiles, name)
|
||||
continue
|
||||
case ".S":
|
||||
Sfiles = append(Sfiles, name)
|
||||
continue
|
||||
}
|
||||
|
||||
pf, err := parser.ParseFile(fset, filename, data, parser.ImportsOnly|parser.ParseComments)
|
||||
|
@ -256,7 +291,9 @@ func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) {
|
|||
}
|
||||
}
|
||||
if isCgo {
|
||||
di.CgoFiles = append(di.CgoFiles, name)
|
||||
if ctxt.CgoEnabled {
|
||||
di.CgoFiles = append(di.CgoFiles, name)
|
||||
}
|
||||
} else if isTest {
|
||||
if pkg == string(pf.Name.Name) {
|
||||
di.TestGoFiles = append(di.TestGoFiles, name)
|
||||
|
@ -282,6 +319,15 @@ func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) {
|
|||
di.TestImports[i] = p
|
||||
i++
|
||||
}
|
||||
|
||||
// add the .S files only if we are using cgo
|
||||
// (which means gcc will compile them).
|
||||
// The standard assemblers expect .s files.
|
||||
if len(di.CgoFiles) > 0 {
|
||||
di.SFiles = append(di.SFiles, Sfiles...)
|
||||
sort.Strings(di.SFiles)
|
||||
}
|
||||
|
||||
// File name lists are sorted because ReadDir sorts.
|
||||
sort.Strings(di.Imports)
|
||||
sort.Strings(di.TestImports)
|
||||
|
@ -289,7 +335,6 @@ func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) {
|
|||
}
|
||||
|
||||
var slashslash = []byte("//")
|
||||
var plusBuild = []byte("+build")
|
||||
|
||||
// shouldBuild reports whether it is okay to use this file,
|
||||
// The rule is that in the file's leading run of // comments
|
||||
|
@ -510,14 +555,22 @@ func splitQuoted(s string) (r []string, err error) {
|
|||
//
|
||||
// $GOOS
|
||||
// $GOARCH
|
||||
// $GOOS/$GOARCH
|
||||
// cgo (if cgo is enabled)
|
||||
// nocgo (if cgo is disabled)
|
||||
// a slash-separated list of any of these
|
||||
//
|
||||
func (ctxt *Context) matchOSArch(name string) bool {
|
||||
if ctxt.CgoEnabled && name == "cgo" {
|
||||
return true
|
||||
}
|
||||
if !ctxt.CgoEnabled && name == "nocgo" {
|
||||
return true
|
||||
}
|
||||
if name == ctxt.GOOS || name == ctxt.GOARCH {
|
||||
return true
|
||||
}
|
||||
i := strings.Index(name, "/")
|
||||
return i >= 0 && name[:i] == ctxt.GOOS && name[i+1:] == ctxt.GOARCH
|
||||
return i >= 0 && ctxt.matchOSArch(name[:i]) && ctxt.matchOSArch(name[i+1:])
|
||||
}
|
||||
|
||||
// goodOSArchFile returns false if the name contains a $GOOS or $GOARCH
|
||||
|
|
|
@ -57,7 +57,7 @@ func (t *Tree) PkgDir() string {
|
|||
func (t *Tree) BinDir() string {
|
||||
if t.Goroot {
|
||||
if gobin := os.Getenv("GOBIN"); gobin != "" {
|
||||
return gobin
|
||||
return filepath.Clean(gobin)
|
||||
}
|
||||
}
|
||||
return filepath.Join(t.Path, "bin")
|
||||
|
@ -85,8 +85,8 @@ func (t *Tree) HasPkg(pkg string) bool {
|
|||
}
|
||||
|
||||
var (
|
||||
ErrNotFound = errors.New("go/build: package could not be found locally")
|
||||
ErrTreeNotFound = errors.New("go/build: no valid GOROOT or GOPATH could be found")
|
||||
ErrNotFound = errors.New("package could not be found locally")
|
||||
ErrTreeNotFound = errors.New("no valid GOROOT or GOPATH could be found")
|
||||
)
|
||||
|
||||
// FindTree takes an import or filesystem path and returns the
|
||||
|
@ -151,7 +151,7 @@ func init() {
|
|||
root := runtime.GOROOT()
|
||||
t, err := newTree(root)
|
||||
if err != nil {
|
||||
log.Printf("go/build: invalid GOROOT %q: %v", root, err)
|
||||
log.Printf("invalid GOROOT %q: %v", root, err)
|
||||
} else {
|
||||
t.Goroot = true
|
||||
Path = []*Tree{t}
|
||||
|
@ -163,7 +163,7 @@ func init() {
|
|||
}
|
||||
t, err := newTree(p)
|
||||
if err != nil {
|
||||
log.Printf("go/build: invalid GOPATH %q: %v", p, err)
|
||||
log.Printf("invalid GOPATH %q: %v", p, err)
|
||||
continue
|
||||
}
|
||||
Path = append(Path, t)
|
||||
|
|
|
@ -13,17 +13,32 @@ import (
|
|||
)
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Collection of documentation info
|
||||
|
||||
type typeDoc struct {
|
||||
// embeddedType describes the type of an anonymous field.
|
||||
//
|
||||
type embeddedType struct {
|
||||
typ *typeInfo // the corresponding base type
|
||||
ptr bool // if set, the anonymous field type is a pointer
|
||||
}
|
||||
|
||||
type typeInfo struct {
|
||||
// len(decl.Specs) == 1, and the element type is *ast.TypeSpec
|
||||
// if the type declaration hasn't been seen yet, decl is nil
|
||||
decl *ast.GenDecl
|
||||
// values, factory functions, and methods associated with the type
|
||||
decl *ast.GenDecl
|
||||
embedded []embeddedType
|
||||
forward *TypeDoc // forward link to processed type documentation
|
||||
|
||||
// declarations associated with the type
|
||||
values []*ast.GenDecl // consts and vars
|
||||
factories map[string]*ast.FuncDecl
|
||||
methods map[string]*ast.FuncDecl
|
||||
}
|
||||
|
||||
func (info *typeInfo) addEmbeddedType(embedded *typeInfo, isPtr bool) {
|
||||
info.embedded = append(info.embedded, embeddedType{embedded, isPtr})
|
||||
}
|
||||
|
||||
// docReader accumulates documentation for a single package.
|
||||
// It modifies the AST: Comments (declaration documentation)
|
||||
// that have been collected by the DocReader are set to nil
|
||||
|
@ -32,17 +47,19 @@ type typeDoc struct {
|
|||
// printing the corresponding AST node).
|
||||
//
|
||||
type docReader struct {
|
||||
doc *ast.CommentGroup // package documentation, if any
|
||||
pkgName string
|
||||
values []*ast.GenDecl // consts and vars
|
||||
types map[string]*typeDoc
|
||||
funcs map[string]*ast.FuncDecl
|
||||
bugs []*ast.CommentGroup
|
||||
doc *ast.CommentGroup // package documentation, if any
|
||||
pkgName string
|
||||
values []*ast.GenDecl // consts and vars
|
||||
types map[string]*typeInfo
|
||||
embedded map[string]*typeInfo // embedded types, possibly not exported
|
||||
funcs map[string]*ast.FuncDecl
|
||||
bugs []*ast.CommentGroup
|
||||
}
|
||||
|
||||
func (doc *docReader) init(pkgName string) {
|
||||
doc.pkgName = pkgName
|
||||
doc.types = make(map[string]*typeDoc)
|
||||
doc.types = make(map[string]*typeInfo)
|
||||
doc.embedded = make(map[string]*typeInfo)
|
||||
doc.funcs = make(map[string]*ast.FuncDecl)
|
||||
}
|
||||
|
||||
|
@ -52,56 +69,40 @@ func (doc *docReader) addDoc(comments *ast.CommentGroup) {
|
|||
doc.doc = comments
|
||||
return
|
||||
}
|
||||
|
||||
// More than one package comment: Usually there will be only
|
||||
// one file with a package comment, but it's better to collect
|
||||
// all comments than drop them on the floor.
|
||||
// (This code isn't particularly clever - no amortized doubling is
|
||||
// used - but this situation occurs rarely and is not time-critical.)
|
||||
n1 := len(doc.doc.List)
|
||||
n2 := len(comments.List)
|
||||
list := make([]*ast.Comment, n1+1+n2) // + 1 for separator line
|
||||
copy(list, doc.doc.List)
|
||||
list[n1] = &ast.Comment{token.NoPos, "//"} // separator line
|
||||
copy(list[n1+1:], comments.List)
|
||||
doc.doc = &ast.CommentGroup{list}
|
||||
blankComment := &ast.Comment{token.NoPos, "//"}
|
||||
list := append(doc.doc.List, blankComment)
|
||||
doc.doc.List = append(list, comments.List...)
|
||||
}
|
||||
|
||||
func (doc *docReader) addType(decl *ast.GenDecl) {
|
||||
spec := decl.Specs[0].(*ast.TypeSpec)
|
||||
typ := doc.lookupTypeDoc(spec.Name.Name)
|
||||
// typ should always be != nil since declared types
|
||||
// are always named - be conservative and check
|
||||
if typ != nil {
|
||||
// a type should be added at most once, so typ.decl
|
||||
// should be nil - if it isn't, simply overwrite it
|
||||
typ.decl = decl
|
||||
}
|
||||
}
|
||||
|
||||
func (doc *docReader) lookupTypeDoc(name string) *typeDoc {
|
||||
if name == "" {
|
||||
func (doc *docReader) lookupTypeInfo(name string) *typeInfo {
|
||||
if name == "" || name == "_" {
|
||||
return nil // no type docs for anonymous types
|
||||
}
|
||||
if tdoc, found := doc.types[name]; found {
|
||||
return tdoc
|
||||
if info, found := doc.types[name]; found {
|
||||
return info
|
||||
}
|
||||
// type wasn't found - add one without declaration
|
||||
tdoc := &typeDoc{nil, nil, make(map[string]*ast.FuncDecl), make(map[string]*ast.FuncDecl)}
|
||||
doc.types[name] = tdoc
|
||||
return tdoc
|
||||
info := &typeInfo{
|
||||
factories: make(map[string]*ast.FuncDecl),
|
||||
methods: make(map[string]*ast.FuncDecl),
|
||||
}
|
||||
doc.types[name] = info
|
||||
return info
|
||||
}
|
||||
|
||||
func baseTypeName(typ ast.Expr) string {
|
||||
func baseTypeName(typ ast.Expr, allTypes bool) string {
|
||||
switch t := typ.(type) {
|
||||
case *ast.Ident:
|
||||
// if the type is not exported, the effect to
|
||||
// a client is as if there were no type name
|
||||
if t.IsExported() {
|
||||
if t.IsExported() || allTypes {
|
||||
return t.Name
|
||||
}
|
||||
case *ast.StarExpr:
|
||||
return baseTypeName(t.X)
|
||||
return baseTypeName(t.X, allTypes)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
@ -120,7 +121,7 @@ func (doc *docReader) addValue(decl *ast.GenDecl) {
|
|||
switch {
|
||||
case v.Type != nil:
|
||||
// a type is present; determine its name
|
||||
name = baseTypeName(v.Type)
|
||||
name = baseTypeName(v.Type, false)
|
||||
case decl.Tok == token.CONST:
|
||||
// no type is present but we have a constant declaration;
|
||||
// use the previous type name (w/o more type information
|
||||
|
@ -148,7 +149,7 @@ func (doc *docReader) addValue(decl *ast.GenDecl) {
|
|||
values := &doc.values
|
||||
if domName != "" && domFreq >= int(float64(len(decl.Specs))*threshold) {
|
||||
// typed entries are sufficiently frequent
|
||||
typ := doc.lookupTypeDoc(domName)
|
||||
typ := doc.lookupTypeInfo(domName)
|
||||
if typ != nil {
|
||||
values = &typ.values // associate with that type
|
||||
}
|
||||
|
@ -175,10 +176,13 @@ func setFunc(table map[string]*ast.FuncDecl, f *ast.FuncDecl) {
|
|||
}
|
||||
|
||||
func (doc *docReader) addFunc(fun *ast.FuncDecl) {
|
||||
// strip function body
|
||||
fun.Body = nil
|
||||
|
||||
// determine if it should be associated with a type
|
||||
if fun.Recv != nil {
|
||||
// method
|
||||
typ := doc.lookupTypeDoc(baseTypeName(fun.Recv.List[0].Type))
|
||||
typ := doc.lookupTypeInfo(baseTypeName(fun.Recv.List[0].Type, false))
|
||||
if typ != nil {
|
||||
// exported receiver type
|
||||
setFunc(typ.methods, fun)
|
||||
|
@ -199,8 +203,8 @@ func (doc *docReader) addFunc(fun *ast.FuncDecl) {
|
|||
// exactly one (named or anonymous) result associated
|
||||
// with the first type in result signature (there may
|
||||
// be more than one result)
|
||||
tname := baseTypeName(res.Type)
|
||||
typ := doc.lookupTypeDoc(tname)
|
||||
tname := baseTypeName(res.Type, false)
|
||||
typ := doc.lookupTypeInfo(tname)
|
||||
if typ != nil {
|
||||
// named and exported result type
|
||||
setFunc(typ.factories, fun)
|
||||
|
@ -224,10 +228,17 @@ func (doc *docReader) addDecl(decl ast.Decl) {
|
|||
case token.TYPE:
|
||||
// types are handled individually
|
||||
for _, spec := range d.Specs {
|
||||
// make a (fake) GenDecl node for this TypeSpec
|
||||
tspec := spec.(*ast.TypeSpec)
|
||||
// add the type to the documentation
|
||||
info := doc.lookupTypeInfo(tspec.Name.Name)
|
||||
if info == nil {
|
||||
continue // no name - ignore the type
|
||||
}
|
||||
// Make a (fake) GenDecl node for this TypeSpec
|
||||
// (we need to do this here - as opposed to just
|
||||
// for printing - so we don't lose the GenDecl
|
||||
// documentation)
|
||||
// documentation). Since a new GenDecl node is
|
||||
// created, there's no need to nil out d.Doc.
|
||||
//
|
||||
// TODO(gri): Consider just collecting the TypeSpec
|
||||
// node (and copy in the GenDecl.doc if there is no
|
||||
|
@ -235,8 +246,32 @@ func (doc *docReader) addDecl(decl ast.Decl) {
|
|||
// makeTypeDocs below). Simpler data structures, but
|
||||
// would lose GenDecl documentation if the TypeSpec
|
||||
// has documentation as well.
|
||||
doc.addType(&ast.GenDecl{d.Doc, d.Pos(), token.TYPE, token.NoPos, []ast.Spec{spec}, token.NoPos})
|
||||
// A new GenDecl node is created, no need to nil out d.Doc.
|
||||
fake := &ast.GenDecl{d.Doc, d.Pos(), token.TYPE, token.NoPos,
|
||||
[]ast.Spec{tspec}, token.NoPos}
|
||||
// A type should be added at most once, so info.decl
|
||||
// should be nil - if it isn't, simply overwrite it.
|
||||
info.decl = fake
|
||||
// Look for anonymous fields that might contribute methods.
|
||||
var fields *ast.FieldList
|
||||
switch typ := spec.(*ast.TypeSpec).Type.(type) {
|
||||
case *ast.StructType:
|
||||
fields = typ.Fields
|
||||
case *ast.InterfaceType:
|
||||
fields = typ.Methods
|
||||
}
|
||||
if fields != nil {
|
||||
for _, field := range fields.List {
|
||||
if len(field.Names) == 0 {
|
||||
// anonymous field - add corresponding type
|
||||
// to the info and collect it in doc
|
||||
name := baseTypeName(field.Type, true)
|
||||
if embedded := doc.lookupTypeInfo(name); embedded != nil {
|
||||
_, ptr := field.Type.(*ast.StarExpr)
|
||||
info.addEmbeddedType(embedded, ptr)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -285,19 +320,15 @@ func (doc *docReader) addFile(src *ast.File) {
|
|||
src.Comments = nil // consumed unassociated comments - remove from ast.File node
|
||||
}
|
||||
|
||||
func NewFileDoc(file *ast.File) *PackageDoc {
|
||||
var r docReader
|
||||
r.init(file.Name.Name)
|
||||
r.addFile(file)
|
||||
return r.newDoc("", nil)
|
||||
}
|
||||
|
||||
func NewPackageDoc(pkg *ast.Package, importpath string) *PackageDoc {
|
||||
func NewPackageDoc(pkg *ast.Package, importpath string, exportsOnly bool) *PackageDoc {
|
||||
var r docReader
|
||||
r.init(pkg.Name)
|
||||
filenames := make([]string, len(pkg.Files))
|
||||
i := 0
|
||||
for filename, f := range pkg.Files {
|
||||
if exportsOnly {
|
||||
r.fileExports(f)
|
||||
}
|
||||
r.addFile(f)
|
||||
filenames[i] = filename
|
||||
i++
|
||||
|
@ -397,6 +428,25 @@ func makeFuncDocs(m map[string]*ast.FuncDecl) []*FuncDoc {
|
|||
return d
|
||||
}
|
||||
|
||||
type methodSet map[string]*FuncDoc
|
||||
|
||||
func (mset methodSet) add(m *FuncDoc) {
|
||||
if mset[m.Name] == nil {
|
||||
mset[m.Name] = m
|
||||
}
|
||||
}
|
||||
|
||||
func (mset methodSet) sortedList() []*FuncDoc {
|
||||
list := make([]*FuncDoc, len(mset))
|
||||
i := 0
|
||||
for _, m := range mset {
|
||||
list[i] = m
|
||||
i++
|
||||
}
|
||||
sort.Sort(sortFuncDoc(list))
|
||||
return list
|
||||
}
|
||||
|
||||
// TypeDoc is the documentation for a declared type.
|
||||
// Consts and Vars are sorted lists of constants and variables of (mostly) that type.
|
||||
// Factories is a sorted list of factory functions that return that type.
|
||||
|
@ -407,7 +457,9 @@ type TypeDoc struct {
|
|||
Consts []*ValueDoc
|
||||
Vars []*ValueDoc
|
||||
Factories []*FuncDoc
|
||||
Methods []*FuncDoc
|
||||
methods []*FuncDoc // top-level methods only
|
||||
embedded methodSet // embedded methods only
|
||||
Methods []*FuncDoc // all methods including embedded ones
|
||||
Decl *ast.GenDecl
|
||||
order int
|
||||
}
|
||||
|
@ -429,11 +481,17 @@ func (p sortTypeDoc) Less(i, j int) bool {
|
|||
// NOTE(rsc): This would appear not to be correct for type ( )
|
||||
// blocks, but the doc extractor above has split them into
|
||||
// individual declarations.
|
||||
func (doc *docReader) makeTypeDocs(m map[string]*typeDoc) []*TypeDoc {
|
||||
d := make([]*TypeDoc, len(m))
|
||||
func (doc *docReader) makeTypeDocs(m map[string]*typeInfo) []*TypeDoc {
|
||||
// TODO(gri) Consider computing the embedded method information
|
||||
// before calling makeTypeDocs. Then this function can
|
||||
// be single-phased again. Also, it might simplify some
|
||||
// of the logic.
|
||||
//
|
||||
// phase 1: associate collected declarations with TypeDocs
|
||||
list := make([]*TypeDoc, len(m))
|
||||
i := 0
|
||||
for _, old := range m {
|
||||
// all typeDocs should have a declaration associated with
|
||||
// all typeInfos should have a declaration associated with
|
||||
// them after processing an entire package - be conservative
|
||||
// and check
|
||||
if decl := old.decl; decl != nil {
|
||||
|
@ -451,10 +509,16 @@ func (doc *docReader) makeTypeDocs(m map[string]*typeDoc) []*TypeDoc {
|
|||
t.Consts = makeValueDocs(old.values, token.CONST)
|
||||
t.Vars = makeValueDocs(old.values, token.VAR)
|
||||
t.Factories = makeFuncDocs(old.factories)
|
||||
t.Methods = makeFuncDocs(old.methods)
|
||||
t.methods = makeFuncDocs(old.methods)
|
||||
// The list of embedded types' methods is computed from the list
|
||||
// of embedded types, some of which may not have been processed
|
||||
// yet (i.e., their forward link is nil) - do this in a 2nd phase.
|
||||
// The final list of methods can only be computed after that -
|
||||
// do this in a 3rd phase.
|
||||
t.Decl = old.decl
|
||||
t.order = i
|
||||
d[i] = t
|
||||
old.forward = t // old has been processed
|
||||
list[i] = t
|
||||
i++
|
||||
} else {
|
||||
// no corresponding type declaration found - move any associated
|
||||
|
@ -477,9 +541,99 @@ func (doc *docReader) makeTypeDocs(m map[string]*typeDoc) []*TypeDoc {
|
|||
}
|
||||
}
|
||||
}
|
||||
d = d[0:i] // some types may have been ignored
|
||||
sort.Sort(sortTypeDoc(d))
|
||||
return d
|
||||
list = list[0:i] // some types may have been ignored
|
||||
|
||||
// phase 2: collect embedded methods for each processed typeInfo
|
||||
for _, old := range m {
|
||||
if t := old.forward; t != nil {
|
||||
// old has been processed into t; collect embedded
|
||||
// methods for t from the list of processed embedded
|
||||
// types in old (and thus for which the methods are known)
|
||||
typ := t.Type
|
||||
if _, ok := typ.Type.(*ast.StructType); ok {
|
||||
// struct
|
||||
t.embedded = make(methodSet)
|
||||
collectEmbeddedMethods(t.embedded, old, typ.Name.Name)
|
||||
} else {
|
||||
// interface
|
||||
// TODO(gri) fix this
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// phase 3: compute final method set for each TypeDoc
|
||||
for _, d := range list {
|
||||
if len(d.embedded) > 0 {
|
||||
// there are embedded methods - exclude
|
||||
// the ones with names conflicting with
|
||||
// non-embedded methods
|
||||
mset := make(methodSet)
|
||||
// top-level methods have priority
|
||||
for _, m := range d.methods {
|
||||
mset.add(m)
|
||||
}
|
||||
// add non-conflicting embedded methods
|
||||
for _, m := range d.embedded {
|
||||
mset.add(m)
|
||||
}
|
||||
d.Methods = mset.sortedList()
|
||||
} else {
|
||||
// no embedded methods
|
||||
d.Methods = d.methods
|
||||
}
|
||||
}
|
||||
|
||||
sort.Sort(sortTypeDoc(list))
|
||||
return list
|
||||
}
|
||||
|
||||
// collectEmbeddedMethods collects the embedded methods from all
|
||||
// processed embedded types found in info in mset. It considers
|
||||
// embedded types at the most shallow level first so that more
|
||||
// deeply nested embedded methods with conflicting names are
|
||||
// excluded.
|
||||
//
|
||||
func collectEmbeddedMethods(mset methodSet, info *typeInfo, recvTypeName string) {
|
||||
for _, e := range info.embedded {
|
||||
if e.typ.forward != nil { // == e was processed
|
||||
for _, m := range e.typ.forward.methods {
|
||||
mset.add(customizeRecv(m, e.ptr, recvTypeName))
|
||||
}
|
||||
collectEmbeddedMethods(mset, e.typ, recvTypeName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func customizeRecv(m *FuncDoc, embeddedIsPtr bool, recvTypeName string) *FuncDoc {
|
||||
if m == nil || m.Decl == nil || m.Decl.Recv == nil || len(m.Decl.Recv.List) != 1 {
|
||||
return m // shouldn't happen, but be safe
|
||||
}
|
||||
|
||||
// copy existing receiver field and set new type
|
||||
// TODO(gri) is receiver type computation correct?
|
||||
// what about deeply nested embeddings?
|
||||
newField := *m.Decl.Recv.List[0]
|
||||
_, origRecvIsPtr := newField.Type.(*ast.StarExpr)
|
||||
var typ ast.Expr = ast.NewIdent(recvTypeName)
|
||||
if embeddedIsPtr || origRecvIsPtr {
|
||||
typ = &ast.StarExpr{token.NoPos, typ}
|
||||
}
|
||||
newField.Type = typ
|
||||
|
||||
// copy existing receiver field list and set new receiver field
|
||||
newFieldList := *m.Decl.Recv
|
||||
newFieldList.List = []*ast.Field{&newField}
|
||||
|
||||
// copy existing function declaration and set new receiver field list
|
||||
newFuncDecl := *m.Decl
|
||||
newFuncDecl.Recv = &newFieldList
|
||||
|
||||
// copy existing function documentation and set new declaration
|
||||
newM := *m
|
||||
newM.Decl = &newFuncDecl
|
||||
newM.Recv = typ
|
||||
|
||||
return &newM
|
||||
}
|
||||
|
||||
func makeBugDocs(list []*ast.CommentGroup) []string {
|
||||
|
@ -523,104 +677,3 @@ func (doc *docReader) newDoc(importpath string, filenames []string) *PackageDoc
|
|||
p.Bugs = makeBugDocs(doc.bugs)
|
||||
return p
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Filtering by name
|
||||
|
||||
type Filter func(string) bool
|
||||
|
||||
func matchFields(fields *ast.FieldList, f Filter) bool {
|
||||
if fields != nil {
|
||||
for _, field := range fields.List {
|
||||
for _, name := range field.Names {
|
||||
if f(name.Name) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func matchDecl(d *ast.GenDecl, f Filter) bool {
|
||||
for _, d := range d.Specs {
|
||||
switch v := d.(type) {
|
||||
case *ast.ValueSpec:
|
||||
for _, name := range v.Names {
|
||||
if f(name.Name) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
case *ast.TypeSpec:
|
||||
if f(v.Name.Name) {
|
||||
return true
|
||||
}
|
||||
switch t := v.Type.(type) {
|
||||
case *ast.StructType:
|
||||
if matchFields(t.Fields, f) {
|
||||
return true
|
||||
}
|
||||
case *ast.InterfaceType:
|
||||
if matchFields(t.Methods, f) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func filterValueDocs(a []*ValueDoc, f Filter) []*ValueDoc {
|
||||
w := 0
|
||||
for _, vd := range a {
|
||||
if matchDecl(vd.Decl, f) {
|
||||
a[w] = vd
|
||||
w++
|
||||
}
|
||||
}
|
||||
return a[0:w]
|
||||
}
|
||||
|
||||
func filterFuncDocs(a []*FuncDoc, f Filter) []*FuncDoc {
|
||||
w := 0
|
||||
for _, fd := range a {
|
||||
if f(fd.Name) {
|
||||
a[w] = fd
|
||||
w++
|
||||
}
|
||||
}
|
||||
return a[0:w]
|
||||
}
|
||||
|
||||
func filterTypeDocs(a []*TypeDoc, f Filter) []*TypeDoc {
|
||||
w := 0
|
||||
for _, td := range a {
|
||||
n := 0 // number of matches
|
||||
if matchDecl(td.Decl, f) {
|
||||
n = 1
|
||||
} else {
|
||||
// type name doesn't match, but we may have matching consts, vars, factories or methods
|
||||
td.Consts = filterValueDocs(td.Consts, f)
|
||||
td.Vars = filterValueDocs(td.Vars, f)
|
||||
td.Factories = filterFuncDocs(td.Factories, f)
|
||||
td.Methods = filterFuncDocs(td.Methods, f)
|
||||
n += len(td.Consts) + len(td.Vars) + len(td.Factories) + len(td.Methods)
|
||||
}
|
||||
if n > 0 {
|
||||
a[w] = td
|
||||
w++
|
||||
}
|
||||
}
|
||||
return a[0:w]
|
||||
}
|
||||
|
||||
// Filter eliminates documentation for names that don't pass through the filter f.
|
||||
// TODO: Recognize "Type.Method" as a name.
|
||||
//
|
||||
func (p *PackageDoc) Filter(f Filter) {
|
||||
p.Consts = filterValueDocs(p.Consts, f)
|
||||
p.Vars = filterValueDocs(p.Vars, f)
|
||||
p.Types = filterTypeDocs(p.Types, f)
|
||||
p.Funcs = filterFuncDocs(p.Funcs, f)
|
||||
p.Doc = "" // don't show top-level package doc
|
||||
}
|
||||
|
|
167
libgo/go/go/doc/exports.go
Normal file
167
libgo/go/go/doc/exports.go
Normal file
|
@ -0,0 +1,167 @@
|
|||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This file implements export filtering of an AST.
|
||||
|
||||
package doc
|
||||
|
||||
import "go/ast"
|
||||
|
||||
func filterIdentList(list []*ast.Ident) []*ast.Ident {
|
||||
j := 0
|
||||
for _, x := range list {
|
||||
if ast.IsExported(x.Name) {
|
||||
list[j] = x
|
||||
j++
|
||||
}
|
||||
}
|
||||
return list[0:j]
|
||||
}
|
||||
|
||||
func baseName(x ast.Expr) *ast.Ident {
|
||||
switch t := x.(type) {
|
||||
case *ast.Ident:
|
||||
return t
|
||||
case *ast.SelectorExpr:
|
||||
if _, ok := t.X.(*ast.Ident); ok {
|
||||
return t.Sel
|
||||
}
|
||||
case *ast.StarExpr:
|
||||
return baseName(t.X)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (doc *docReader) filterFieldList(fields *ast.FieldList) (removedFields bool) {
|
||||
if fields == nil {
|
||||
return false
|
||||
}
|
||||
list := fields.List
|
||||
j := 0
|
||||
for _, f := range list {
|
||||
keepField := false
|
||||
if len(f.Names) == 0 {
|
||||
// anonymous field
|
||||
name := baseName(f.Type)
|
||||
keepField = name != nil && name.IsExported()
|
||||
} else {
|
||||
n := len(f.Names)
|
||||
f.Names = filterIdentList(f.Names)
|
||||
if len(f.Names) < n {
|
||||
removedFields = true
|
||||
}
|
||||
keepField = len(f.Names) > 0
|
||||
}
|
||||
if keepField {
|
||||
doc.filterType(f.Type)
|
||||
list[j] = f
|
||||
j++
|
||||
}
|
||||
}
|
||||
if j < len(list) {
|
||||
removedFields = true
|
||||
}
|
||||
fields.List = list[0:j]
|
||||
return
|
||||
}
|
||||
|
||||
func (doc *docReader) filterParamList(fields *ast.FieldList) bool {
|
||||
if fields == nil {
|
||||
return false
|
||||
}
|
||||
var b bool
|
||||
for _, f := range fields.List {
|
||||
if doc.filterType(f.Type) {
|
||||
b = true
|
||||
}
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func (doc *docReader) filterType(typ ast.Expr) bool {
|
||||
switch t := typ.(type) {
|
||||
case *ast.Ident:
|
||||
return ast.IsExported(t.Name)
|
||||
case *ast.ParenExpr:
|
||||
return doc.filterType(t.X)
|
||||
case *ast.ArrayType:
|
||||
return doc.filterType(t.Elt)
|
||||
case *ast.StructType:
|
||||
if doc.filterFieldList(t.Fields) {
|
||||
t.Incomplete = true
|
||||
}
|
||||
return len(t.Fields.List) > 0
|
||||
case *ast.FuncType:
|
||||
b1 := doc.filterParamList(t.Params)
|
||||
b2 := doc.filterParamList(t.Results)
|
||||
return b1 || b2
|
||||
case *ast.InterfaceType:
|
||||
if doc.filterFieldList(t.Methods) {
|
||||
t.Incomplete = true
|
||||
}
|
||||
return len(t.Methods.List) > 0
|
||||
case *ast.MapType:
|
||||
b1 := doc.filterType(t.Key)
|
||||
b2 := doc.filterType(t.Value)
|
||||
return b1 || b2
|
||||
case *ast.ChanType:
|
||||
return doc.filterType(t.Value)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (doc *docReader) filterSpec(spec ast.Spec) bool {
|
||||
switch s := spec.(type) {
|
||||
case *ast.ValueSpec:
|
||||
s.Names = filterIdentList(s.Names)
|
||||
if len(s.Names) > 0 {
|
||||
doc.filterType(s.Type)
|
||||
return true
|
||||
}
|
||||
case *ast.TypeSpec:
|
||||
if ast.IsExported(s.Name.Name) {
|
||||
doc.filterType(s.Type)
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (doc *docReader) filterSpecList(list []ast.Spec) []ast.Spec {
|
||||
j := 0
|
||||
for _, s := range list {
|
||||
if doc.filterSpec(s) {
|
||||
list[j] = s
|
||||
j++
|
||||
}
|
||||
}
|
||||
return list[0:j]
|
||||
}
|
||||
|
||||
func (doc *docReader) filterDecl(decl ast.Decl) bool {
|
||||
switch d := decl.(type) {
|
||||
case *ast.GenDecl:
|
||||
d.Specs = doc.filterSpecList(d.Specs)
|
||||
return len(d.Specs) > 0
|
||||
case *ast.FuncDecl:
|
||||
return ast.IsExported(d.Name.Name)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// fileExports trims the AST for a Go file in place such that
|
||||
// only exported nodes remain. fileExports returns true if
|
||||
// there are exported declarations; otherwise it returns false.
|
||||
//
|
||||
func (doc *docReader) fileExports(src *ast.File) bool {
|
||||
j := 0
|
||||
for _, d := range src.Decls {
|
||||
if doc.filterDecl(d) {
|
||||
src.Decls[j] = d
|
||||
j++
|
||||
}
|
||||
}
|
||||
src.Decls = src.Decls[0:j]
|
||||
return j > 0
|
||||
}
|
105
libgo/go/go/doc/filter.go
Normal file
105
libgo/go/go/doc/filter.go
Normal file
|
@ -0,0 +1,105 @@
|
|||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package doc
|
||||
|
||||
import "go/ast"
|
||||
|
||||
type Filter func(string) bool
|
||||
|
||||
func matchFields(fields *ast.FieldList, f Filter) bool {
|
||||
if fields != nil {
|
||||
for _, field := range fields.List {
|
||||
for _, name := range field.Names {
|
||||
if f(name.Name) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func matchDecl(d *ast.GenDecl, f Filter) bool {
|
||||
for _, d := range d.Specs {
|
||||
switch v := d.(type) {
|
||||
case *ast.ValueSpec:
|
||||
for _, name := range v.Names {
|
||||
if f(name.Name) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
case *ast.TypeSpec:
|
||||
if f(v.Name.Name) {
|
||||
return true
|
||||
}
|
||||
switch t := v.Type.(type) {
|
||||
case *ast.StructType:
|
||||
if matchFields(t.Fields, f) {
|
||||
return true
|
||||
}
|
||||
case *ast.InterfaceType:
|
||||
if matchFields(t.Methods, f) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func filterValueDocs(a []*ValueDoc, f Filter) []*ValueDoc {
|
||||
w := 0
|
||||
for _, vd := range a {
|
||||
if matchDecl(vd.Decl, f) {
|
||||
a[w] = vd
|
||||
w++
|
||||
}
|
||||
}
|
||||
return a[0:w]
|
||||
}
|
||||
|
||||
func filterFuncDocs(a []*FuncDoc, f Filter) []*FuncDoc {
|
||||
w := 0
|
||||
for _, fd := range a {
|
||||
if f(fd.Name) {
|
||||
a[w] = fd
|
||||
w++
|
||||
}
|
||||
}
|
||||
return a[0:w]
|
||||
}
|
||||
|
||||
func filterTypeDocs(a []*TypeDoc, f Filter) []*TypeDoc {
|
||||
w := 0
|
||||
for _, td := range a {
|
||||
n := 0 // number of matches
|
||||
if matchDecl(td.Decl, f) {
|
||||
n = 1
|
||||
} else {
|
||||
// type name doesn't match, but we may have matching consts, vars, factories or methods
|
||||
td.Consts = filterValueDocs(td.Consts, f)
|
||||
td.Vars = filterValueDocs(td.Vars, f)
|
||||
td.Factories = filterFuncDocs(td.Factories, f)
|
||||
td.Methods = filterFuncDocs(td.Methods, f)
|
||||
n += len(td.Consts) + len(td.Vars) + len(td.Factories) + len(td.Methods)
|
||||
}
|
||||
if n > 0 {
|
||||
a[w] = td
|
||||
w++
|
||||
}
|
||||
}
|
||||
return a[0:w]
|
||||
}
|
||||
|
||||
// Filter eliminates documentation for names that don't pass through the filter f.
|
||||
// TODO: Recognize "Type.Method" as a name.
|
||||
//
|
||||
func (p *PackageDoc) Filter(f Filter) {
|
||||
p.Consts = filterValueDocs(p.Consts, f)
|
||||
p.Vars = filterValueDocs(p.Vars, f)
|
||||
p.Types = filterTypeDocs(p.Types, f)
|
||||
p.Funcs = filterFuncDocs(p.Funcs, f)
|
||||
p.Doc = "" // don't show top-level package doc
|
||||
}
|
|
@ -144,28 +144,31 @@ func (p *parser) declare(decl, data interface{}, scope *ast.Scope, kind ast.ObjK
|
|||
}
|
||||
}
|
||||
|
||||
func (p *parser) shortVarDecl(idents []*ast.Ident) {
|
||||
func (p *parser) shortVarDecl(decl *ast.AssignStmt, list []ast.Expr) {
|
||||
// Go spec: A short variable declaration may redeclare variables
|
||||
// provided they were originally declared in the same block with
|
||||
// the same type, and at least one of the non-blank variables is new.
|
||||
n := 0 // number of new variables
|
||||
for _, ident := range idents {
|
||||
assert(ident.Obj == nil, "identifier already declared or resolved")
|
||||
obj := ast.NewObj(ast.Var, ident.Name)
|
||||
// short var declarations cannot have redeclaration errors
|
||||
// and are not global => no need to remember the respective
|
||||
// declaration
|
||||
ident.Obj = obj
|
||||
if ident.Name != "_" {
|
||||
if alt := p.topScope.Insert(obj); alt != nil {
|
||||
ident.Obj = alt // redeclaration
|
||||
} else {
|
||||
n++ // new declaration
|
||||
for _, x := range list {
|
||||
if ident, isIdent := x.(*ast.Ident); isIdent {
|
||||
assert(ident.Obj == nil, "identifier already declared or resolved")
|
||||
obj := ast.NewObj(ast.Var, ident.Name)
|
||||
// remember corresponding assignment for other tools
|
||||
obj.Decl = decl
|
||||
ident.Obj = obj
|
||||
if ident.Name != "_" {
|
||||
if alt := p.topScope.Insert(obj); alt != nil {
|
||||
ident.Obj = alt // redeclaration
|
||||
} else {
|
||||
n++ // new declaration
|
||||
}
|
||||
}
|
||||
} else {
|
||||
p.errorExpected(x.Pos(), "identifier")
|
||||
}
|
||||
}
|
||||
if n == 0 && p.mode&DeclarationErrors != 0 {
|
||||
p.error(idents[0].Pos(), "no new variables on left side of :=")
|
||||
p.error(list[0].Pos(), "no new variables on left side of :=")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -522,7 +525,7 @@ func (p *parser) makeIdentList(list []ast.Expr) []*ast.Ident {
|
|||
for i, x := range list {
|
||||
ident, isIdent := x.(*ast.Ident)
|
||||
if !isIdent {
|
||||
pos := x.(ast.Expr).Pos()
|
||||
pos := x.Pos()
|
||||
p.errorExpected(pos, "identifier")
|
||||
ident = &ast.Ident{pos, "_", nil}
|
||||
}
|
||||
|
@ -1400,10 +1403,11 @@ func (p *parser) parseSimpleStmt(mode int) (ast.Stmt, bool) {
|
|||
} else {
|
||||
y = p.parseRhsList()
|
||||
}
|
||||
as := &ast.AssignStmt{x, pos, tok, y}
|
||||
if tok == token.DEFINE {
|
||||
p.shortVarDecl(p.makeIdentList(x))
|
||||
p.shortVarDecl(as, x)
|
||||
}
|
||||
return &ast.AssignStmt{x, pos, tok, y}, isRange
|
||||
return as, isRange
|
||||
}
|
||||
|
||||
if len(x) > 1 {
|
||||
|
@ -1715,34 +1719,28 @@ func (p *parser) parseCommClause() *ast.CommClause {
|
|||
comm = &ast.SendStmt{lhs[0], arrow, rhs}
|
||||
} else {
|
||||
// RecvStmt
|
||||
pos := p.pos
|
||||
tok := p.tok
|
||||
var rhs ast.Expr
|
||||
if tok == token.ASSIGN || tok == token.DEFINE {
|
||||
if tok := p.tok; tok == token.ASSIGN || tok == token.DEFINE {
|
||||
// RecvStmt with assignment
|
||||
if len(lhs) > 2 {
|
||||
p.errorExpected(lhs[0].Pos(), "1 or 2 expressions")
|
||||
// continue with first two expressions
|
||||
lhs = lhs[0:2]
|
||||
}
|
||||
pos := p.pos
|
||||
p.next()
|
||||
rhs = p.parseRhs()
|
||||
if tok == token.DEFINE && lhs != nil {
|
||||
p.shortVarDecl(p.makeIdentList(lhs))
|
||||
rhs := p.parseRhs()
|
||||
as := &ast.AssignStmt{lhs, pos, tok, []ast.Expr{rhs}}
|
||||
if tok == token.DEFINE {
|
||||
p.shortVarDecl(as, lhs)
|
||||
}
|
||||
comm = as
|
||||
} else {
|
||||
// rhs must be single receive operation
|
||||
// lhs must be single receive operation
|
||||
if len(lhs) > 1 {
|
||||
p.errorExpected(lhs[0].Pos(), "1 expression")
|
||||
// continue with first expression
|
||||
}
|
||||
rhs = lhs[0]
|
||||
lhs = nil // there is no lhs
|
||||
}
|
||||
if lhs != nil {
|
||||
comm = &ast.AssignStmt{lhs, pos, tok, []ast.Expr{rhs}}
|
||||
} else {
|
||||
comm = &ast.ExprStmt{rhs}
|
||||
comm = &ast.ExprStmt{lhs[0]}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -39,7 +39,10 @@ import (
|
|||
// future (not yet interspersed) comments in this function.
|
||||
//
|
||||
func (p *printer) linebreak(line, min int, ws whiteSpace, newSection bool) (printedBreak bool) {
|
||||
n := p.nlines(line-p.pos.Line, min)
|
||||
n := nlimit(line - p.pos.Line)
|
||||
if n < min {
|
||||
n = min
|
||||
}
|
||||
if n > 0 {
|
||||
p.print(ws)
|
||||
if newSection {
|
||||
|
@ -361,9 +364,10 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
|
|||
lbrace := fields.Opening
|
||||
list := fields.List
|
||||
rbrace := fields.Closing
|
||||
hasComments := isIncomplete || p.commentBefore(p.fset.Position(rbrace))
|
||||
srcIsOneLine := lbrace.IsValid() && rbrace.IsValid() && p.fset.Position(lbrace).Line == p.fset.Position(rbrace).Line
|
||||
|
||||
if !isIncomplete && !p.commentBefore(p.fset.Position(rbrace)) && srcIsOneLine {
|
||||
if !hasComments && srcIsOneLine {
|
||||
// possibly a one-line struct/interface
|
||||
if len(list) == 0 {
|
||||
// no blank between keyword and {} in this case
|
||||
|
@ -388,9 +392,13 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
|
|||
return
|
||||
}
|
||||
}
|
||||
// hasComments || !srcIsOneLine
|
||||
|
||||
p.print(blank, lbrace, token.LBRACE, indent)
|
||||
if hasComments || len(list) > 0 {
|
||||
p.print(formfeed)
|
||||
}
|
||||
|
||||
// at least one entry or incomplete
|
||||
p.print(blank, lbrace, token.LBRACE, indent, formfeed)
|
||||
if isStruct {
|
||||
|
||||
sep := vtab
|
||||
|
@ -1509,9 +1517,14 @@ func (p *printer) file(src *ast.File) {
|
|||
prev := tok
|
||||
tok = declToken(d)
|
||||
// if the declaration token changed (e.g., from CONST to TYPE)
|
||||
// or the next declaration has documentation associated with it,
|
||||
// print an empty line between top-level declarations
|
||||
// (because p.linebreak is called with the position of d, which
|
||||
// is past any documentation, the minimum requirement is satisfied
|
||||
// even w/o the extra getDoc(d) nil-check - leave it in case the
|
||||
// linebreak logic improves - there's already a TODO).
|
||||
min := 1
|
||||
if prev != tok {
|
||||
if prev != tok || getDoc(d) != nil {
|
||||
min = 2
|
||||
}
|
||||
p.linebreak(p.fset.Position(d.Pos()).Line, min, ignore, false)
|
||||
|
|
|
@ -18,8 +18,11 @@ import (
|
|||
"text/tabwriter"
|
||||
)
|
||||
|
||||
const debug = false // enable for debugging
|
||||
const infinity = 1 << 30
|
||||
const (
|
||||
maxNewlines = 2 // max. number of newlines between source text
|
||||
debug = false // enable for debugging
|
||||
infinity = 1 << 30
|
||||
)
|
||||
|
||||
type whiteSpace byte
|
||||
|
||||
|
@ -89,21 +92,7 @@ func (p *printer) internalError(msg ...interface{}) {
|
|||
}
|
||||
}
|
||||
|
||||
// nlines returns the adjusted number of linebreaks given the desired number
|
||||
// of breaks n such that min <= result <= max.
|
||||
//
|
||||
func (p *printer) nlines(n, min int) int {
|
||||
const max = 2 // max. number of newlines
|
||||
switch {
|
||||
case n < min:
|
||||
return min
|
||||
case n > max:
|
||||
return max
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// writeByte writes a single byte to p.output and updates p.pos.
|
||||
// writeByte writes ch to p.output and updates p.pos.
|
||||
func (p *printer) writeByte(ch byte) {
|
||||
p.output.WriteByte(ch)
|
||||
p.pos.Offset++
|
||||
|
@ -128,13 +117,11 @@ func (p *printer) writeByte(ch byte) {
|
|||
}
|
||||
}
|
||||
|
||||
// writeNewlines writes up to n newlines to p.output and updates p.pos.
|
||||
// The actual number of newlines written is limited by nlines.
|
||||
// nl must be one of '\n' or '\f'.
|
||||
//
|
||||
func (p *printer) writeNewlines(n int, nl byte) {
|
||||
for n = p.nlines(n, 0); n > 0; n-- {
|
||||
p.writeByte(nl)
|
||||
// writeByteN writes ch n times to p.output and updates p.pos.
|
||||
func (p *printer) writeByteN(ch byte, n int) {
|
||||
for n > 0 {
|
||||
p.writeByte(ch)
|
||||
n--
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -223,8 +210,8 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, prev, comment *as
|
|||
}
|
||||
|
||||
if pos.IsValid() && pos.Filename != p.last.Filename {
|
||||
// comment in a different file - separate with newlines (writeNewlines will limit the number)
|
||||
p.writeNewlines(10, '\f')
|
||||
// comment in a different file - separate with newlines
|
||||
p.writeByteN('\f', maxNewlines)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -270,6 +257,7 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, prev, comment *as
|
|||
} else {
|
||||
// comment on a different line:
|
||||
// separate with at least one line break
|
||||
droppedLinebreak := false
|
||||
if prev == nil {
|
||||
// first comment of a comment group
|
||||
j := 0
|
||||
|
@ -295,6 +283,7 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, prev, comment *as
|
|||
case newline, formfeed:
|
||||
// TODO(gri): may want to keep formfeed info in some cases
|
||||
p.wsbuf[i] = ignore
|
||||
droppedLinebreak = true
|
||||
}
|
||||
j = i
|
||||
break
|
||||
|
@ -302,25 +291,41 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, prev, comment *as
|
|||
p.writeWhitespace(j)
|
||||
}
|
||||
|
||||
// turn off indent if we're about to print a line directive.
|
||||
indent := p.indent
|
||||
if strings.HasPrefix(comment.Text, linePrefix) {
|
||||
p.indent = 0
|
||||
// determine number of linebreaks before the comment
|
||||
n := 0
|
||||
if pos.IsValid() && p.last.IsValid() {
|
||||
n = pos.Line - p.last.Line
|
||||
if n < 0 { // should never happen
|
||||
n = 0
|
||||
}
|
||||
}
|
||||
|
||||
// use formfeeds to break columns before a comment;
|
||||
// this is analogous to using formfeeds to separate
|
||||
// individual lines of /*-style comments - but make
|
||||
// sure there is at least one line break if the previous
|
||||
// comment was a line comment
|
||||
n := pos.Line - p.last.Line // if !pos.IsValid(), pos.Line == 0, and n will be 0
|
||||
if n <= 0 && prev != nil && prev.Text[1] == '/' {
|
||||
// at the package scope level only (p.indent == 0),
|
||||
// add an extra newline if we dropped one before:
|
||||
// this preserves a blank line before documentation
|
||||
// comments at the package scope level (issue 2570)
|
||||
if p.indent == 0 && droppedLinebreak {
|
||||
n++
|
||||
}
|
||||
|
||||
// make sure there is at least one line break
|
||||
// if the previous comment was a line comment
|
||||
if n == 0 && prev != nil && prev.Text[1] == '/' {
|
||||
n = 1
|
||||
}
|
||||
|
||||
if n > 0 {
|
||||
p.writeNewlines(n, '\f')
|
||||
// turn off indent if we're about to print a line directive
|
||||
indent := p.indent
|
||||
if strings.HasPrefix(comment.Text, linePrefix) {
|
||||
p.indent = 0
|
||||
}
|
||||
// use formfeeds to break columns before a comment;
|
||||
// this is analogous to using formfeeds to separate
|
||||
// individual lines of /*-style comments
|
||||
p.writeByteN('\f', nlimit(n))
|
||||
p.indent = indent // restore indent
|
||||
}
|
||||
p.indent = indent
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -550,10 +555,11 @@ func (p *printer) writeComment(comment *ast.Comment) {
|
|||
// writeCommentSuffix writes a line break after a comment if indicated
|
||||
// and processes any leftover indentation information. If a line break
|
||||
// is needed, the kind of break (newline vs formfeed) depends on the
|
||||
// pending whitespace. writeCommentSuffix returns true if a pending
|
||||
// formfeed was dropped from the whitespace buffer.
|
||||
// pending whitespace. The writeCommentSuffix result indicates if a
|
||||
// newline was written or if a formfeed was dropped from the whitespace
|
||||
// buffer.
|
||||
//
|
||||
func (p *printer) writeCommentSuffix(needsLinebreak bool) (droppedFF bool) {
|
||||
func (p *printer) writeCommentSuffix(needsLinebreak bool) (wroteNewline, droppedFF bool) {
|
||||
for i, ch := range p.wsbuf {
|
||||
switch ch {
|
||||
case blank, vtab:
|
||||
|
@ -566,6 +572,7 @@ func (p *printer) writeCommentSuffix(needsLinebreak bool) (droppedFF bool) {
|
|||
// but remember if we dropped any formfeeds
|
||||
if needsLinebreak {
|
||||
needsLinebreak = false
|
||||
wroteNewline = true
|
||||
} else {
|
||||
if ch == formfeed {
|
||||
droppedFF = true
|
||||
|
@ -579,6 +586,7 @@ func (p *printer) writeCommentSuffix(needsLinebreak bool) (droppedFF bool) {
|
|||
// make sure we have a line break
|
||||
if needsLinebreak {
|
||||
p.writeByte('\n')
|
||||
wroteNewline = true
|
||||
}
|
||||
|
||||
return
|
||||
|
@ -587,10 +595,10 @@ func (p *printer) writeCommentSuffix(needsLinebreak bool) (droppedFF bool) {
|
|||
// intersperseComments consumes all comments that appear before the next token
|
||||
// tok and prints it together with the buffered whitespace (i.e., the whitespace
|
||||
// that needs to be written before the next token). A heuristic is used to mix
|
||||
// the comments and whitespace. intersperseComments returns true if a pending
|
||||
// formfeed was dropped from the whitespace buffer.
|
||||
// the comments and whitespace. The intersperseComments result indicates if a
|
||||
// newline was written or if a formfeed was dropped from the whitespace buffer.
|
||||
//
|
||||
func (p *printer) intersperseComments(next token.Position, tok token.Token) (droppedFF bool) {
|
||||
func (p *printer) intersperseComments(next token.Position, tok token.Token) (wroteNewline, droppedFF bool) {
|
||||
var last *ast.Comment
|
||||
for ; p.commentBefore(next); p.cindex++ {
|
||||
for _, c := range p.comments[p.cindex].List {
|
||||
|
@ -618,7 +626,7 @@ func (p *printer) intersperseComments(next token.Position, tok token.Token) (dro
|
|||
// no comment was written - we should never reach here since
|
||||
// intersperseComments should not be called in that case
|
||||
p.internalError("intersperseComments called without pending comments")
|
||||
return false
|
||||
return
|
||||
}
|
||||
|
||||
// whiteWhitespace writes the first n whitespace entries.
|
||||
|
@ -671,6 +679,14 @@ func (p *printer) writeWhitespace(n int) {
|
|||
// ----------------------------------------------------------------------------
|
||||
// Printing interface
|
||||
|
||||
// nlines limits n to maxNewlines.
|
||||
func nlimit(n int) int {
|
||||
if n > maxNewlines {
|
||||
n = maxNewlines
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func mayCombine(prev token.Token, next byte) (b bool) {
|
||||
switch prev {
|
||||
case token.INT:
|
||||
|
@ -765,17 +781,22 @@ func (p *printer) print(args ...interface{}) {
|
|||
p.pos = next
|
||||
|
||||
if data != "" {
|
||||
nl := byte('\n')
|
||||
if p.flush(next, tok) {
|
||||
nl = '\f' // dropped formfeed before
|
||||
}
|
||||
wroteNewline, droppedFF := p.flush(next, tok)
|
||||
|
||||
// intersperse extra newlines if present in the source
|
||||
// (don't do this in flush as it will cause extra newlines
|
||||
// at the end of a file) - use formfeeds if we dropped one
|
||||
// before
|
||||
if n := next.Line - p.pos.Line; n > 0 {
|
||||
p.writeNewlines(n, nl)
|
||||
// at the end of a file)
|
||||
n := nlimit(next.Line - p.pos.Line)
|
||||
// don't exceed maxNewlines if we already wrote one
|
||||
if wroteNewline && n == maxNewlines {
|
||||
n = maxNewlines - 1
|
||||
}
|
||||
if n > 0 {
|
||||
ch := byte('\n')
|
||||
if droppedFF {
|
||||
ch = '\f' // use formfeed since we dropped one before
|
||||
}
|
||||
p.writeByteN(ch, n)
|
||||
}
|
||||
|
||||
p.writeItem(next, data, isLit)
|
||||
|
@ -790,16 +811,15 @@ func (p *printer) commentBefore(next token.Position) bool {
|
|||
return p.cindex < len(p.comments) && p.fset.Position(p.comments[p.cindex].List[0].Pos()).Offset < next.Offset
|
||||
}
|
||||
|
||||
// Flush prints any pending comments and whitespace occurring
|
||||
// textually before the position of the next token tok. Flush
|
||||
// returns true if a pending formfeed character was dropped
|
||||
// from the whitespace buffer as a result of interspersing
|
||||
// comments.
|
||||
// Flush prints any pending comments and whitespace occurring textually
|
||||
// before the position of the next token tok. The Flush result indicates
|
||||
// if a newline was written or if a formfeed was dropped from the whitespace
|
||||
// buffer.
|
||||
//
|
||||
func (p *printer) flush(next token.Position, tok token.Token) (droppedFF bool) {
|
||||
func (p *printer) flush(next token.Position, tok token.Token) (wroteNewline, droppedFF bool) {
|
||||
if p.commentBefore(next) {
|
||||
// if there are comments before the next item, intersperse them
|
||||
droppedFF = p.intersperseComments(next, tok)
|
||||
wroteNewline, droppedFF = p.intersperseComments(next, tok)
|
||||
} else {
|
||||
// otherwise, write any leftover whitespace
|
||||
p.writeWhitespace(len(p.wsbuf))
|
||||
|
@ -810,7 +830,8 @@ func (p *printer) flush(next token.Position, tok token.Token) (droppedFF bool) {
|
|||
// getNode returns the ast.CommentGroup associated with n, if any.
|
||||
func getDoc(n ast.Node) *ast.CommentGroup {
|
||||
switch n := n.(type) {
|
||||
// *ast.Fields cannot be printed separately - ignore for now
|
||||
case *ast.Field:
|
||||
return n.Doc
|
||||
case *ast.ImportSpec:
|
||||
return n.Doc
|
||||
case *ast.ValueSpec:
|
||||
|
|
5
libgo/go/go/printer/testdata/comments.golden
vendored
5
libgo/go/go/printer/testdata/comments.golden
vendored
|
@ -106,7 +106,7 @@ type S3 struct {
|
|||
var x int // x
|
||||
var ()
|
||||
|
||||
// This comment SHOULD be associated with the next declaration.
|
||||
// This comment SHOULD be associated with f0.
|
||||
func f0() {
|
||||
const pi = 3.14 // pi
|
||||
var s1 struct{} /* an empty struct */ /* foo */
|
||||
|
@ -115,8 +115,9 @@ func f0() {
|
|||
var s2 struct{} = struct{}{}
|
||||
x := pi
|
||||
}
|
||||
|
||||
//
|
||||
// NO SPACE HERE
|
||||
// This comment should be associated with f1, with one blank line before the comment.
|
||||
//
|
||||
func f1() {
|
||||
f0()
|
||||
|
|
6
libgo/go/go/printer/testdata/comments.input
vendored
6
libgo/go/go/printer/testdata/comments.input
vendored
|
@ -107,7 +107,7 @@ var x int // x
|
|||
var ()
|
||||
|
||||
|
||||
// This comment SHOULD be associated with the next declaration.
|
||||
// This comment SHOULD be associated with f0.
|
||||
func f0() {
|
||||
const pi = 3.14 // pi
|
||||
var s1 struct {} /* an empty struct */ /* foo */
|
||||
|
@ -117,7 +117,7 @@ func f0() {
|
|||
x := pi
|
||||
}
|
||||
//
|
||||
// NO SPACE HERE
|
||||
// This comment should be associated with f1, with one blank line before the comment.
|
||||
//
|
||||
func f1() {
|
||||
f0()
|
||||
|
@ -130,7 +130,7 @@ func f1() {
|
|||
|
||||
|
||||
func _() {
|
||||
// this comment should be properly indented
|
||||
// this comment should be properly indented
|
||||
}
|
||||
|
||||
|
||||
|
|
21
libgo/go/go/printer/testdata/declarations.golden
vendored
21
libgo/go/go/printer/testdata/declarations.golden
vendored
|
@ -115,6 +115,18 @@ import _ "io"
|
|||
|
||||
var _ int
|
||||
|
||||
// at least one empty line between declarations of the same kind
|
||||
// if there is associated documentation (was issue 2570)
|
||||
type T1 struct{}
|
||||
|
||||
// T2 comment
|
||||
type T2 struct {
|
||||
} // should be a two-line struct
|
||||
|
||||
// T3 comment
|
||||
type T2 struct {
|
||||
} // should be a two-line struct
|
||||
|
||||
// printing of constant literals
|
||||
const (
|
||||
_ = "foobar"
|
||||
|
@ -286,6 +298,15 @@ type _ struct {
|
|||
}
|
||||
}
|
||||
|
||||
// no blank lines in empty structs and interfaces, but leave 1- or 2-line layout alone
|
||||
type _ struct{}
|
||||
type _ struct {
|
||||
}
|
||||
|
||||
type _ interface{}
|
||||
type _ interface {
|
||||
}
|
||||
|
||||
// no tabs for single or ungrouped decls
|
||||
func _() {
|
||||
const xxxxxx = 0
|
||||
|
|
26
libgo/go/go/printer/testdata/declarations.input
vendored
26
libgo/go/go/printer/testdata/declarations.input
vendored
|
@ -115,6 +115,20 @@ import (
|
|||
import _ "io"
|
||||
var _ int
|
||||
|
||||
// at least one empty line between declarations of the same kind
|
||||
// if there is associated documentation (was issue 2570)
|
||||
type T1 struct{}
|
||||
// T2 comment
|
||||
type T2 struct {
|
||||
} // should be a two-line struct
|
||||
|
||||
|
||||
// T3 comment
|
||||
type T2 struct {
|
||||
|
||||
|
||||
} // should be a two-line struct
|
||||
|
||||
|
||||
// printing of constant literals
|
||||
const (
|
||||
|
@ -293,6 +307,18 @@ type _ struct {
|
|||
}
|
||||
|
||||
|
||||
// no blank lines in empty structs and interfaces, but leave 1- or 2-line layout alone
|
||||
type _ struct{ }
|
||||
type _ struct {
|
||||
|
||||
}
|
||||
|
||||
type _ interface{ }
|
||||
type _ interface {
|
||||
|
||||
}
|
||||
|
||||
|
||||
// no tabs for single or ungrouped decls
|
||||
func _() {
|
||||
const xxxxxx = 0
|
||||
|
|
|
@ -271,7 +271,6 @@ func _() {
|
|||
// Known bug: The first use call may have more than one empty line before
|
||||
// (see go/printer/nodes.go, func linebreak).
|
||||
|
||||
|
||||
use(x)
|
||||
|
||||
if x < x {
|
||||
|
@ -386,7 +385,6 @@ L: // A comment on the same line as the label, followed by a single empty line.
|
|||
// Known bug: There may be more than one empty line before MoreCode()
|
||||
// (see go/printer/nodes.go, func linebreak).
|
||||
|
||||
|
||||
MoreCode()
|
||||
}
|
||||
|
||||
|
|
|
@ -426,13 +426,16 @@ func (S *Scanner) scanString() {
|
|||
S.next()
|
||||
}
|
||||
|
||||
func (S *Scanner) scanRawString() {
|
||||
func (S *Scanner) scanRawString() (hasCR bool) {
|
||||
// '`' opening already consumed
|
||||
offs := S.offset - 1
|
||||
|
||||
for S.ch != '`' {
|
||||
ch := S.ch
|
||||
S.next()
|
||||
if ch == '\r' {
|
||||
hasCR = true
|
||||
}
|
||||
if ch < 0 {
|
||||
S.error(offs, "string not terminated")
|
||||
break
|
||||
|
@ -440,6 +443,7 @@ func (S *Scanner) scanRawString() {
|
|||
}
|
||||
|
||||
S.next()
|
||||
return
|
||||
}
|
||||
|
||||
func (S *Scanner) skipWhitespace() {
|
||||
|
@ -490,6 +494,18 @@ func (S *Scanner) switch4(tok0, tok1 token.Token, ch2 rune, tok2, tok3 token.Tok
|
|||
return tok0
|
||||
}
|
||||
|
||||
func stripCR(b []byte) []byte {
|
||||
c := make([]byte, len(b))
|
||||
i := 0
|
||||
for _, ch := range b {
|
||||
if ch != '\r' {
|
||||
c[i] = ch
|
||||
i++
|
||||
}
|
||||
}
|
||||
return c[:i]
|
||||
}
|
||||
|
||||
// Scan scans the next token and returns the token position,
|
||||
// the token, and the literal string corresponding to the
|
||||
// token. The source end is indicated by token.EOF.
|
||||
|
@ -518,6 +534,7 @@ scanAgain:
|
|||
insertSemi := false
|
||||
offs := S.offset
|
||||
tok := token.ILLEGAL
|
||||
hasCR := false
|
||||
|
||||
// determine token value
|
||||
switch ch := S.ch; {
|
||||
|
@ -556,7 +573,7 @@ scanAgain:
|
|||
case '`':
|
||||
insertSemi = true
|
||||
tok = token.STRING
|
||||
S.scanRawString()
|
||||
hasCR = S.scanRawString()
|
||||
case ':':
|
||||
tok = S.switch2(token.COLON, token.DEFINE)
|
||||
case '.':
|
||||
|
@ -663,5 +680,9 @@ scanAgain:
|
|||
// TODO(gri): The scanner API should change such that the literal string
|
||||
// is only valid if an actual literal was scanned. This will
|
||||
// permit a more efficient implementation.
|
||||
return S.file.Pos(offs), tok, string(S.src[offs:S.offset])
|
||||
lit := S.src[offs:S.offset]
|
||||
if hasCR {
|
||||
lit = stripCR(lit)
|
||||
}
|
||||
return S.file.Pos(offs), tok, string(lit)
|
||||
}
|
||||
|
|
|
@ -83,6 +83,8 @@ var tokens = [...]elt{
|
|||
"`",
|
||||
literal,
|
||||
},
|
||||
{token.STRING, "`\r`", literal},
|
||||
{token.STRING, "`foo\r\nbar`", literal},
|
||||
|
||||
// Operators and delimiters
|
||||
{token.ADD, "+", operator},
|
||||
|
@ -239,8 +241,16 @@ func TestScan(t *testing.T) {
|
|||
if tok != e.tok {
|
||||
t.Errorf("bad token for %q: got %s, expected %s", lit, tok, e.tok)
|
||||
}
|
||||
if e.tok.IsLiteral() && lit != e.lit {
|
||||
t.Errorf("bad literal for %q: got %q, expected %q", lit, lit, e.lit)
|
||||
if e.tok.IsLiteral() {
|
||||
// no CRs in raw string literals
|
||||
elit := e.lit
|
||||
if elit[0] == '`' {
|
||||
elit = string(stripCR([]byte(elit)))
|
||||
epos.Offset += len(e.lit) - len(lit) // correct position
|
||||
}
|
||||
if lit != elit {
|
||||
t.Errorf("bad literal for %q: got %q, expected %q", lit, lit, elit)
|
||||
}
|
||||
}
|
||||
if tokenclass(tok) != e.class {
|
||||
t.Errorf("bad class for %q: got %d, expected %d", lit, tokenclass(tok), e.class)
|
||||
|
|
|
@ -7,7 +7,7 @@ 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 isSpecialElement = map[string]bool{
|
||||
var isSpecialElementMap = map[string]bool{
|
||||
"address": true,
|
||||
"applet": true,
|
||||
"area": true,
|
||||
|
@ -88,3 +88,13 @@ var isSpecialElement = map[string]bool{
|
|||
"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
|
||||
}
|
||||
|
|
|
@ -319,10 +319,7 @@ func (p *parser) resetInsertionMode() {
|
|||
case "html":
|
||||
p.im = beforeHeadIM
|
||||
default:
|
||||
if p.top().Namespace == "" {
|
||||
continue
|
||||
}
|
||||
p.im = inForeignContentIM
|
||||
continue
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -705,7 +702,7 @@ func inBodyIM(p *parser) bool {
|
|||
case "address", "div", "p":
|
||||
continue
|
||||
default:
|
||||
if !isSpecialElement[node.Data] {
|
||||
if !isSpecialElement(node) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
@ -723,7 +720,7 @@ func inBodyIM(p *parser) bool {
|
|||
case "address", "div", "p":
|
||||
continue
|
||||
default:
|
||||
if !isSpecialElement[node.Data] {
|
||||
if !isSpecialElement(node) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
@ -814,7 +811,6 @@ func inBodyIM(p *parser) bool {
|
|||
// TODO: adjust foreign attributes.
|
||||
p.addElement(p.tok.Data, p.tok.Attr)
|
||||
p.top().Namespace = namespace
|
||||
p.im = inForeignContentIM
|
||||
return true
|
||||
case "caption", "col", "colgroup", "frame", "head", "tbody", "td", "tfoot", "th", "thead", "tr":
|
||||
// Ignore the token.
|
||||
|
@ -895,7 +891,7 @@ func (p *parser) inBodyEndTagFormatting(tag string) {
|
|||
// Steps 5-6. Find the furthest block.
|
||||
var furthestBlock *Node
|
||||
for _, e := range p.oe[feIndex:] {
|
||||
if isSpecialElement[e.Data] {
|
||||
if isSpecialElement(e) {
|
||||
furthestBlock = e
|
||||
break
|
||||
}
|
||||
|
@ -988,7 +984,7 @@ func (p *parser) inBodyEndTagOther(tag string) {
|
|||
p.oe = p.oe[:i]
|
||||
break
|
||||
}
|
||||
if isSpecialElement[p.oe[i].Data] {
|
||||
if isSpecialElement(p.oe[i]) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -1206,6 +1202,13 @@ func inTableBodyIM(p *parser) bool {
|
|||
add = true
|
||||
data = "tr"
|
||||
consumed = false
|
||||
case "caption", "col", "colgroup", "tbody", "tfoot", "thead":
|
||||
if !p.popUntil(tableScopeStopTags, "tbody", "thead", "tfoot") {
|
||||
// Ignore the token.
|
||||
return true
|
||||
}
|
||||
p.im = inTableIM
|
||||
return false
|
||||
default:
|
||||
// TODO.
|
||||
}
|
||||
|
@ -1569,6 +1572,19 @@ func afterAfterFramesetIM(p *parser) bool {
|
|||
Type: CommentNode,
|
||||
Data: p.tok.Data,
|
||||
})
|
||||
case TextToken:
|
||||
// Ignore all text but whitespace.
|
||||
s := strings.Map(func(c rune) rune {
|
||||
switch c {
|
||||
case ' ', '\t', '\n', '\f', '\r':
|
||||
return c
|
||||
}
|
||||
return -1
|
||||
}, p.tok.Data)
|
||||
if s != "" {
|
||||
p.reconstructActiveFormattingElements()
|
||||
p.addText(s)
|
||||
}
|
||||
case StartTagToken:
|
||||
switch p.tok.Data {
|
||||
case "html":
|
||||
|
@ -1583,8 +1599,19 @@ func afterAfterFramesetIM(p *parser) bool {
|
|||
}
|
||||
|
||||
// Section 12.2.5.5.
|
||||
func inForeignContentIM(p *parser) bool {
|
||||
func parseForeignContent(p *parser) bool {
|
||||
switch p.tok.Type {
|
||||
case TextToken:
|
||||
// TODO: HTML integration points.
|
||||
if p.top().Namespace == "" {
|
||||
inBodyIM(p)
|
||||
p.resetInsertionMode()
|
||||
return true
|
||||
}
|
||||
if p.framesetOK {
|
||||
p.framesetOK = strings.TrimLeft(p.tok.Data, whitespace) == ""
|
||||
}
|
||||
p.addText(p.tok.Data)
|
||||
case CommentToken:
|
||||
p.addChild(&Node{
|
||||
Type: CommentNode,
|
||||
|
@ -1592,7 +1619,14 @@ func inForeignContentIM(p *parser) bool {
|
|||
})
|
||||
case StartTagToken:
|
||||
if breakout[p.tok.Data] {
|
||||
// TODO.
|
||||
for i := len(p.oe) - 1; i >= 0; i-- {
|
||||
// TODO: HTML, MathML integration points.
|
||||
if p.oe[i].Namespace == "" {
|
||||
p.oe = p.oe[:i+1]
|
||||
break
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
switch p.top().Namespace {
|
||||
case "mathml":
|
||||
|
@ -1606,13 +1640,36 @@ func inForeignContentIM(p *parser) bool {
|
|||
// TODO: adjust foreign attributes.
|
||||
p.addElement(p.tok.Data, p.tok.Attr)
|
||||
case EndTagToken:
|
||||
// TODO.
|
||||
for i := len(p.oe) - 1; i >= 0; i-- {
|
||||
if p.oe[i].Namespace == "" {
|
||||
return p.im(p)
|
||||
}
|
||||
if strings.EqualFold(p.oe[i].Data, p.tok.Data) {
|
||||
p.oe = p.oe[:i]
|
||||
break
|
||||
}
|
||||
}
|
||||
return true
|
||||
default:
|
||||
// Ignore the token.
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Section 12.2.5.
|
||||
func (p *parser) inForeignContent() bool {
|
||||
if len(p.oe) == 0 {
|
||||
return false
|
||||
}
|
||||
n := p.oe[len(p.oe)-1]
|
||||
if n.Namespace == "" {
|
||||
return false
|
||||
}
|
||||
// TODO: MathML, HTML integration points.
|
||||
// TODO: MathML's annotation-xml combining with SVG's svg.
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *parser) parse() error {
|
||||
// Iterate until EOF. Any other error will cause an early return.
|
||||
consumed := true
|
||||
|
@ -1625,7 +1682,11 @@ func (p *parser) parse() error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
consumed = p.im(p)
|
||||
if p.inForeignContent() {
|
||||
consumed = parseForeignContent(p)
|
||||
} else {
|
||||
consumed = p.im(p)
|
||||
}
|
||||
}
|
||||
// Loop until the final token (the ErrorToken signifying EOF) is consumed.
|
||||
for {
|
||||
|
|
|
@ -172,7 +172,8 @@ func TestParser(t *testing.T) {
|
|||
{"tests3.dat", -1},
|
||||
{"tests4.dat", -1},
|
||||
{"tests5.dat", -1},
|
||||
{"tests6.dat", 36},
|
||||
{"tests6.dat", 47},
|
||||
{"tests10.dat", 16},
|
||||
}
|
||||
for _, tf := range testFiles {
|
||||
f, err := os.Open("testdata/webkit/" + tf.filename)
|
||||
|
|
|
@ -183,11 +183,11 @@ const (
|
|||
|
||||
func (e *Error) Error() string {
|
||||
if e.Line != 0 {
|
||||
return fmt.Sprintf("exp/template/html:%s:%d: %s", e.Name, e.Line, e.Description)
|
||||
return fmt.Sprintf("html/template:%s:%d: %s", e.Name, e.Line, e.Description)
|
||||
} else if e.Name != "" {
|
||||
return fmt.Sprintf("exp/template/html:%s: %s", e.Name, e.Description)
|
||||
return fmt.Sprintf("html/template:%s: %s", e.Name, e.Description)
|
||||
}
|
||||
return "exp/template/html: " + e.Description
|
||||
return "html/template: " + e.Description
|
||||
}
|
||||
|
||||
// errorf creates an error given a format string f and args.
|
||||
|
|
|
@ -486,9 +486,17 @@ func (e *escaper) escapeTree(c context, name string, line int) (context, string)
|
|||
}
|
||||
t := e.template(name)
|
||||
if t == nil {
|
||||
// Two cases: The template exists but is empty, or has never been mentioned at
|
||||
// all. Distinguish the cases in the error messages.
|
||||
if e.tmpl.set[name] != nil {
|
||||
return context{
|
||||
state: stateError,
|
||||
err: errorf(ErrNoSuchTemplate, line, "%q is an incomplete or empty template", name),
|
||||
}, dname
|
||||
}
|
||||
return context{
|
||||
state: stateError,
|
||||
err: errorf(ErrNoSuchTemplate, line, "no such template %s", name),
|
||||
err: errorf(ErrNoSuchTemplate, line, "no such template %q", name),
|
||||
}, dname
|
||||
}
|
||||
if dname != name {
|
||||
|
|
|
@ -928,7 +928,7 @@ func TestErrors(t *testing.T) {
|
|||
},
|
||||
{
|
||||
`{{template "foo"}}`,
|
||||
"z:1: no such template foo",
|
||||
"z:1: no such template \"foo\"",
|
||||
},
|
||||
{
|
||||
`<div{{template "y"}}>` +
|
||||
|
@ -944,23 +944,23 @@ func TestErrors(t *testing.T) {
|
|||
},
|
||||
{
|
||||
`<input type=button value=onclick=>`,
|
||||
`exp/template/html:z: "=" in unquoted attr: "onclick="`,
|
||||
`html/template:z: "=" in unquoted attr: "onclick="`,
|
||||
},
|
||||
{
|
||||
`<input type=button value= onclick=>`,
|
||||
`exp/template/html:z: "=" in unquoted attr: "onclick="`,
|
||||
`html/template:z: "=" in unquoted attr: "onclick="`,
|
||||
},
|
||||
{
|
||||
`<input type=button value= 1+1=2>`,
|
||||
`exp/template/html:z: "=" in unquoted attr: "1+1=2"`,
|
||||
`html/template:z: "=" in unquoted attr: "1+1=2"`,
|
||||
},
|
||||
{
|
||||
"<a class=`foo>",
|
||||
"exp/template/html:z: \"`\" in unquoted attr: \"`foo\"",
|
||||
"html/template:z: \"`\" in unquoted attr: \"`foo\"",
|
||||
},
|
||||
{
|
||||
`<a style=font:'Arial'>`,
|
||||
`exp/template/html:z: "'" in unquoted attr: "font:'Arial'"`,
|
||||
`html/template:z: "'" in unquoted attr: "font:'Arial'"`,
|
||||
},
|
||||
{
|
||||
`<a=foo>`,
|
||||
|
|
99
libgo/go/image/color/ycbcr.go
Normal file
99
libgo/go/image/color/ycbcr.go
Normal file
|
@ -0,0 +1,99 @@
|
|||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package color
|
||||
|
||||
// RGBToYCbCr converts an RGB triple to a Y'CbCr triple. All components lie
|
||||
// within the range [0, 255].
|
||||
func RGBToYCbCr(r, g, b uint8) (uint8, uint8, uint8) {
|
||||
// The JFIF specification says:
|
||||
// Y' = 0.2990*R + 0.5870*G + 0.1140*B
|
||||
// Cb = -0.1687*R - 0.3313*G + 0.5000*B + 128
|
||||
// Cr = 0.5000*R - 0.4187*G - 0.0813*B + 128
|
||||
// http://www.w3.org/Graphics/JPEG/jfif3.pdf says Y but means Y'.
|
||||
r1 := int(r)
|
||||
g1 := int(g)
|
||||
b1 := int(b)
|
||||
yy := (19595*r1 + 38470*g1 + 7471*b1 + 1<<15) >> 16
|
||||
cb := (-11056*r1 - 21712*g1 + 32768*b1 + 257<<15) >> 16
|
||||
cr := (32768*r1 - 27440*g1 - 5328*b1 + 257<<15) >> 16
|
||||
if yy < 0 {
|
||||
yy = 0
|
||||
} else if yy > 255 {
|
||||
yy = 255
|
||||
}
|
||||
if cb < 0 {
|
||||
cb = 0
|
||||
} else if cb > 255 {
|
||||
cb = 255
|
||||
}
|
||||
if cr < 0 {
|
||||
cr = 0
|
||||
} else if cr > 255 {
|
||||
cr = 255
|
||||
}
|
||||
return uint8(yy), uint8(cb), uint8(cr)
|
||||
}
|
||||
|
||||
// YCbCrToRGB converts a Y'CbCr triple to an RGB triple. All components lie
|
||||
// within the range [0, 255].
|
||||
func YCbCrToRGB(y, cb, cr uint8) (uint8, uint8, uint8) {
|
||||
// The JFIF specification says:
|
||||
// R = Y' + 1.40200*(Cr-128)
|
||||
// G = Y' - 0.34414*(Cb-128) - 0.71414*(Cr-128)
|
||||
// B = Y' + 1.77200*(Cb-128)
|
||||
// http://www.w3.org/Graphics/JPEG/jfif3.pdf says Y but means Y'.
|
||||
yy1 := int(y)<<16 + 1<<15
|
||||
cb1 := int(cb) - 128
|
||||
cr1 := int(cr) - 128
|
||||
r := (yy1 + 91881*cr1) >> 16
|
||||
g := (yy1 - 22554*cb1 - 46802*cr1) >> 16
|
||||
b := (yy1 + 116130*cb1) >> 16
|
||||
if r < 0 {
|
||||
r = 0
|
||||
} else if r > 255 {
|
||||
r = 255
|
||||
}
|
||||
if g < 0 {
|
||||
g = 0
|
||||
} else if g > 255 {
|
||||
g = 255
|
||||
}
|
||||
if b < 0 {
|
||||
b = 0
|
||||
} else if b > 255 {
|
||||
b = 255
|
||||
}
|
||||
return uint8(r), uint8(g), uint8(b)
|
||||
}
|
||||
|
||||
// YCbCr represents a fully opaque 24-bit Y'CbCr color, having 8 bits each for
|
||||
// one luma and two chroma components.
|
||||
//
|
||||
// JPEG, VP8, the MPEG family and other codecs use this color model. Such
|
||||
// codecs often use the terms YUV and Y'CbCr interchangeably, but strictly
|
||||
// speaking, the term YUV applies only to analog video signals, and Y' (luma)
|
||||
// is Y (luminance) after applying gamma correction.
|
||||
//
|
||||
// Conversion between RGB and Y'CbCr is lossy and there are multiple, slightly
|
||||
// different formulae for converting between the two. This package follows
|
||||
// the JFIF specification at http://www.w3.org/Graphics/JPEG/jfif3.pdf.
|
||||
type YCbCr struct {
|
||||
Y, Cb, Cr uint8
|
||||
}
|
||||
|
||||
func (c YCbCr) RGBA() (uint32, uint32, uint32, uint32) {
|
||||
r, g, b := YCbCrToRGB(c.Y, c.Cb, c.Cr)
|
||||
return uint32(r) * 0x101, uint32(g) * 0x101, uint32(b) * 0x101, 0xffff
|
||||
}
|
||||
|
||||
// YCbCrModel is the Model for Y'CbCr colors.
|
||||
var YCbCrModel Model = ModelFunc(func(c Color) Color {
|
||||
if _, ok := c.(YCbCr); ok {
|
||||
return c
|
||||
}
|
||||
r, g, b, _ := c.RGBA()
|
||||
y, u, v := RGBToYCbCr(uint8(r>>8), uint8(g>>8), uint8(b>>8))
|
||||
return YCbCr{y, u, v}
|
||||
})
|
|
@ -2,7 +2,7 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ycbcr
|
||||
package color
|
||||
|
||||
import (
|
||||
"testing"
|
|
@ -7,7 +7,6 @@ package draw
|
|||
import (
|
||||
"image"
|
||||
"image/color"
|
||||
"image/ycbcr"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
@ -51,7 +50,7 @@ func bench(b *testing.B, dcm, scm, mcm color.Model, op Op) {
|
|||
}
|
||||
dst = dst1
|
||||
default:
|
||||
panic("unreachable")
|
||||
b.Fatal("unknown destination color model", dcm)
|
||||
}
|
||||
|
||||
var src image.Image
|
||||
|
@ -97,7 +96,7 @@ func bench(b *testing.B, dcm, scm, mcm color.Model, op Op) {
|
|||
}
|
||||
}
|
||||
src = src1
|
||||
case ycbcr.YCbCrColorModel:
|
||||
case color.YCbCrModel:
|
||||
yy := make([]uint8, srcw*srch)
|
||||
cb := make([]uint8, srcw*srch)
|
||||
cr := make([]uint8, srcw*srch)
|
||||
|
@ -106,17 +105,17 @@ func bench(b *testing.B, dcm, scm, mcm color.Model, op Op) {
|
|||
cb[i] = uint8(5 * i % 0x100)
|
||||
cr[i] = uint8(7 * i % 0x100)
|
||||
}
|
||||
src = &ycbcr.YCbCr{
|
||||
src = &image.YCbCr{
|
||||
Y: yy,
|
||||
Cb: cb,
|
||||
Cr: cr,
|
||||
YStride: srcw,
|
||||
CStride: srcw,
|
||||
SubsampleRatio: ycbcr.SubsampleRatio444,
|
||||
SubsampleRatio: image.YCbCrSubsampleRatio444,
|
||||
Rect: image.Rect(0, 0, srcw, srch),
|
||||
}
|
||||
default:
|
||||
panic("unreachable")
|
||||
b.Fatal("unknown source color model", scm)
|
||||
}
|
||||
|
||||
var mask image.Image
|
||||
|
@ -137,7 +136,7 @@ func bench(b *testing.B, dcm, scm, mcm color.Model, op Op) {
|
|||
}
|
||||
mask = mask1
|
||||
default:
|
||||
panic("unreachable")
|
||||
b.Fatal("unknown mask color model", mcm)
|
||||
}
|
||||
|
||||
b.StartTimer()
|
||||
|
@ -177,7 +176,7 @@ func BenchmarkNRGBASrc(b *testing.B) {
|
|||
}
|
||||
|
||||
func BenchmarkYCbCr(b *testing.B) {
|
||||
bench(b, color.RGBAModel, ycbcr.YCbCrColorModel, nil, Over)
|
||||
bench(b, color.RGBAModel, color.YCbCrModel, nil, Over)
|
||||
}
|
||||
|
||||
func BenchmarkGlyphOver(b *testing.B) {
|
||||
|
|
|
@ -11,7 +11,6 @@ package draw
|
|||
import (
|
||||
"image"
|
||||
"image/color"
|
||||
"image/ycbcr"
|
||||
)
|
||||
|
||||
// m is the maximum color value returned by image.Color.RGBA.
|
||||
|
@ -81,7 +80,7 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
|
|||
case *image.NRGBA:
|
||||
drawNRGBAOver(dst0, r, src0, sp)
|
||||
return
|
||||
case *ycbcr.YCbCr:
|
||||
case *image.YCbCr:
|
||||
drawYCbCr(dst0, r, src0, sp)
|
||||
return
|
||||
}
|
||||
|
@ -104,7 +103,7 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
|
|||
case *image.NRGBA:
|
||||
drawNRGBASrc(dst0, r, src0, sp)
|
||||
return
|
||||
case *ycbcr.YCbCr:
|
||||
case *image.YCbCr:
|
||||
drawYCbCr(dst0, r, src0, sp)
|
||||
return
|
||||
}
|
||||
|
@ -346,8 +345,8 @@ func drawNRGBASrc(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image
|
|||
}
|
||||
}
|
||||
|
||||
func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *ycbcr.YCbCr, sp image.Point) {
|
||||
// A YCbCr image is always fully opaque, and so if the mask is implicitly nil
|
||||
func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Point) {
|
||||
// An image.YCbCr is always fully opaque, and so if the mask is implicitly nil
|
||||
// (i.e. fully opaque) then the op is effectively always Src.
|
||||
var (
|
||||
yy, cb, cr uint8
|
||||
|
@ -357,7 +356,7 @@ func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *ycbcr.YCbCr, sp image.Po
|
|||
y0 := r.Min.Y - dst.Rect.Min.Y
|
||||
y1 := r.Max.Y - dst.Rect.Min.Y
|
||||
switch src.SubsampleRatio {
|
||||
case ycbcr.SubsampleRatio422:
|
||||
case image.YCbCrSubsampleRatio422:
|
||||
for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
|
||||
dpix := dst.Pix[y*dst.Stride:]
|
||||
for x, sx := x0, sp.X; x != x1; x, sx = x+4, sx+1 {
|
||||
|
@ -365,14 +364,14 @@ func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *ycbcr.YCbCr, sp image.Po
|
|||
yy = src.Y[sy*src.YStride+sx]
|
||||
cb = src.Cb[sy*src.CStride+i]
|
||||
cr = src.Cr[sy*src.CStride+i]
|
||||
rr, gg, bb := ycbcr.YCbCrToRGB(yy, cb, cr)
|
||||
rr, gg, bb := color.YCbCrToRGB(yy, cb, cr)
|
||||
dpix[x+0] = rr
|
||||
dpix[x+1] = gg
|
||||
dpix[x+2] = bb
|
||||
dpix[x+3] = 255
|
||||
}
|
||||
}
|
||||
case ycbcr.SubsampleRatio420:
|
||||
case image.YCbCrSubsampleRatio420:
|
||||
for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
|
||||
dpix := dst.Pix[y*dst.Stride:]
|
||||
for x, sx := x0, sp.X; x != x1; x, sx = x+4, sx+1 {
|
||||
|
@ -380,7 +379,7 @@ func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *ycbcr.YCbCr, sp image.Po
|
|||
yy = src.Y[sy*src.YStride+sx]
|
||||
cb = src.Cb[j*src.CStride+i]
|
||||
cr = src.Cr[j*src.CStride+i]
|
||||
rr, gg, bb := ycbcr.YCbCrToRGB(yy, cb, cr)
|
||||
rr, gg, bb := color.YCbCrToRGB(yy, cb, cr)
|
||||
dpix[x+0] = rr
|
||||
dpix[x+1] = gg
|
||||
dpix[x+2] = bb
|
||||
|
@ -395,7 +394,7 @@ func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *ycbcr.YCbCr, sp image.Po
|
|||
yy = src.Y[sy*src.YStride+sx]
|
||||
cb = src.Cb[sy*src.CStride+sx]
|
||||
cr = src.Cr[sy*src.CStride+sx]
|
||||
rr, gg, bb := ycbcr.YCbCrToRGB(yy, cb, cr)
|
||||
rr, gg, bb := color.YCbCrToRGB(yy, cb, cr)
|
||||
dpix[x+0] = rr
|
||||
dpix[x+1] = gg
|
||||
dpix[x+2] = bb
|
||||
|
|
|
@ -7,7 +7,6 @@ package draw
|
|||
import (
|
||||
"image"
|
||||
"image/color"
|
||||
"image/ycbcr"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
@ -56,13 +55,13 @@ func vgradGreenNRGBA(alpha int) image.Image {
|
|||
}
|
||||
|
||||
func vgradCr() image.Image {
|
||||
m := &ycbcr.YCbCr{
|
||||
m := &image.YCbCr{
|
||||
Y: make([]byte, 16*16),
|
||||
Cb: make([]byte, 16*16),
|
||||
Cr: make([]byte, 16*16),
|
||||
YStride: 16,
|
||||
CStride: 16,
|
||||
SubsampleRatio: ycbcr.SubsampleRatio444,
|
||||
SubsampleRatio: image.YCbCrSubsampleRatio444,
|
||||
Rect: image.Rect(0, 0, 16, 16),
|
||||
}
|
||||
for y := 0; y < 16; y++ {
|
||||
|
|
|
@ -11,7 +11,6 @@ import (
|
|||
"bufio"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/ycbcr"
|
||||
"io"
|
||||
)
|
||||
|
||||
|
@ -97,7 +96,7 @@ type decoder struct {
|
|||
r Reader
|
||||
width, height int
|
||||
img1 *image.Gray
|
||||
img3 *ycbcr.YCbCr
|
||||
img3 *image.YCbCr
|
||||
ri int // Restart Interval.
|
||||
nComp int
|
||||
comp [nColorComponent]component
|
||||
|
@ -203,20 +202,20 @@ func (d *decoder) makeImg(h0, v0, mxx, myy int) {
|
|||
d.img1 = m.SubImage(image.Rect(0, 0, d.width, d.height)).(*image.Gray)
|
||||
return
|
||||
}
|
||||
var subsampleRatio ycbcr.SubsampleRatio
|
||||
var subsampleRatio image.YCbCrSubsampleRatio
|
||||
n := h0 * v0
|
||||
switch n {
|
||||
case 1:
|
||||
subsampleRatio = ycbcr.SubsampleRatio444
|
||||
subsampleRatio = image.YCbCrSubsampleRatio444
|
||||
case 2:
|
||||
subsampleRatio = ycbcr.SubsampleRatio422
|
||||
subsampleRatio = image.YCbCrSubsampleRatio422
|
||||
case 4:
|
||||
subsampleRatio = ycbcr.SubsampleRatio420
|
||||
subsampleRatio = image.YCbCrSubsampleRatio420
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
b := make([]byte, mxx*myy*(1*8*8*n+2*8*8))
|
||||
d.img3 = &ycbcr.YCbCr{
|
||||
d.img3 = &image.YCbCr{
|
||||
Y: b[mxx*myy*(0*8*8*n+0*8*8) : mxx*myy*(1*8*8*n+0*8*8)],
|
||||
Cb: b[mxx*myy*(1*8*8*n+0*8*8) : mxx*myy*(1*8*8*n+1*8*8)],
|
||||
Cr: b[mxx*myy*(1*8*8*n+1*8*8) : mxx*myy*(1*8*8*n+2*8*8)],
|
||||
|
@ -466,7 +465,7 @@ func DecodeConfig(r io.Reader) (image.Config, error) {
|
|||
case nGrayComponent:
|
||||
return image.Config{color.GrayModel, d.width, d.height}, nil
|
||||
case nColorComponent:
|
||||
return image.Config{ycbcr.YCbCrColorModel, d.width, d.height}, nil
|
||||
return image.Config{color.YCbCrModel, d.width, d.height}, nil
|
||||
}
|
||||
return image.Config{}, FormatError("missing SOF marker")
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
"bufio"
|
||||
"errors"
|
||||
"image"
|
||||
"image/ycbcr"
|
||||
"image/color"
|
||||
"io"
|
||||
)
|
||||
|
||||
|
@ -379,7 +379,7 @@ func toYCbCr(m image.Image, p image.Point, yBlock, cbBlock, crBlock *block) {
|
|||
for j := 0; j < 8; j++ {
|
||||
for i := 0; i < 8; i++ {
|
||||
r, g, b, _ := m.At(min(p.X+i, xmax), min(p.Y+j, ymax)).RGBA()
|
||||
yy, cb, cr := ycbcr.RGBToYCbCr(uint8(r>>8), uint8(g>>8), uint8(b>>8))
|
||||
yy, cb, cr := color.RGBToYCbCr(uint8(r>>8), uint8(g>>8), uint8(b>>8))
|
||||
yBlock[8*j+i] = int(yy)
|
||||
cbBlock[8*j+i] = int(cb)
|
||||
crBlock[8*j+i] = int(cr)
|
||||
|
@ -404,7 +404,7 @@ func rgbaToYCbCr(m *image.RGBA, p image.Point, yBlock, cbBlock, crBlock *block)
|
|||
sx = xmax
|
||||
}
|
||||
pix := m.Pix[offset+sx*4:]
|
||||
yy, cb, cr := ycbcr.RGBToYCbCr(pix[0], pix[1], pix[2])
|
||||
yy, cb, cr := color.RGBToYCbCr(pix[0], pix[1], pix[2])
|
||||
yBlock[8*j+i] = int(yy)
|
||||
cbBlock[8*j+i] = int(cb)
|
||||
crBlock[8*j+i] = int(cr)
|
||||
|
|
|
@ -105,7 +105,7 @@ func BenchmarkEncodeRGBOpaque(b *testing.B) {
|
|||
}
|
||||
}
|
||||
if !img.Opaque() {
|
||||
panic("expected image to be opaque")
|
||||
b.Fatal("expected image to be opaque")
|
||||
}
|
||||
b.SetBytes(640 * 480 * 4)
|
||||
b.StartTimer()
|
||||
|
|
|
@ -125,7 +125,7 @@ func BenchmarkEncodeRGBOpaque(b *testing.B) {
|
|||
}
|
||||
}
|
||||
if !img.Opaque() {
|
||||
panic("expected image to be opaque")
|
||||
b.Fatal("expected image to be opaque")
|
||||
}
|
||||
b.SetBytes(640 * 480 * 4)
|
||||
b.StartTimer()
|
||||
|
@ -138,7 +138,7 @@ func BenchmarkEncodeRGBA(b *testing.B) {
|
|||
b.StopTimer()
|
||||
img := image.NewRGBA(image.Rect(0, 0, 640, 480))
|
||||
if img.Opaque() {
|
||||
panic("expected image to not be opaque")
|
||||
b.Fatal("expected image to not be opaque")
|
||||
}
|
||||
b.SetBytes(640 * 480 * 4)
|
||||
b.StartTimer()
|
||||
|
|
|
@ -113,7 +113,7 @@ func BenchmarkDecode(b *testing.B) {
|
|||
for i := 0; i < b.N; i++ {
|
||||
_, err := Decode(r)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
b.Fatal("Decode:", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
87
libgo/go/image/ycbcr.go
Normal file
87
libgo/go/image/ycbcr.go
Normal file
|
@ -0,0 +1,87 @@
|
|||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package image
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
)
|
||||
|
||||
// YCbCrSubsampleRatio is the chroma subsample ratio used in a YCbCr image.
|
||||
type YCbCrSubsampleRatio int
|
||||
|
||||
const (
|
||||
YCbCrSubsampleRatio444 YCbCrSubsampleRatio = iota
|
||||
YCbCrSubsampleRatio422
|
||||
YCbCrSubsampleRatio420
|
||||
)
|
||||
|
||||
// YCbCr is an in-memory image of Y'CbCr colors. There is one Y sample per
|
||||
// pixel, but each Cb and Cr sample can span one or more pixels.
|
||||
// YStride is the Y slice index delta between vertically adjacent pixels.
|
||||
// CStride is the Cb and Cr slice index delta between vertically adjacent pixels
|
||||
// that map to separate chroma samples.
|
||||
// It is not an absolute requirement, but YStride and len(Y) are typically
|
||||
// multiples of 8, and:
|
||||
// For 4:4:4, CStride == YStride/1 && len(Cb) == len(Cr) == len(Y)/1.
|
||||
// For 4:2:2, CStride == YStride/2 && len(Cb) == len(Cr) == len(Y)/2.
|
||||
// For 4:2:0, CStride == YStride/2 && len(Cb) == len(Cr) == len(Y)/4.
|
||||
type YCbCr struct {
|
||||
Y []uint8
|
||||
Cb []uint8
|
||||
Cr []uint8
|
||||
YStride int
|
||||
CStride int
|
||||
SubsampleRatio YCbCrSubsampleRatio
|
||||
Rect Rectangle
|
||||
}
|
||||
|
||||
func (p *YCbCr) ColorModel() color.Model {
|
||||
return color.YCbCrModel
|
||||
}
|
||||
|
||||
func (p *YCbCr) Bounds() Rectangle {
|
||||
return p.Rect
|
||||
}
|
||||
|
||||
func (p *YCbCr) At(x, y int) color.Color {
|
||||
if !(Point{x, y}.In(p.Rect)) {
|
||||
return color.YCbCr{}
|
||||
}
|
||||
switch p.SubsampleRatio {
|
||||
case YCbCrSubsampleRatio422:
|
||||
i := x / 2
|
||||
return color.YCbCr{
|
||||
p.Y[y*p.YStride+x],
|
||||
p.Cb[y*p.CStride+i],
|
||||
p.Cr[y*p.CStride+i],
|
||||
}
|
||||
case YCbCrSubsampleRatio420:
|
||||
i, j := x/2, y/2
|
||||
return color.YCbCr{
|
||||
p.Y[y*p.YStride+x],
|
||||
p.Cb[j*p.CStride+i],
|
||||
p.Cr[j*p.CStride+i],
|
||||
}
|
||||
}
|
||||
// Default to 4:4:4 subsampling.
|
||||
return color.YCbCr{
|
||||
p.Y[y*p.YStride+x],
|
||||
p.Cb[y*p.CStride+x],
|
||||
p.Cr[y*p.CStride+x],
|
||||
}
|
||||
}
|
||||
|
||||
// SubImage returns an image representing the portion of the image p visible
|
||||
// through r. The returned value shares pixels with the original image.
|
||||
func (p *YCbCr) SubImage(r Rectangle) Image {
|
||||
q := new(YCbCr)
|
||||
*q = *p
|
||||
q.Rect = q.Rect.Intersect(r)
|
||||
return q
|
||||
}
|
||||
|
||||
func (p *YCbCr) Opaque() bool {
|
||||
return true
|
||||
}
|
|
@ -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 ycbcr provides images from the Y'CbCr color model.
|
||||
//
|
||||
// JPEG, VP8, the MPEG family and other codecs use this color model. Such
|
||||
// codecs often use the terms YUV and Y'CbCr interchangeably, but strictly
|
||||
// speaking, the term YUV applies only to analog video signals.
|
||||
//
|
||||
// Conversion between RGB and Y'CbCr is lossy and there are multiple, slightly
|
||||
// different formulae for converting between the two. This package follows
|
||||
// the JFIF specification at http://www.w3.org/Graphics/JPEG/jfif3.pdf.
|
||||
package ycbcr
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/color"
|
||||
)
|
||||
|
||||
// RGBToYCbCr converts an RGB triple to a YCbCr triple. All components lie
|
||||
// within the range [0, 255].
|
||||
func RGBToYCbCr(r, g, b uint8) (uint8, uint8, uint8) {
|
||||
// The JFIF specification says:
|
||||
// Y' = 0.2990*R + 0.5870*G + 0.1140*B
|
||||
// Cb = -0.1687*R - 0.3313*G + 0.5000*B + 128
|
||||
// Cr = 0.5000*R - 0.4187*G - 0.0813*B + 128
|
||||
// http://www.w3.org/Graphics/JPEG/jfif3.pdf says Y but means Y'.
|
||||
r1 := int(r)
|
||||
g1 := int(g)
|
||||
b1 := int(b)
|
||||
yy := (19595*r1 + 38470*g1 + 7471*b1 + 1<<15) >> 16
|
||||
cb := (-11056*r1 - 21712*g1 + 32768*b1 + 257<<15) >> 16
|
||||
cr := (32768*r1 - 27440*g1 - 5328*b1 + 257<<15) >> 16
|
||||
if yy < 0 {
|
||||
yy = 0
|
||||
} else if yy > 255 {
|
||||
yy = 255
|
||||
}
|
||||
if cb < 0 {
|
||||
cb = 0
|
||||
} else if cb > 255 {
|
||||
cb = 255
|
||||
}
|
||||
if cr < 0 {
|
||||
cr = 0
|
||||
} else if cr > 255 {
|
||||
cr = 255
|
||||
}
|
||||
return uint8(yy), uint8(cb), uint8(cr)
|
||||
}
|
||||
|
||||
// YCbCrToRGB converts a YCbCr triple to an RGB triple. All components lie
|
||||
// within the range [0, 255].
|
||||
func YCbCrToRGB(y, cb, cr uint8) (uint8, uint8, uint8) {
|
||||
// The JFIF specification says:
|
||||
// R = Y' + 1.40200*(Cr-128)
|
||||
// G = Y' - 0.34414*(Cb-128) - 0.71414*(Cr-128)
|
||||
// B = Y' + 1.77200*(Cb-128)
|
||||
// http://www.w3.org/Graphics/JPEG/jfif3.pdf says Y but means Y'.
|
||||
yy1 := int(y)<<16 + 1<<15
|
||||
cb1 := int(cb) - 128
|
||||
cr1 := int(cr) - 128
|
||||
r := (yy1 + 91881*cr1) >> 16
|
||||
g := (yy1 - 22554*cb1 - 46802*cr1) >> 16
|
||||
b := (yy1 + 116130*cb1) >> 16
|
||||
if r < 0 {
|
||||
r = 0
|
||||
} else if r > 255 {
|
||||
r = 255
|
||||
}
|
||||
if g < 0 {
|
||||
g = 0
|
||||
} else if g > 255 {
|
||||
g = 255
|
||||
}
|
||||
if b < 0 {
|
||||
b = 0
|
||||
} else if b > 255 {
|
||||
b = 255
|
||||
}
|
||||
return uint8(r), uint8(g), uint8(b)
|
||||
}
|
||||
|
||||
// YCbCrColor represents a fully opaque 24-bit Y'CbCr color, having 8 bits for
|
||||
// each of one luma and two chroma components.
|
||||
type YCbCrColor struct {
|
||||
Y, Cb, Cr uint8
|
||||
}
|
||||
|
||||
func (c YCbCrColor) RGBA() (uint32, uint32, uint32, uint32) {
|
||||
r, g, b := YCbCrToRGB(c.Y, c.Cb, c.Cr)
|
||||
return uint32(r) * 0x101, uint32(g) * 0x101, uint32(b) * 0x101, 0xffff
|
||||
}
|
||||
|
||||
func toYCbCrColor(c color.Color) color.Color {
|
||||
if _, ok := c.(YCbCrColor); ok {
|
||||
return c
|
||||
}
|
||||
r, g, b, _ := c.RGBA()
|
||||
y, u, v := RGBToYCbCr(uint8(r>>8), uint8(g>>8), uint8(b>>8))
|
||||
return YCbCrColor{y, u, v}
|
||||
}
|
||||
|
||||
// YCbCrColorModel is the color model for YCbCrColor.
|
||||
var YCbCrColorModel color.Model = color.ModelFunc(toYCbCrColor)
|
||||
|
||||
// SubsampleRatio is the chroma subsample ratio used in a YCbCr image.
|
||||
type SubsampleRatio int
|
||||
|
||||
const (
|
||||
SubsampleRatio444 SubsampleRatio = iota
|
||||
SubsampleRatio422
|
||||
SubsampleRatio420
|
||||
)
|
||||
|
||||
// YCbCr is an in-memory image of YCbCr colors. There is one Y sample per pixel,
|
||||
// but each Cb and Cr sample can span one or more pixels.
|
||||
// YStride is the Y slice index delta between vertically adjacent pixels.
|
||||
// CStride is the Cb and Cr slice index delta between vertically adjacent pixels
|
||||
// that map to separate chroma samples.
|
||||
// It is not an absolute requirement, but YStride and len(Y) are typically
|
||||
// multiples of 8, and:
|
||||
// For 4:4:4, CStride == YStride/1 && len(Cb) == len(Cr) == len(Y)/1.
|
||||
// For 4:2:2, CStride == YStride/2 && len(Cb) == len(Cr) == len(Y)/2.
|
||||
// For 4:2:0, CStride == YStride/2 && len(Cb) == len(Cr) == len(Y)/4.
|
||||
type YCbCr struct {
|
||||
Y []uint8
|
||||
Cb []uint8
|
||||
Cr []uint8
|
||||
YStride int
|
||||
CStride int
|
||||
SubsampleRatio SubsampleRatio
|
||||
Rect image.Rectangle
|
||||
}
|
||||
|
||||
func (p *YCbCr) ColorModel() color.Model {
|
||||
return YCbCrColorModel
|
||||
}
|
||||
|
||||
func (p *YCbCr) Bounds() image.Rectangle {
|
||||
return p.Rect
|
||||
}
|
||||
|
||||
func (p *YCbCr) At(x, y int) color.Color {
|
||||
if !(image.Point{x, y}.In(p.Rect)) {
|
||||
return YCbCrColor{}
|
||||
}
|
||||
switch p.SubsampleRatio {
|
||||
case SubsampleRatio422:
|
||||
i := x / 2
|
||||
return YCbCrColor{
|
||||
p.Y[y*p.YStride+x],
|
||||
p.Cb[y*p.CStride+i],
|
||||
p.Cr[y*p.CStride+i],
|
||||
}
|
||||
case SubsampleRatio420:
|
||||
i, j := x/2, y/2
|
||||
return YCbCrColor{
|
||||
p.Y[y*p.YStride+x],
|
||||
p.Cb[j*p.CStride+i],
|
||||
p.Cr[j*p.CStride+i],
|
||||
}
|
||||
}
|
||||
// Default to 4:4:4 subsampling.
|
||||
return YCbCrColor{
|
||||
p.Y[y*p.YStride+x],
|
||||
p.Cb[y*p.CStride+x],
|
||||
p.Cr[y*p.CStride+x],
|
||||
}
|
||||
}
|
||||
|
||||
// SubImage returns an image representing the portion of the image p visible
|
||||
// through r. The returned value shares pixels with the original image.
|
||||
func (p *YCbCr) SubImage(r image.Rectangle) image.Image {
|
||||
q := new(YCbCr)
|
||||
*q = *p
|
||||
q.Rect = q.Rect.Intersect(r)
|
||||
return q
|
||||
}
|
||||
|
||||
func (p *YCbCr) Opaque() bool {
|
||||
return true
|
||||
}
|
|
@ -37,7 +37,11 @@ func TestReadFile(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestWriteFile(t *testing.T) {
|
||||
filename := "_test/rumpelstilzchen"
|
||||
f, err := TempFile("", "ioutil-test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
filename := f.Name()
|
||||
data := "Programming today is a race between software engineers striving to " +
|
||||
"build bigger and better idiot-proof programs, and the Universe trying " +
|
||||
"to produce bigger and better idiots. So far, the Universe is winning."
|
||||
|
@ -56,6 +60,7 @@ func TestWriteFile(t *testing.T) {
|
|||
}
|
||||
|
||||
// cleanup
|
||||
f.Close()
|
||||
os.Remove(filename) // ignore error
|
||||
}
|
||||
|
||||
|
@ -66,26 +71,28 @@ func TestReadDir(t *testing.T) {
|
|||
t.Fatalf("ReadDir %s: error expected, none found", dirname)
|
||||
}
|
||||
|
||||
dirname = "."
|
||||
dirname = ".."
|
||||
list, err := ReadDir(dirname)
|
||||
if err != nil {
|
||||
t.Fatalf("ReadDir %s: %v", dirname, err)
|
||||
}
|
||||
|
||||
foundTest := false
|
||||
foundTestDir := false
|
||||
/* Does not work in gccgo testing environment.
|
||||
foundFile := false
|
||||
foundSubDir := false
|
||||
for _, dir := range list {
|
||||
switch {
|
||||
case !dir.IsDir() && dir.Name() == "ioutil_test.go":
|
||||
foundTest = true
|
||||
case dir.IsDir() && dir.Name() == "_test":
|
||||
foundTestDir = true
|
||||
case !dir.IsDir() && dir.Name() == "io_test.go":
|
||||
foundFile = true
|
||||
case dir.IsDir() && dir.Name() == "ioutil":
|
||||
foundSubDir = true
|
||||
}
|
||||
}
|
||||
if !foundTest {
|
||||
t.Fatalf("ReadDir %s: test file not found", dirname)
|
||||
if !foundFile {
|
||||
t.Fatalf("ReadDir %s: io_test.go file not found", dirname)
|
||||
}
|
||||
if !foundTestDir {
|
||||
t.Fatalf("ReadDir %s: _test directory not found", dirname)
|
||||
if !foundSubDir {
|
||||
t.Fatalf("ReadDir %s: ioutil directory not found", dirname)
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
|
@ -92,11 +92,13 @@ func (w *Writer) Emerg(m string) (err error) {
|
|||
_, err = w.writeString(LOG_EMERG, m)
|
||||
return err
|
||||
}
|
||||
|
||||
// Crit logs a message using the LOG_CRIT priority.
|
||||
func (w *Writer) Crit(m string) (err error) {
|
||||
_, err = w.writeString(LOG_CRIT, m)
|
||||
return err
|
||||
}
|
||||
|
||||
// ERR logs a message using the LOG_ERR priority.
|
||||
func (w *Writer) Err(m string) (err error) {
|
||||
_, err = w.writeString(LOG_ERR, m)
|
||||
|
@ -114,11 +116,13 @@ func (w *Writer) Notice(m string) (err error) {
|
|||
_, err = w.writeString(LOG_NOTICE, m)
|
||||
return err
|
||||
}
|
||||
|
||||
// Info logs a message using the LOG_INFO priority.
|
||||
func (w *Writer) Info(m string) (err error) {
|
||||
_, err = w.writeString(LOG_INFO, m)
|
||||
return err
|
||||
}
|
||||
|
||||
// Debug logs a message using the LOG_DEBUG priority.
|
||||
func (w *Writer) Debug(m string) (err error) {
|
||||
_, err = w.writeString(LOG_DEBUG, m)
|
||||
|
|
|
@ -22,6 +22,7 @@ var vf = []float64{
|
|||
1.8253080916808550e+00,
|
||||
-8.6859247685756013e+00,
|
||||
}
|
||||
|
||||
// The expected results below were computed by the high precision calculators
|
||||
// at http://keisan.casio.com/. More exact input values (array vf[], above)
|
||||
// were obtained by printing them with "%.26f". The answers were calculated
|
||||
|
@ -159,6 +160,7 @@ var cos = []float64{
|
|||
-2.517729313893103197176091e-01,
|
||||
-7.39241351595676573201918e-01,
|
||||
}
|
||||
|
||||
// Results for 100000 * Pi + vf[i]
|
||||
var cosLarge = []float64{
|
||||
2.634752141185559426744e-01,
|
||||
|
@ -514,6 +516,7 @@ var sin = []float64{
|
|||
9.6778633541687993721617774e-01,
|
||||
-6.734405869050344734943028e-01,
|
||||
}
|
||||
|
||||
// Results for 100000 * Pi + vf[i]
|
||||
var sinLarge = []float64{
|
||||
-9.646661658548936063912e-01,
|
||||
|
@ -563,6 +566,7 @@ var tan = []float64{
|
|||
-3.843885560201130679995041e+00,
|
||||
9.10988793377685105753416e-01,
|
||||
}
|
||||
|
||||
// Results for 100000 * Pi + vf[i]
|
||||
var tanLarge = []float64{
|
||||
-3.66131656475596512705e+00,
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"encoding/gob"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"testing"
|
||||
"testing/quick"
|
||||
)
|
||||
|
@ -1405,3 +1406,9 @@ func TestIntGobEncoding(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIssue2607(t *testing.T) {
|
||||
// This code sequence used to hang.
|
||||
n := NewInt(10)
|
||||
n.Rand(rand.New(rand.NewSource(9)), n)
|
||||
}
|
||||
|
|
|
@ -1196,12 +1196,16 @@ func (x nat) powersOfTwoDecompose() (q nat, k int) {
|
|||
// random creates a random integer in [0..limit), using the space in z if
|
||||
// possible. n is the bit length of limit.
|
||||
func (z nat) random(rand *rand.Rand, limit nat, n int) nat {
|
||||
if alias(z, limit) {
|
||||
z = nil // z is an alias for limit - cannot reuse
|
||||
}
|
||||
z = z.make(len(limit))
|
||||
|
||||
bitLengthOfMSW := uint(n % _W)
|
||||
if bitLengthOfMSW == 0 {
|
||||
bitLengthOfMSW = _W
|
||||
}
|
||||
mask := Word((1 << bitLengthOfMSW) - 1)
|
||||
z = z.make(len(limit))
|
||||
|
||||
for {
|
||||
for i := range z {
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
package big
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"testing"
|
||||
|
@ -402,7 +401,7 @@ func ScanHelper(b *testing.B, base int, x, y Word) {
|
|||
var s string
|
||||
s = z.string(lowercaseDigits[0:base])
|
||||
if t := toString(z, lowercaseDigits[0:base]); t != s {
|
||||
panic(fmt.Sprintf("scanning: got %s; want %s", s, t))
|
||||
b.Fatalf("scanning: got %s; want %s", s, t)
|
||||
}
|
||||
b.StartTimer()
|
||||
|
||||
|
|
|
@ -98,6 +98,7 @@ var _sin = [...]float64{
|
|||
8.33333333332211858878E-3, // 0x3f8111111110f7d0
|
||||
-1.66666666666666307295E-1, // 0xbfc5555555555548
|
||||
}
|
||||
|
||||
// cos coefficients
|
||||
var _cos = [...]float64{
|
||||
-1.13585365213876817300E-11, // 0xbda8fa49a0861a9b
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue