diff options
Diffstat (limited to 'src/pkg/fmt/scan.go')
-rw-r--r-- | src/pkg/fmt/scan.go | 97 |
1 files changed, 57 insertions, 40 deletions
diff --git a/src/pkg/fmt/scan.go b/src/pkg/fmt/scan.go index c0f2bacb6..b1b3975e2 100644 --- a/src/pkg/fmt/scan.go +++ b/src/pkg/fmt/scan.go @@ -35,10 +35,15 @@ type ScanState interface { ReadRune() (rune int, size int, err os.Error) // UnreadRune causes the next call to ReadRune to return the same rune. UnreadRune() os.Error - // Token returns the next space-delimited token from the input. If - // a width has been specified, the returned token will be no longer - // than the width. - Token() (token string, err os.Error) + // Token skips space in the input if skipSpace is true, then returns the + // run of Unicode code points c satisfying f(c). If f is nil, + // !unicode.IsSpace(c) is used; that is, the token will hold non-space + // characters. Newlines are treated as space unless the scan operation + // is Scanln, Fscanln or Sscanln, in which case a newline is treated as + // EOF. The returned slice points to shared data that may be overwritten + // by the next call to Token, a call to a Scan function using the ScanState + // as input, or when the calling Scan method returns. + Token(skipSpace bool, f func(int) bool) (token []byte, err os.Error) // Width returns the value of the width option and whether it has been set. // The unit is Unicode code points. Width() (wid int, ok bool) @@ -134,7 +139,7 @@ type scanError struct { err os.Error } -const EOF = -1 +const eof = -1 // ss is the internal implementation of ScanState. type ss struct { @@ -202,7 +207,7 @@ func (s *ss) getRune() (rune int) { rune, _, err := s.ReadRune() if err != nil { if err == os.EOF { - return EOF + return eof } s.error(err) } @@ -214,7 +219,7 @@ func (s *ss) getRune() (rune int) { // syntax error. func (s *ss) mustReadRune() (rune int) { rune = s.getRune() - if rune == EOF { + if rune == eof { s.error(io.ErrUnexpectedEOF) } return @@ -238,7 +243,7 @@ func (s *ss) errorString(err string) { panic(scanError{os.ErrorString(err)}) } -func (s *ss) Token() (tok string, err os.Error) { +func (s *ss) Token(skipSpace bool, f func(int) bool) (tok []byte, err os.Error) { defer func() { if e := recover(); e != nil { if se, ok := e.(scanError); ok { @@ -248,10 +253,19 @@ func (s *ss) Token() (tok string, err os.Error) { } } }() - tok = s.token() + if f == nil { + f = notSpace + } + s.buf.Reset() + tok = s.token(skipSpace, f) return } +// notSpace is the default scanning function used in Token. +func notSpace(r int) bool { + return !unicode.IsSpace(r) +} + // readRune is a structure to enable reading UTF-8 encoded code points // from an io.Reader. It is used if the Reader given to the scanner does // not already implement io.RuneReader. @@ -364,7 +378,7 @@ func (s *ss) free(old ssave) { func (s *ss) skipSpace(stopAtNewline bool) { for { rune := s.getRune() - if rune == EOF { + if rune == eof { return } if rune == '\n' { @@ -384,24 +398,27 @@ func (s *ss) skipSpace(stopAtNewline bool) { } } + // token returns the next space-delimited string from the input. It // skips white space. For Scanln, it stops at newlines. For Scan, // newlines are treated as spaces. -func (s *ss) token() string { - s.skipSpace(false) +func (s *ss) token(skipSpace bool, f func(int) bool) []byte { + if skipSpace { + s.skipSpace(false) + } // read until white space or newline for { rune := s.getRune() - if rune == EOF { + if rune == eof { break } - if unicode.IsSpace(rune) { + if !f(rune) { s.UnreadRune() break } s.buf.WriteRune(rune) } - return s.buf.String() + return s.buf.Bytes() } // typeError indicates that the type of the operand did not match the format @@ -416,7 +433,7 @@ var boolError = os.ErrorString("syntax error scanning boolean") // If accept is true, it puts the character into the input token. func (s *ss) consume(ok string, accept bool) bool { rune := s.getRune() - if rune == EOF { + if rune == eof { return false } if strings.IndexRune(ok, rune) >= 0 { @@ -425,7 +442,7 @@ func (s *ss) consume(ok string, accept bool) bool { } return true } - if rune != EOF && accept { + if rune != eof && accept { s.UnreadRune() } return false @@ -434,7 +451,7 @@ func (s *ss) consume(ok string, accept bool) bool { // peek reports whether the next character is in the ok string, without consuming it. func (s *ss) peek(ok string) bool { rune := s.getRune() - if rune != EOF { + if rune != eof { s.UnreadRune() } return strings.IndexRune(ok, rune) >= 0 @@ -729,7 +746,7 @@ func (s *ss) convertString(verb int) (str string) { case 'x': str = s.hexString() default: - str = s.token() // %s and %v just return the next word + str = string(s.token(true, notSpace)) // %s and %v just return the next word } // Empty strings other than with %q are not OK. if len(str) == 0 && verb != 'q' && s.maxWid > 0 { @@ -797,7 +814,7 @@ func (s *ss) hexDigit(digit int) int { // 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 { + if rune1 == eof { return } if unicode.IsSpace(rune1) { @@ -892,36 +909,36 @@ func (s *ss) scanOne(verb int, field interface{}) { *v = []byte(s.convertString(verb)) default: val := reflect.NewValue(v) - ptr, ok := val.(*reflect.PtrValue) - if !ok { + ptr := val + if ptr.Kind() != reflect.Ptr { s.errorString("Scan: type not a pointer: " + val.Type().String()) return } - switch v := ptr.Elem().(type) { - case *reflect.BoolValue: - v.Set(s.scanBool(verb)) - case *reflect.IntValue: - v.Set(s.scanInt(verb, v.Type().Bits())) - case *reflect.UintValue: - v.Set(s.scanUint(verb, v.Type().Bits())) - case *reflect.StringValue: - v.Set(s.convertString(verb)) - case *reflect.SliceValue: + switch v := ptr.Elem(); v.Kind() { + case reflect.Bool: + v.SetBool(s.scanBool(verb)) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + v.SetInt(s.scanInt(verb, v.Type().Bits())) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + v.SetUint(s.scanUint(verb, v.Type().Bits())) + case reflect.String: + v.SetString(s.convertString(verb)) + case reflect.Slice: // For now, can only handle (renamed) []byte. - typ := v.Type().(*reflect.SliceType) + typ := v.Type() if typ.Elem().Kind() != reflect.Uint8 { goto CantHandle } str := s.convertString(verb) v.Set(reflect.MakeSlice(typ, len(str), len(str))) for i := 0; i < len(str); i++ { - v.Elem(i).(*reflect.UintValue).Set(uint64(str[i])) + v.Index(i).SetUint(uint64(str[i])) } - case *reflect.FloatValue: + case reflect.Float32, reflect.Float64: s.skipSpace(false) - v.Set(s.convertFloat(s.floatToken(), v.Type().Bits())) - case *reflect.ComplexValue: - v.Set(s.scanComplex(verb, v.Type().Bits())) + v.SetFloat(s.convertFloat(s.floatToken(), v.Type().Bits())) + case reflect.Complex64, reflect.Complex128: + v.SetComplex(s.scanComplex(verb, v.Type().Bits())) default: CantHandle: s.errorString("Scan: can't handle type: " + val.Type().String()) @@ -953,7 +970,7 @@ func (s *ss) doScan(a []interface{}) (numProcessed int, err os.Error) { if !s.nlIsSpace { for { rune := s.getRune() - if rune == '\n' || rune == EOF { + if rune == '\n' || rune == eof { break } if !unicode.IsSpace(rune) { @@ -993,7 +1010,7 @@ func (s *ss) advance(format string) (i int) { // There was space in the format, so there should be space (EOF) // in the input. inputc := s.getRune() - if inputc == EOF { + if inputc == eof { return } if !unicode.IsSpace(inputc) { |