mirror of
https://github.com/golang/go
synced 2024-11-22 06:54:39 -07:00
fmt.Scan: renamings, strings, errors
- implement scanning for all renamed types (compiler bug stops complex from being renamable, so it can't be tested but the code is there) - %q %x for strings - error handling now done with panic/recover R=rsc CC=golang-dev https://golang.org/cl/1458041
This commit is contained in:
parent
cd016d7558
commit
b8a89972ee
@ -68,8 +68,7 @@ func Scanln(a ...interface{}) (n int, err os.Error) {
|
|||||||
// is less than the number of arguments, err will report why.
|
// is less than the number of arguments, err will report why.
|
||||||
func Fscan(r io.Reader, a ...interface{}) (n int, err os.Error) {
|
func Fscan(r io.Reader, a ...interface{}) (n int, err os.Error) {
|
||||||
s := newScanState(r, true)
|
s := newScanState(r, true)
|
||||||
n = s.doScan(a)
|
n, err = s.doScan(a)
|
||||||
err = s.err
|
|
||||||
s.free()
|
s.free()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -82,8 +81,7 @@ func Fscan(r io.Reader, a ...interface{}) (n int, err os.Error) {
|
|||||||
// number of arguments, err will report why.
|
// number of arguments, err will report why.
|
||||||
func Fscanln(r io.Reader, a ...interface{}) (n int, err os.Error) {
|
func Fscanln(r io.Reader, a ...interface{}) (n int, err os.Error) {
|
||||||
s := newScanState(r, false)
|
s := newScanState(r, false)
|
||||||
n = s.doScan(a)
|
n, err = s.doScan(a)
|
||||||
err = s.err
|
|
||||||
s.free()
|
s.free()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -96,19 +94,23 @@ func XXXScanf(format string, a ...interface{}) (n int, err os.Error) {
|
|||||||
// XXXFscanf is incomplete, do not use.
|
// XXXFscanf is incomplete, do not use.
|
||||||
func XXXFscanf(r io.Reader, format string, a ...interface{}) (n int, err os.Error) {
|
func XXXFscanf(r io.Reader, format string, a ...interface{}) (n int, err os.Error) {
|
||||||
s := newScanState(r, false)
|
s := newScanState(r, false)
|
||||||
n = s.doScanf(format, a)
|
n, err = s.doScanf(format, a)
|
||||||
err = s.err
|
|
||||||
s.free()
|
s.free()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// scanError represents an error generated by the scanning software.
|
||||||
|
// It's used as a unique signature to identify such errors when recovering.
|
||||||
|
type scanError struct {
|
||||||
|
err os.Error
|
||||||
|
}
|
||||||
|
|
||||||
// ss is the internal implementation of ScanState.
|
// ss is the internal implementation of ScanState.
|
||||||
type ss struct {
|
type ss struct {
|
||||||
rr readRuner // where to read input
|
rr readRuner // where to read input
|
||||||
buf bytes.Buffer // token accumulator
|
buf bytes.Buffer // token accumulator
|
||||||
nlIsSpace bool // whether newline counts as white space
|
nlIsSpace bool // whether newline counts as white space
|
||||||
peekRune int // one-rune lookahead
|
peekRune int // one-rune lookahead
|
||||||
err os.Error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ss) GetRune() (rune int, err os.Error) {
|
func (s *ss) GetRune() (rune int, err os.Error) {
|
||||||
@ -121,13 +123,69 @@ func (s *ss) GetRune() (rune int, err os.Error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const EOF = -1
|
||||||
|
|
||||||
|
// The public method returns an error; this private one panics.
|
||||||
|
// If getRune reaches EOF, the return value is EOF (-1).
|
||||||
|
func (s *ss) getRune() (rune int) {
|
||||||
|
if s.peekRune >= 0 {
|
||||||
|
rune = s.peekRune
|
||||||
|
s.peekRune = -1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rune, _, err := s.rr.ReadRune()
|
||||||
|
if err != nil {
|
||||||
|
if err == os.EOF {
|
||||||
|
return EOF
|
||||||
|
}
|
||||||
|
s.error(err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// mustGetRune turns os.EOF into a panic(io.ErrUnexpectedEOF).
|
||||||
|
// It is called in cases such as string scanning where an EOF is a
|
||||||
|
// syntax error.
|
||||||
|
func (s *ss) mustGetRune() (rune int) {
|
||||||
|
if s.peekRune >= 0 {
|
||||||
|
rune = s.peekRune
|
||||||
|
s.peekRune = -1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rune, _, err := s.rr.ReadRune()
|
||||||
|
if err != nil {
|
||||||
|
if err == os.EOF {
|
||||||
|
err = io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
s.error(err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
func (s *ss) UngetRune(rune int) {
|
func (s *ss) UngetRune(rune int) {
|
||||||
s.peekRune = rune
|
s.peekRune = rune
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *ss) error(err os.Error) {
|
||||||
|
panic(scanError{err})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ss) errorString(err string) {
|
||||||
|
panic(scanError{os.ErrorString(err)})
|
||||||
|
}
|
||||||
|
|
||||||
func (s *ss) Token() (tok string, err os.Error) {
|
func (s *ss) Token() (tok string, err os.Error) {
|
||||||
|
defer func() {
|
||||||
|
if e := recover(); e != nil {
|
||||||
|
if se, ok := e.(scanError); ok {
|
||||||
|
err = se.err
|
||||||
|
} else {
|
||||||
|
panic(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
tok = s.token()
|
tok = s.token()
|
||||||
err = s.err
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,7 +242,6 @@ func newScanState(r io.Reader, nlIsSpace bool) *ss {
|
|||||||
}
|
}
|
||||||
s.nlIsSpace = nlIsSpace
|
s.nlIsSpace = nlIsSpace
|
||||||
s.peekRune = -1
|
s.peekRune = -1
|
||||||
s.err = nil
|
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,40 +256,39 @@ func (s *ss) free() {
|
|||||||
_ = ssFree <- s
|
_ = ssFree <- s
|
||||||
}
|
}
|
||||||
|
|
||||||
// token returns the next space-delimited string from the input.
|
// skipSpace skips spaces and maybe newlines
|
||||||
// For Scanln, it stops at newlines. For Scan, newlines are treated as
|
func (s *ss) skipSpace() {
|
||||||
// spaces.
|
|
||||||
func (s *ss) token() string {
|
|
||||||
s.buf.Reset()
|
s.buf.Reset()
|
||||||
// skip white space and maybe newline
|
|
||||||
for {
|
for {
|
||||||
rune, err := s.GetRune()
|
rune := s.getRune()
|
||||||
if err != nil {
|
if rune == EOF {
|
||||||
s.err = err
|
return
|
||||||
return ""
|
|
||||||
}
|
}
|
||||||
if rune == '\n' {
|
if rune == '\n' {
|
||||||
if s.nlIsSpace {
|
if s.nlIsSpace {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
s.err = os.ErrorString("unexpected newline")
|
s.errorString("unexpected newline")
|
||||||
return ""
|
return
|
||||||
}
|
}
|
||||||
if !unicode.IsSpace(rune) {
|
if !unicode.IsSpace(rune) {
|
||||||
s.buf.WriteRune(rune)
|
s.UngetRune(rune)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// token returns the next space-delimited string from the input.
|
||||||
|
// For Scanln, it stops at newlines. For Scan, newlines are treated as
|
||||||
|
// spaces.
|
||||||
|
func (s *ss) token() string {
|
||||||
|
s.skipSpace()
|
||||||
// read until white space or newline
|
// read until white space or newline
|
||||||
for {
|
for {
|
||||||
rune, err := s.GetRune()
|
rune := s.getRune()
|
||||||
if err != nil {
|
if rune == EOF {
|
||||||
if err == os.EOF {
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
s.err = err
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
if unicode.IsSpace(rune) {
|
if unicode.IsSpace(rune) {
|
||||||
s.UngetRune(rune)
|
s.UngetRune(rune)
|
||||||
break
|
break
|
||||||
@ -242,9 +298,9 @@ func (s *ss) token() string {
|
|||||||
return s.buf.String()
|
return s.buf.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// typeError sets the error string to an indication that the type of the operand did not match the format
|
// typeError indicates that the type of the operand did not match the format
|
||||||
func (s *ss) typeError(field interface{}, expected string) {
|
func (s *ss) typeError(field interface{}, expected string) {
|
||||||
s.err = os.ErrorString("expected field of type pointer to " + expected + "; found " + reflect.Typeof(field).String())
|
s.errorString("expected field of type pointer to " + expected + "; found " + reflect.Typeof(field).String())
|
||||||
}
|
}
|
||||||
|
|
||||||
var intBits = uint(reflect.Typeof(int(0)).Size() * 8)
|
var intBits = uint(reflect.Typeof(int(0)).Size() * 8)
|
||||||
@ -253,28 +309,29 @@ var complexError = os.ErrorString("syntax error scanning complex number")
|
|||||||
|
|
||||||
// okVerb verifies that the verb is present in the list, setting s.err appropriately if not.
|
// okVerb verifies that the verb is present in the list, setting s.err appropriately if not.
|
||||||
func (s *ss) okVerb(verb int, okVerbs, typ string) bool {
|
func (s *ss) okVerb(verb int, okVerbs, typ string) bool {
|
||||||
if s.err != nil { // don't overwrite error
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
for _, v := range okVerbs {
|
for _, v := range okVerbs {
|
||||||
if v == verb {
|
if v == verb {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s.err = os.ErrorString("bad verb %" + string(verb) + " for " + typ)
|
s.errorString("bad verb %" + string(verb) + " for " + typ)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// scanBool converts the token to a boolean value.
|
// scanBool returns the value of the boolean represented by the next token.
|
||||||
func (s *ss) scanBool(verb int, tok string) bool {
|
func (s *ss) scanBool(verb int) bool {
|
||||||
if !s.okVerb(verb, "tv", "boolean") {
|
if !s.okVerb(verb, "tv", "boolean") {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
var b bool
|
tok := s.token()
|
||||||
b, s.err = strconv.Atob(tok)
|
b, err := strconv.Atob(tok)
|
||||||
|
if err != nil {
|
||||||
|
s.error(err)
|
||||||
|
}
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getBase returns the numeric base represented by the verb.
|
||||||
func (s *ss) getBase(verb int) int {
|
func (s *ss) getBase(verb int) int {
|
||||||
s.okVerb(verb, "bdoxXv", "integer") // sets s.err
|
s.okVerb(verb, "bdoxXv", "integer") // sets s.err
|
||||||
base := 10
|
base := 10
|
||||||
@ -289,32 +346,34 @@ func (s *ss) getBase(verb int) int {
|
|||||||
return base
|
return base
|
||||||
}
|
}
|
||||||
|
|
||||||
// convertInt returns the value of the integer
|
// scanInt returns the value of the integer represented by the next
|
||||||
// stored in the token, checking for overflow. Any error is stored in s.err.
|
// token, checking for overflow. Any error is stored in s.err.
|
||||||
func (s *ss) convertInt(verb int, tok string, bitSize uint) (i int64) {
|
func (s *ss) scanInt(verb int, bitSize uint) int64 {
|
||||||
base := s.getBase(verb)
|
base := s.getBase(verb)
|
||||||
if s.err != nil {
|
tok := s.token()
|
||||||
return 0
|
i, err := strconv.Btoi64(tok, base)
|
||||||
|
if err != nil {
|
||||||
|
s.error(err)
|
||||||
}
|
}
|
||||||
i, s.err = strconv.Btoi64(tok, base)
|
|
||||||
x := (i << (64 - bitSize)) >> (64 - bitSize)
|
x := (i << (64 - bitSize)) >> (64 - bitSize)
|
||||||
if x != i {
|
if x != i {
|
||||||
s.err = os.ErrorString("integer overflow on token " + tok)
|
s.errorString("integer overflow on token " + tok)
|
||||||
}
|
}
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
// convertUint returns the value of the unsigned integer
|
// scanUint returns the value of the unsigned integer represented
|
||||||
// stored in the token, checking for overflow. Any error is stored in s.err.
|
// by the next token, checking for overflow. Any error is stored in s.err.
|
||||||
func (s *ss) convertUint(verb int, tok string, bitSize uint) (i uint64) {
|
func (s *ss) scanUint(verb int, bitSize uint) uint64 {
|
||||||
base := s.getBase(verb)
|
base := s.getBase(verb)
|
||||||
if s.err != nil {
|
tok := s.token()
|
||||||
return 0
|
i, err := strconv.Btoui64(tok, base)
|
||||||
|
if err != nil {
|
||||||
|
s.error(err)
|
||||||
}
|
}
|
||||||
i, s.err = strconv.Btoui64(tok, base)
|
|
||||||
x := (i << (64 - bitSize)) >> (64 - bitSize)
|
x := (i << (64 - bitSize)) >> (64 - bitSize)
|
||||||
if x != i {
|
if x != i {
|
||||||
s.err = os.ErrorString("unsigned integer overflow on token " + tok)
|
s.errorString("unsigned integer overflow on token " + tok)
|
||||||
}
|
}
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
@ -327,13 +386,11 @@ func (s *ss) complexParts(str string) (real, imag string) {
|
|||||||
real, str = floatPart(str)
|
real, str = floatPart(str)
|
||||||
// Must now have a sign.
|
// Must now have a sign.
|
||||||
if len(str) == 0 || (str[0] != '+' && str[0] != '-') {
|
if len(str) == 0 || (str[0] != '+' && str[0] != '-') {
|
||||||
s.err = complexError
|
s.error(complexError)
|
||||||
return "", ""
|
|
||||||
}
|
}
|
||||||
imag, str = floatPart(str)
|
imag, str = floatPart(str)
|
||||||
if str != "i" {
|
if str != "i" {
|
||||||
s.err = complexError
|
s.error(complexError)
|
||||||
return "", ""
|
|
||||||
}
|
}
|
||||||
return real, imag
|
return real, imag
|
||||||
}
|
}
|
||||||
@ -343,11 +400,11 @@ func (s *ss) complexParts(str string) (real, imag string) {
|
|||||||
func floatPart(str string) (first, last string) {
|
func floatPart(str string) (first, last string) {
|
||||||
i := 0
|
i := 0
|
||||||
// leading sign?
|
// leading sign?
|
||||||
if len(str) > 0 && (str[0] == '+' || str[0] == '-') {
|
if len(str) > i && (str[0] == '+' || str[0] == '-') {
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
// digits?
|
// digits?
|
||||||
for len(str) > 0 && '0' <= str[i] && str[i] <= '9' {
|
for len(str) > i && '0' <= str[i] && str[i] <= '9' {
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
// period?
|
// period?
|
||||||
@ -355,197 +412,323 @@ func floatPart(str string) (first, last string) {
|
|||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
// fraction?
|
// fraction?
|
||||||
for len(str) > 0 && '0' <= str[i] && str[i] <= '9' {
|
for len(str) > i && '0' <= str[i] && str[i] <= '9' {
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
// exponent?
|
// exponent?
|
||||||
if len(str) > 0 && (str[i] == 'e' || str[i] == 'E') {
|
if len(str) > i && (str[i] == 'e' || str[i] == 'E') {
|
||||||
i++
|
i++
|
||||||
// leading sign?
|
// leading sign?
|
||||||
if str[0] == '+' || str[0] == '-' {
|
if str[i] == '+' || str[i] == '-' {
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
// digits?
|
// digits?
|
||||||
for len(str) > 0 && '0' <= str[i] && str[i] <= '9' {
|
for len(str) > i && '0' <= str[i] && str[i] <= '9' {
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return str[0:i], str[i:]
|
return str[0:i], str[i:]
|
||||||
}
|
}
|
||||||
|
|
||||||
// scanFloat converts the string to a float value.
|
// convertFloat converts the string to a float value.
|
||||||
func (s *ss) scanFloat(str string) float64 {
|
func (s *ss) convertFloat(str string) float64 {
|
||||||
var f float
|
f, err := strconv.Atof(str)
|
||||||
f, s.err = strconv.Atof(str)
|
if err != nil {
|
||||||
|
s.error(err)
|
||||||
|
}
|
||||||
return float64(f)
|
return float64(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// scanFloat32 converts the string to a float32 value.
|
// convertFloat32 converts the string to a float32 value.
|
||||||
func (s *ss) scanFloat32(str string) float64 {
|
func (s *ss) convertFloat32(str string) float64 {
|
||||||
var f float32
|
f, err := strconv.Atof32(str)
|
||||||
f, s.err = strconv.Atof32(str)
|
if err != nil {
|
||||||
|
s.error(err)
|
||||||
|
}
|
||||||
return float64(f)
|
return float64(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// scanFloat64 converts the string to a float64 value.
|
// convertFloat64 converts the string to a float64 value.
|
||||||
func (s *ss) scanFloat64(str string) float64 {
|
func (s *ss) convertFloat64(str string) float64 {
|
||||||
var f float64
|
f, err := strconv.Atof64(str)
|
||||||
f, s.err = strconv.Atof64(str)
|
if err != nil {
|
||||||
|
s.error(err)
|
||||||
|
}
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
|
|
||||||
// scanComplex converts the token to a complex128 value.
|
// convertComplex converts the next token to a complex128 value.
|
||||||
// The atof argument is a type-specific reader for the underlying type.
|
// The atof argument is a type-specific reader for the underlying type.
|
||||||
// If we're reading complex64, atof will parse float32s and convert them
|
// If we're reading complex64, atof will parse float32s and convert them
|
||||||
// to float64's to avoid reproducing this code for each complex type.
|
// to float64's to avoid reproducing this code for each complex type.
|
||||||
func (s *ss) scanComplex(tok string, atof func(*ss, string) float64) complex128 {
|
func (s *ss) scanComplex(verb int, atof func(*ss, string) float64) complex128 {
|
||||||
|
if !s.okVerb(verb, floatVerbs, "complex") {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
tok := s.token()
|
||||||
sreal, simag := s.complexParts(tok)
|
sreal, simag := s.complexParts(tok)
|
||||||
if s.err != nil {
|
real := atof(s, sreal)
|
||||||
return 0
|
imag := atof(s, simag)
|
||||||
}
|
|
||||||
var real, imag float64
|
|
||||||
real = atof(s, sreal)
|
|
||||||
if s.err != nil {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
imag = atof(s, simag)
|
|
||||||
if s.err != nil {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return cmplx(real, imag)
|
return cmplx(real, imag)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// convertString returns the string represented by the next input characters.
|
||||||
|
// The format of the input is determined by the verb.
|
||||||
|
func (s *ss) convertString(verb int) string {
|
||||||
|
if !s.okVerb(verb, "svqx", "string") {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
s.skipSpace()
|
||||||
|
switch verb {
|
||||||
|
case 'q':
|
||||||
|
return s.quotedString()
|
||||||
|
case 'x':
|
||||||
|
return s.hexString()
|
||||||
|
}
|
||||||
|
return s.token() // %s and %v just return the next word
|
||||||
|
}
|
||||||
|
|
||||||
|
// quotedString returns the double- or back-quoted string.
|
||||||
|
func (s *ss) quotedString() string {
|
||||||
|
quote := s.mustGetRune()
|
||||||
|
switch quote {
|
||||||
|
case '`':
|
||||||
|
// Back-quoted: Anything goes until EOF or back quote.
|
||||||
|
for {
|
||||||
|
rune := s.mustGetRune()
|
||||||
|
if rune == quote {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
s.buf.WriteRune(rune)
|
||||||
|
}
|
||||||
|
return s.buf.String()
|
||||||
|
case '"':
|
||||||
|
// Double-quoted: Include the quotes and let strconv.Unquote do the backslash escapes.
|
||||||
|
s.buf.WriteRune(quote)
|
||||||
|
for {
|
||||||
|
rune := s.mustGetRune()
|
||||||
|
s.buf.WriteRune(rune)
|
||||||
|
if rune == '\\' {
|
||||||
|
// In a legal backslash escape, no matter how long, only the character
|
||||||
|
// immediately after the escape can itself be a backslash or quote.
|
||||||
|
// Thus we only need to protect the first character after the backslash.
|
||||||
|
rune := s.mustGetRune()
|
||||||
|
s.buf.WriteRune(rune)
|
||||||
|
} else if rune == '"' {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result, err := strconv.Unquote(s.buf.String())
|
||||||
|
if err != nil {
|
||||||
|
s.error(err)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
default:
|
||||||
|
s.errorString("expected quoted string")
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// hexDigit returns the value of the hexadecimal digit
|
||||||
|
func (s *ss) hexDigit(digit int) int {
|
||||||
|
switch digit {
|
||||||
|
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||||
|
return digit - '0'
|
||||||
|
case 'a', 'b', 'c', 'd', 'e', 'f':
|
||||||
|
return 10 + digit - 'a'
|
||||||
|
case 'A', 'B', 'C', 'D', 'E', 'F':
|
||||||
|
return 10 + digit - 'A'
|
||||||
|
}
|
||||||
|
s.errorString("Scan: illegal hex digit")
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// hexByte returns the next hex-encoded (two-character) byte from the input.
|
||||||
|
// There must be either two hexadecimal digits or a space character in the input.
|
||||||
|
func (s *ss) hexByte() (b byte, ok bool) {
|
||||||
|
rune1 := s.getRune()
|
||||||
|
if rune1 == EOF {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if unicode.IsSpace(rune1) {
|
||||||
|
s.UngetRune(rune1)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rune2 := s.mustGetRune()
|
||||||
|
return byte(s.hexDigit(rune1)<<4 | s.hexDigit(rune2)), true
|
||||||
|
}
|
||||||
|
|
||||||
|
// hexString returns the space-delimited hexpair-encoded string.
|
||||||
|
func (s *ss) hexString() string {
|
||||||
|
for {
|
||||||
|
b, ok := s.hexByte()
|
||||||
|
if !ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
s.buf.WriteByte(b)
|
||||||
|
}
|
||||||
|
if s.buf.Len() == 0 {
|
||||||
|
s.errorString("Scan: no hex data for %x string")
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return s.buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
const floatVerbs = "eEfFgGv"
|
const floatVerbs = "eEfFgGv"
|
||||||
|
|
||||||
// scanOne scans a single value, deriving the scanner from the type of the argument.
|
// scanOne scans a single value, deriving the scanner from the type of the argument.
|
||||||
func (s *ss) scanOne(verb int, field interface{}) {
|
func (s *ss) scanOne(verb int, field interface{}) {
|
||||||
|
var err os.Error
|
||||||
// If the parameter has its own Scan method, use that.
|
// If the parameter has its own Scan method, use that.
|
||||||
if v, ok := field.(Scanner); ok {
|
if v, ok := field.(Scanner); ok {
|
||||||
s.err = v.Scan(s)
|
err = v.Scan(s)
|
||||||
return
|
if err != nil {
|
||||||
|
s.error(err)
|
||||||
}
|
}
|
||||||
tok := s.token()
|
|
||||||
if s.err != nil {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch v := field.(type) {
|
switch v := field.(type) {
|
||||||
case *bool:
|
case *bool:
|
||||||
*v = s.scanBool(verb, tok)
|
*v = s.scanBool(verb)
|
||||||
case *complex:
|
case *complex:
|
||||||
*v = complex(s.scanComplex(tok, (*ss).scanFloat))
|
*v = complex(s.scanComplex(verb, (*ss).convertFloat))
|
||||||
case *complex64:
|
case *complex64:
|
||||||
*v = complex64(s.scanComplex(tok, (*ss).scanFloat32))
|
*v = complex64(s.scanComplex(verb, (*ss).convertFloat32))
|
||||||
case *complex128:
|
case *complex128:
|
||||||
*v = s.scanComplex(tok, (*ss).scanFloat64)
|
*v = s.scanComplex(verb, (*ss).convertFloat64)
|
||||||
case *int:
|
case *int:
|
||||||
*v = int(s.convertInt(verb, tok, intBits))
|
*v = int(s.scanInt(verb, intBits))
|
||||||
case *int8:
|
case *int8:
|
||||||
*v = int8(s.convertInt(verb, tok, 8))
|
*v = int8(s.scanInt(verb, 8))
|
||||||
case *int16:
|
case *int16:
|
||||||
*v = int16(s.convertInt(verb, tok, 16))
|
*v = int16(s.scanInt(verb, 16))
|
||||||
case *int32:
|
case *int32:
|
||||||
*v = int32(s.convertInt(verb, tok, 32))
|
*v = int32(s.scanInt(verb, 32))
|
||||||
case *int64:
|
case *int64:
|
||||||
*v = s.convertInt(verb, tok, intBits)
|
*v = s.scanInt(verb, intBits)
|
||||||
case *uint:
|
case *uint:
|
||||||
*v = uint(s.convertUint(verb, tok, intBits))
|
*v = uint(s.scanUint(verb, intBits))
|
||||||
case *uint8:
|
case *uint8:
|
||||||
*v = uint8(s.convertUint(verb, tok, 8))
|
*v = uint8(s.scanUint(verb, 8))
|
||||||
case *uint16:
|
case *uint16:
|
||||||
*v = uint16(s.convertUint(verb, tok, 16))
|
*v = uint16(s.scanUint(verb, 16))
|
||||||
case *uint32:
|
case *uint32:
|
||||||
*v = uint32(s.convertUint(verb, tok, 32))
|
*v = uint32(s.scanUint(verb, 32))
|
||||||
case *uint64:
|
case *uint64:
|
||||||
*v = s.convertUint(verb, tok, 64)
|
*v = s.scanUint(verb, 64)
|
||||||
case *uintptr:
|
case *uintptr:
|
||||||
*v = uintptr(s.convertUint(verb, tok, uintptrBits))
|
*v = uintptr(s.scanUint(verb, uintptrBits))
|
||||||
|
// Floats are tricky because you want to scan in the precision of the result, not
|
||||||
|
// scan in high precision and convert, in order to preserve the correct error condition.
|
||||||
case *float:
|
case *float:
|
||||||
if s.okVerb(verb, floatVerbs, "float") {
|
if s.okVerb(verb, floatVerbs, "float") {
|
||||||
*v, s.err = strconv.Atof(tok)
|
*v = float(s.convertFloat(s.token()))
|
||||||
}
|
}
|
||||||
case *float32:
|
case *float32:
|
||||||
if s.okVerb(verb, floatVerbs, "float32") {
|
if s.okVerb(verb, floatVerbs, "float32") {
|
||||||
*v, s.err = strconv.Atof32(tok)
|
*v = float32(s.convertFloat32(s.token()))
|
||||||
}
|
}
|
||||||
case *float64:
|
case *float64:
|
||||||
if s.okVerb(verb, floatVerbs, "float64") {
|
if s.okVerb(verb, floatVerbs, "float64") {
|
||||||
*v, s.err = strconv.Atof64(tok)
|
*v = s.convertFloat64(s.token())
|
||||||
}
|
}
|
||||||
case *string:
|
case *string:
|
||||||
*v = tok
|
*v = s.convertString(verb)
|
||||||
default:
|
default:
|
||||||
val := reflect.NewValue(v)
|
val := reflect.NewValue(v)
|
||||||
ptr, ok := val.(*reflect.PtrValue)
|
ptr, ok := val.(*reflect.PtrValue)
|
||||||
if !ok {
|
if !ok {
|
||||||
s.err = os.ErrorString("Scan: type not a pointer: " + val.Type().String())
|
s.errorString("Scan: type not a pointer: " + val.Type().String())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch v := ptr.Elem().(type) {
|
switch v := ptr.Elem().(type) {
|
||||||
|
case *reflect.BoolValue:
|
||||||
|
v.Set(s.scanBool(verb))
|
||||||
case *reflect.IntValue:
|
case *reflect.IntValue:
|
||||||
v.Set(int(s.convertInt(verb, tok, intBits)))
|
v.Set(int(s.scanInt(verb, intBits)))
|
||||||
case *reflect.Int8Value:
|
case *reflect.Int8Value:
|
||||||
v.Set(int8(s.convertInt(verb, tok, 8)))
|
v.Set(int8(s.scanInt(verb, 8)))
|
||||||
case *reflect.Int16Value:
|
case *reflect.Int16Value:
|
||||||
v.Set(int16(s.convertInt(verb, tok, 16)))
|
v.Set(int16(s.scanInt(verb, 16)))
|
||||||
case *reflect.Int32Value:
|
case *reflect.Int32Value:
|
||||||
v.Set(int32(s.convertInt(verb, tok, 32)))
|
v.Set(int32(s.scanInt(verb, 32)))
|
||||||
case *reflect.Int64Value:
|
case *reflect.Int64Value:
|
||||||
v.Set(s.convertInt(verb, tok, 64))
|
v.Set(s.scanInt(verb, 64))
|
||||||
case *reflect.UintValue:
|
case *reflect.UintValue:
|
||||||
v.Set(uint(s.convertUint(verb, tok, intBits)))
|
v.Set(uint(s.scanUint(verb, intBits)))
|
||||||
case *reflect.Uint8Value:
|
case *reflect.Uint8Value:
|
||||||
v.Set(uint8(s.convertUint(verb, tok, 8)))
|
v.Set(uint8(s.scanUint(verb, 8)))
|
||||||
case *reflect.Uint16Value:
|
case *reflect.Uint16Value:
|
||||||
v.Set(uint16(s.convertUint(verb, tok, 16)))
|
v.Set(uint16(s.scanUint(verb, 16)))
|
||||||
case *reflect.Uint32Value:
|
case *reflect.Uint32Value:
|
||||||
v.Set(uint32(s.convertUint(verb, tok, 32)))
|
v.Set(uint32(s.scanUint(verb, 32)))
|
||||||
case *reflect.Uint64Value:
|
case *reflect.Uint64Value:
|
||||||
v.Set(s.convertUint(verb, tok, 64))
|
v.Set(s.scanUint(verb, 64))
|
||||||
case *reflect.UintptrValue:
|
case *reflect.UintptrValue:
|
||||||
v.Set(uintptr(s.convertUint(verb, tok, uintptrBits)))
|
v.Set(uintptr(s.scanUint(verb, uintptrBits)))
|
||||||
|
case *reflect.StringValue:
|
||||||
|
v.Set(s.convertString(verb))
|
||||||
|
case *reflect.FloatValue:
|
||||||
|
v.Set(float(s.convertFloat(s.token())))
|
||||||
|
case *reflect.Float32Value:
|
||||||
|
v.Set(float32(s.convertFloat(s.token())))
|
||||||
|
case *reflect.Float64Value:
|
||||||
|
v.Set(s.convertFloat(s.token()))
|
||||||
|
case *reflect.ComplexValue:
|
||||||
|
v.Set(complex(s.scanComplex(verb, (*ss).convertFloat)))
|
||||||
|
case *reflect.Complex64Value:
|
||||||
|
v.Set(complex64(s.scanComplex(verb, (*ss).convertFloat32)))
|
||||||
|
case *reflect.Complex128Value:
|
||||||
|
v.Set(s.scanComplex(verb, (*ss).convertFloat64))
|
||||||
default:
|
default:
|
||||||
s.err = os.ErrorString("Scan: can't handle type: " + val.Type().String())
|
s.errorString("Scan: can't handle type: " + val.Type().String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// errorHandler turns local panics into error returns. EOFs are benign.
|
||||||
|
func errorHandler(errp *os.Error) {
|
||||||
|
if e := recover(); e != nil {
|
||||||
|
if se, ok := e.(scanError); ok { // catch local error
|
||||||
|
if se.err != os.EOF {
|
||||||
|
*errp = se.err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// doScan does the real work for scanning without a format string.
|
// doScan does the real work for scanning without a format string.
|
||||||
// At the moment, it handles only pointers to basic types.
|
// At the moment, it handles only pointers to basic types.
|
||||||
func (s *ss) doScan(a []interface{}) int {
|
func (s *ss) doScan(a []interface{}) (numProcessed int, err os.Error) {
|
||||||
for fieldnum, field := range a {
|
defer errorHandler(&err)
|
||||||
|
for _, field := range a {
|
||||||
s.scanOne('v', field)
|
s.scanOne('v', field)
|
||||||
if s.err != nil {
|
numProcessed++
|
||||||
return fieldnum
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Check for newline if required.
|
// Check for newline if required.
|
||||||
if !s.nlIsSpace {
|
if !s.nlIsSpace {
|
||||||
for {
|
for {
|
||||||
rune, err := s.GetRune()
|
rune := s.getRune()
|
||||||
if err != nil {
|
if rune == '\n' || rune == EOF {
|
||||||
if err == os.EOF {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
s.err = err
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if rune == '\n' {
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if !unicode.IsSpace(rune) {
|
if !unicode.IsSpace(rune) {
|
||||||
s.err = os.ErrorString("Scan: expected newline")
|
s.errorString("Scan: expected newline")
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return len(a)
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// doScanf does the real work when scanning with a format string.
|
// doScanf does the real work when scanning with a format string.
|
||||||
// At the moment, it handles only pointers to basic types.
|
// At the moment, it handles only pointers to basic types.
|
||||||
func (s *ss) doScanf(format string, a []interface{}) int {
|
func (s *ss) doScanf(format string, a []interface{}) (numProcessed int, err os.Error) {
|
||||||
|
defer errorHandler(&err)
|
||||||
end := len(format) - 1
|
end := len(format) - 1
|
||||||
fieldnum := 0 // we process one item per non-trivial format
|
// We process one item per non-trivial format
|
||||||
for i := 0; i <= end; {
|
for i := 0; i <= end; {
|
||||||
c, w := utf8.DecodeRuneInString(format[i:])
|
c, w := utf8.DecodeRuneInString(format[i:])
|
||||||
if c != '%' || i == end {
|
if c != '%' || i == end {
|
||||||
@ -563,17 +746,14 @@ func (s *ss) doScanf(format string, a []interface{}) int {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if fieldnum >= len(a) { // out of operands
|
if numProcessed >= len(a) { // out of operands
|
||||||
s.err = os.ErrorString("too few operands for format %" + format[i-w:])
|
s.errorString("too few operands for format %" + format[i-w:])
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
field := a[fieldnum]
|
field := a[numProcessed]
|
||||||
|
|
||||||
s.scanOne(c, field)
|
s.scanOne(c, field)
|
||||||
if s.err != nil {
|
numProcessed++
|
||||||
break
|
|
||||||
}
|
}
|
||||||
fieldnum++
|
return
|
||||||
}
|
|
||||||
return fieldnum
|
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ type ScanfTest struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type (
|
type (
|
||||||
|
renamedBool bool
|
||||||
renamedInt int
|
renamedInt int
|
||||||
renamedInt8 int8
|
renamedInt8 int8
|
||||||
renamedInt16 int16
|
renamedInt16 int16
|
||||||
@ -38,6 +39,13 @@ type (
|
|||||||
renamedUint32 uint32
|
renamedUint32 uint32
|
||||||
renamedUint64 uint64
|
renamedUint64 uint64
|
||||||
renamedUintptr uintptr
|
renamedUintptr uintptr
|
||||||
|
renamedString string
|
||||||
|
renamedFloat float
|
||||||
|
renamedFloat32 float32
|
||||||
|
renamedFloat64 float64
|
||||||
|
renamedComplex complex
|
||||||
|
renamedComplex64 complex64
|
||||||
|
renamedComplex128 complex128
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -59,6 +67,7 @@ var (
|
|||||||
complexVal complex
|
complexVal complex
|
||||||
complex64Val complex64
|
complex64Val complex64
|
||||||
complex128Val complex128
|
complex128Val complex128
|
||||||
|
renamedBoolVal renamedBool
|
||||||
renamedIntVal renamedInt
|
renamedIntVal renamedInt
|
||||||
renamedInt8Val renamedInt8
|
renamedInt8Val renamedInt8
|
||||||
renamedInt16Val renamedInt16
|
renamedInt16Val renamedInt16
|
||||||
@ -70,6 +79,13 @@ var (
|
|||||||
renamedUint32Val renamedUint32
|
renamedUint32Val renamedUint32
|
||||||
renamedUint64Val renamedUint64
|
renamedUint64Val renamedUint64
|
||||||
renamedUintptrVal renamedUintptr
|
renamedUintptrVal renamedUintptr
|
||||||
|
renamedStringVal renamedString
|
||||||
|
renamedFloatVal renamedFloat
|
||||||
|
renamedFloat32Val renamedFloat32
|
||||||
|
renamedFloat64Val renamedFloat64
|
||||||
|
renamedComplexVal renamedComplex
|
||||||
|
renamedComplex64Val renamedComplex64
|
||||||
|
renamedComplex128Val renamedComplex128
|
||||||
)
|
)
|
||||||
|
|
||||||
// Xs accepts any non-empty run of x's.
|
// Xs accepts any non-empty run of x's.
|
||||||
@ -92,7 +108,9 @@ func (x *Xs) Scan(state ScanState) os.Error {
|
|||||||
var xVal Xs
|
var xVal Xs
|
||||||
|
|
||||||
var scanTests = []ScanTest{
|
var scanTests = []ScanTest{
|
||||||
ScanTest{"T\n", &boolVal, true},
|
// Numbers
|
||||||
|
ScanTest{"T\n", &boolVal, true}, // boolean test vals toggle to be sure they are written
|
||||||
|
ScanTest{"F\n", &boolVal, false}, // restored to zero value
|
||||||
ScanTest{"21\n", &intVal, 21},
|
ScanTest{"21\n", &intVal, 21},
|
||||||
ScanTest{"22\n", &int8Val, int8(22)},
|
ScanTest{"22\n", &int8Val, int8(22)},
|
||||||
ScanTest{"23\n", &int16Val, int16(23)},
|
ScanTest{"23\n", &int16Val, int16(23)},
|
||||||
@ -125,8 +143,11 @@ var scanTests = []ScanTest{
|
|||||||
ScanTest{"(3.4e1-2i)\n", &complexVal, 3.4e1 - 2i},
|
ScanTest{"(3.4e1-2i)\n", &complexVal, 3.4e1 - 2i},
|
||||||
ScanTest{"-3.45e1-3i\n", &complex64Val, complex64(-3.45e1 - 3i)},
|
ScanTest{"-3.45e1-3i\n", &complex64Val, complex64(-3.45e1 - 3i)},
|
||||||
ScanTest{"-.45e1-1e2i\n", &complex128Val, complex128(-.45e1 - 100i)},
|
ScanTest{"-.45e1-1e2i\n", &complex128Val, complex128(-.45e1 - 100i)},
|
||||||
|
ScanTest{"hello\n", &stringVal, "hello"},
|
||||||
|
|
||||||
// Renamed types
|
// Renamed types
|
||||||
|
ScanTest{"true\n", &renamedBoolVal, renamedBool(true)},
|
||||||
|
ScanTest{"F\n", &renamedBoolVal, renamedBool(false)},
|
||||||
ScanTest{"101\n", &renamedIntVal, renamedInt(101)},
|
ScanTest{"101\n", &renamedIntVal, renamedInt(101)},
|
||||||
ScanTest{"102\n", &renamedIntVal, renamedInt(102)},
|
ScanTest{"102\n", &renamedIntVal, renamedInt(102)},
|
||||||
ScanTest{"103\n", &renamedUintVal, renamedUint(103)},
|
ScanTest{"103\n", &renamedUintVal, renamedUint(103)},
|
||||||
@ -140,14 +161,15 @@ var scanTests = []ScanTest{
|
|||||||
ScanTest{"111\n", &renamedUint32Val, renamedUint32(111)},
|
ScanTest{"111\n", &renamedUint32Val, renamedUint32(111)},
|
||||||
ScanTest{"112\n", &renamedUint64Val, renamedUint64(112)},
|
ScanTest{"112\n", &renamedUint64Val, renamedUint64(112)},
|
||||||
ScanTest{"113\n", &renamedUintptrVal, renamedUintptr(113)},
|
ScanTest{"113\n", &renamedUintptrVal, renamedUintptr(113)},
|
||||||
|
ScanTest{"114\n", &renamedStringVal, renamedString("114")},
|
||||||
|
|
||||||
// Custom scanner.
|
// Custom scanner.
|
||||||
ScanTest{" xxx ", &xVal, Xs("xxx")},
|
ScanTest{" xxx ", &xVal, Xs("xxx")},
|
||||||
}
|
}
|
||||||
|
|
||||||
var scanfTests = []ScanfTest{
|
var scanfTests = []ScanfTest{
|
||||||
ScanfTest{"%v", "FALSE\n", &boolVal, false},
|
ScanfTest{"%v", "TRUE\n", &boolVal, true},
|
||||||
ScanfTest{"%t", "true\n", &boolVal, true},
|
ScanfTest{"%t", "false\n", &boolVal, false},
|
||||||
ScanfTest{"%v", "-71\n", &intVal, -71},
|
ScanfTest{"%v", "-71\n", &intVal, -71},
|
||||||
ScanfTest{"%d", "72\n", &intVal, 72},
|
ScanfTest{"%d", "72\n", &intVal, 72},
|
||||||
ScanfTest{"%d", "73\n", &int8Val, int8(73)},
|
ScanfTest{"%d", "73\n", &int8Val, int8(73)},
|
||||||
@ -168,7 +190,15 @@ var scanfTests = []ScanfTest{
|
|||||||
ScanfTest{"%x", "a75\n", &uintVal, uint(0xa75)},
|
ScanfTest{"%x", "a75\n", &uintVal, uint(0xa75)},
|
||||||
ScanfTest{"%x", "A75\n", &uintVal, uint(0xa75)},
|
ScanfTest{"%x", "A75\n", &uintVal, uint(0xa75)},
|
||||||
|
|
||||||
|
// Strings
|
||||||
|
ScanfTest{"%s", "using-%s\n", &stringVal, "using-%s"},
|
||||||
|
ScanfTest{"%x", "7573696e672d2578\n", &stringVal, "using-%x"},
|
||||||
|
ScanfTest{"%q", `"quoted\twith\\do\u0075bl\x65s"` + "\n", &stringVal, "quoted\twith\\doubles"},
|
||||||
|
ScanfTest{"%q", "`quoted with backs`\n", &stringVal, "quoted with backs"},
|
||||||
|
|
||||||
// Renamed types
|
// Renamed types
|
||||||
|
ScanfTest{"%v\n", "true\n", &renamedBoolVal, renamedBool(true)},
|
||||||
|
ScanfTest{"%t\n", "F\n", &renamedBoolVal, renamedBool(false)},
|
||||||
ScanfTest{"%v", "101\n", &renamedIntVal, renamedInt(101)},
|
ScanfTest{"%v", "101\n", &renamedIntVal, renamedInt(101)},
|
||||||
ScanfTest{"%o", "0146\n", &renamedIntVal, renamedInt(102)},
|
ScanfTest{"%o", "0146\n", &renamedIntVal, renamedInt(102)},
|
||||||
ScanfTest{"%v", "103\n", &renamedUintVal, renamedUint(103)},
|
ScanfTest{"%v", "103\n", &renamedUintVal, renamedUint(103)},
|
||||||
@ -182,6 +212,13 @@ var scanfTests = []ScanfTest{
|
|||||||
ScanfTest{"%d", "111\n", &renamedUint32Val, renamedUint32(111)},
|
ScanfTest{"%d", "111\n", &renamedUint32Val, renamedUint32(111)},
|
||||||
ScanfTest{"%d", "112\n", &renamedUint64Val, renamedUint64(112)},
|
ScanfTest{"%d", "112\n", &renamedUint64Val, renamedUint64(112)},
|
||||||
ScanfTest{"%d", "113\n", &renamedUintptrVal, renamedUintptr(113)},
|
ScanfTest{"%d", "113\n", &renamedUintptrVal, renamedUintptr(113)},
|
||||||
|
ScanfTest{"%s", "114\n", &renamedStringVal, renamedString("114")},
|
||||||
|
ScanfTest{"%g", "115.1\n", &renamedFloatVal, renamedFloat(115.1)},
|
||||||
|
ScanfTest{"%g", "116e1\n", &renamedFloat32Val, renamedFloat32(116e1)},
|
||||||
|
ScanfTest{"%g", "-11.7e+1", &renamedFloat64Val, renamedFloat64(-11.7e+1)},
|
||||||
|
ScanfTest{"%g", "11+5.1i\n", &renamedComplexVal, renamedComplex(11 + 5.1i)},
|
||||||
|
ScanfTest{"%g", "11+6e1i\n", &renamedComplex64Val, renamedComplex64(11 + 6e1i)},
|
||||||
|
ScanfTest{"%g", "-11.+7e+1i", &renamedComplex128Val, renamedComplex128(-11. + 7e+1i)},
|
||||||
|
|
||||||
ScanfTest{"%x", "FFFFFFFF\n", &uint32Val, uint32(0xFFFFFFFF)},
|
ScanfTest{"%x", "FFFFFFFF\n", &uint32Val, uint32(0xFFFFFFFF)},
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user