]> Cypherpunks repositories - gostls13.git/commitdiff
fmt.Scan:
authorRob Pike <r@golang.org>
Mon, 31 May 2010 17:56:58 +0000 (10:56 -0700)
committerRob Pike <r@golang.org>
Mon, 31 May 2010 17:56:58 +0000 (10:56 -0700)
- reimplement integer scanning to handle renamed basic integer types
- start implementation of Fscanf and Scanf; not yet ready for general use.

This intermediate CL is a useful checkpoint. A similar change needs to be
done for float and complex, but it seemed worth getting the approach
reviewed before making those changes.

R=rsc
CC=golang-dev
https://golang.org/cl/1418041

src/pkg/fmt/scan.go
src/pkg/fmt/scan_test.go

index fee9fd8437d97bc113ff553362516c93d375097d..ec7ba9bf591b43d15085eda2b14ae61561cf27d8 100644 (file)
@@ -41,6 +41,67 @@ type Scanner interface {
        Scan(ScanState) os.Error
 }
 
+// Scan parses text read from standard input, storing successive
+// space-separated values into successive arguments.  Newlines count as
+// space.  Each argument must be a pointer to a basic type or an
+// implementation of the Scanner interface.  It returns the number of items
+// successfully parsed.  If that is less than the number of arguments, err
+// will report why.
+func Scan(a ...interface{}) (n int, err os.Error) {
+       return Fscan(os.Stdin, a)
+}
+
+// Fscanln parses text read from standard input, storing successive
+// space-separated values into successive arguments.  Scanning stops at a
+// newline and after the final item there must be a newline or EOF.  Each
+// argument must be a pointer to a basic type or an implementation of the
+// Scanner interface.  It returns the number of items successfully parsed.
+// If that is less than the number of arguments, err will report why.
+func Scanln(a ...interface{}) (n int, err os.Error) {
+       return Fscanln(os.Stdin, a)
+}
+
+// Fscan parses text read from r, storing successive space-separated values
+// into successive arguments.  Newlines count as space.  Each argument must
+// be a pointer to a basic type or an implementation of the Scanner
+// interface.  It returns the number of items successfully parsed.  If that
+// is less than the number of arguments, err will report why.
+func Fscan(r io.Reader, a ...interface{}) (n int, err os.Error) {
+       s := newScanState(r, true)
+       n = s.doScan(a)
+       err = s.err
+       s.free()
+       return
+}
+
+// Fscanln parses text read from r, storing successive space-separated values
+// into successive arguments.  Scanning stops at a newline and after the
+// final item there must be a newline or EOF.  Each argument must be a
+// pointer to a basic type or an implementation of the Scanner interface.  It
+// returns the number of items successfully parsed.  If that is less than the
+// number of arguments, err will report why.
+func Fscanln(r io.Reader, a ...interface{}) (n int, err os.Error) {
+       s := newScanState(r, false)
+       n = s.doScan(a)
+       err = s.err
+       s.free()
+       return
+}
+
+// XXXScanf is incomplete, do not use.
+func XXXScanf(format string, a ...interface{}) (n int, err os.Error) {
+       return XXXFscanf(os.Stdin, format, a)
+}
+
+// XXXFscanf is incomplete, do not use.
+func XXXFscanf(r io.Reader, format string, a ...interface{}) (n int, err os.Error) {
+       s := newScanState(r, false)
+       n = s.doScanf(format, a)
+       err = s.err
+       s.free()
+       return
+}
+
 // ss is the internal implementation of ScanState.
 type ss struct {
        rr        readRuner    // where to read input
@@ -181,51 +242,9 @@ func (s *ss) token() string {
        return s.buf.String()
 }
 
-// Scan parses text read from standard input, storing successive
-// space-separated values into successive arguments.  Newlines count as
-// space.  Each argument must be a pointer to a basic type or an
-// implementation of the Scanner interface.  It returns the number of items
-// successfully parsed.  If that is less than the number of arguments, err
-// will report why.
-func Scan(a ...interface{}) (n int, err os.Error) {
-       return Fscan(os.Stdin, a)
-}
-
-// Fscanln parses text read from standard input, storing successive
-// space-separated values into successive arguments.  Scanning stops at a
-// newline and after the final item there must be a newline or EOF.  Each
-// argument must be a pointer to a basic type or an implementation of the
-// Scanner interface.  It returns the number of items successfully parsed.
-// If that is less than the number of arguments, err will report why.
-func Scanln(a ...interface{}) (n int, err os.Error) {
-       return Fscanln(os.Stdin, a)
-}
-
-// Fscan parses text read from r, storing successive space-separated values
-// into successive arguments.  Newlines count as space.  Each argument must
-// be a pointer to a basic type or an implementation of the Scanner
-// interface.  It returns the number of items successfully parsed.  If that
-// is less than the number of arguments, err will report why.
-func Fscan(r io.Reader, a ...interface{}) (n int, err os.Error) {
-       s := newScanState(r, true)
-       n = s.doScan(a)
-       err = s.err
-       s.free()
-       return
-}
-
-// Fscanln parses text read from r, storing successive space-separated values
-// into successive arguments.  Scanning stops at a newline and after the
-// final item there must be a newline or EOF.  Each argument must be a
-// pointer to a basic type or an implementation of the Scanner interface.  It
-// returns the number of items successfully parsed.  If that is less than the
-// number of arguments, err will report why.
-func Fscanln(r io.Reader, a ...interface{}) (n int, err os.Error) {
-       s := newScanState(r, false)
-       n = s.doScan(a)
-       err = s.err
-       s.free()
-       return
+// typeError sets the error string to an indication that the type of the operand did not match the format
+func (s *ss) typeError(field interface{}, expected string) {
+       s.err = os.ErrorString("expected field of type pointer to " + expected + "; found " + reflect.Typeof(field).String())
 }
 
 var intBits = uint(reflect.Typeof(int(0)).Size() * 8)
@@ -242,6 +261,101 @@ func (s *ss) scanBool(tok string) bool {
        return b
 }
 
+// convertInt returns the value of the integer
+// stored in the token, checking for overflow.  Any error is stored in s.err.
+func (s *ss) convertInt(tok string, bitSize uint, base int) (i int64) {
+       i, s.err = strconv.Btoi64(tok, base)
+       x := (i << (64 - bitSize)) >> (64 - bitSize)
+       if x != i {
+               s.err = os.ErrorString("integer overflow on token " + tok)
+       }
+       return i
+}
+
+// convertUint returns the value of the unsigned integer
+// stored in the token, checking for overflow.  Any error is stored in s.err.
+func (s *ss) convertUint(tok string, bitSize uint, base int) (i uint64) {
+       i, s.err = strconv.Btoui64(tok, base)
+       x := (i << (64 - bitSize)) >> (64 - bitSize)
+       if x != i {
+               s.err = os.ErrorString("unsigned integer overflow on token " + tok)
+       }
+       return i
+}
+
+// scanInteger converts the token to an integer in the appropriate base
+// and stores the result according to the type of the field.
+func (s *ss) scanInteger(tok string, field interface{}, base int) {
+       switch v := field.(type) {
+       case *int:
+               *v = int(s.convertInt(tok, intBits, base))
+               return
+       case *int8:
+               *v = int8(s.convertInt(tok, 8, base))
+               return
+       case *int16:
+               *v = int16(s.convertInt(tok, 16, base))
+               return
+       case *int32:
+               *v = int32(s.convertInt(tok, 32, base))
+               return
+       case *int64:
+               *v = s.convertInt(tok, 64, base)
+               return
+       case *uint:
+               *v = uint(s.convertUint(tok, intBits, base))
+               return
+       case *uint8:
+               *v = uint8(s.convertUint(tok, 8, base))
+               return
+       case *uint16:
+               *v = uint16(s.convertUint(tok, 16, base))
+               return
+       case *uint32:
+               *v = uint32(s.convertUint(tok, 32, base))
+               return
+       case *uint64:
+               *v = uint64(s.convertUint(tok, 64, base))
+               return
+       case *uintptr:
+               *v = uintptr(s.convertUint(tok, uintptrBits, base))
+               return
+       }
+       // Not a basic type; probably a renamed type. We need to use reflection.
+       v := reflect.NewValue(field)
+       ptr, ok := v.(*reflect.PtrValue)
+       if !ok {
+               s.typeError(field, "integer")
+               return
+       }
+       switch v := ptr.Elem().(type) {
+       case *reflect.IntValue:
+               v.Set(int(s.convertInt(tok, intBits, base)))
+       case *reflect.Int8Value:
+               v.Set(int8(s.convertInt(tok, 8, base)))
+       case *reflect.Int16Value:
+               v.Set(int16(s.convertInt(tok, 16, base)))
+       case *reflect.Int32Value:
+               v.Set(int32(s.convertInt(tok, 32, base)))
+       case *reflect.Int64Value:
+               v.Set(s.convertInt(tok, 64, base))
+       case *reflect.UintValue:
+               v.Set(uint(s.convertUint(tok, intBits, base)))
+       case *reflect.Uint8Value:
+               v.Set(uint8(s.convertUint(tok, 8, base)))
+       case *reflect.Uint16Value:
+               v.Set(uint16(s.convertUint(tok, 16, base)))
+       case *reflect.Uint32Value:
+               v.Set(uint32(s.convertUint(tok, 32, base)))
+       case *reflect.Uint64Value:
+               v.Set(s.convertUint(tok, 64, base))
+       case *reflect.UintptrValue:
+               v.Set(uintptr(s.convertUint(tok, uintptrBits, base)))
+       default:
+               s.err = os.ErrorString("internal error: unknown int type")
+       }
+}
+
 // complexParts returns the strings representing the real and imaginary parts of the string.
 func (s *ss) complexParts(str string) (real, imag string) {
        if len(str) > 2 && str[0] == '(' && str[len(str)-1] == ')' {
@@ -341,110 +455,97 @@ func (s *ss) scanComplex(tok string, atof func(*ss, string) float64) complex128
        return cmplx(real, imag)
 }
 
-// scanInt converts the token to an int64, but checks that it fits into the
-// specified number of bits.
-func (s *ss) scanInt(tok string, bitSize uint) int64 {
+// scanOne scans a single value, deriving the scanner from the type of the argument.
+func (s *ss) scanOne(field interface{}) {
+       tok := s.token()
        if s.err != nil {
-               return 0
-       }
-       var i int64
-       i, s.err = strconv.Atoi64(tok)
-       x := (i << (64 - bitSize)) >> (64 - bitSize)
-       if i != x {
-               s.err = os.ErrorString("integer overflow on token " + tok)
-       }
-       return i
-}
-
-// scanUint converts the token to a uint64, but checks that it fits into the
-// specified number of bits.
-func (s *ss) scanUint(tok string, bitSize uint) uint64 {
-       if s.err != nil {
-               return 0
+               return
        }
-       var i uint64
-       i, s.err = strconv.Atoui64(tok)
-       x := (i << (64 - bitSize)) >> (64 - bitSize)
-       if i != x {
-               s.err = os.ErrorString("unsigned integer overflow on token " + tok)
+       switch v := field.(type) {
+       case *bool:
+               *v = s.scanBool(tok)
+       case *complex:
+               *v = complex(s.scanComplex(tok, (*ss).scanFloat))
+       case *complex64:
+               *v = complex64(s.scanComplex(tok, (*ss).scanFloat32))
+       case *complex128:
+               *v = s.scanComplex(tok, (*ss).scanFloat64)
+       case *int:
+               *v = int(s.convertInt(tok, intBits, 10))
+       case *int8:
+               *v = int8(s.convertInt(tok, 8, 10))
+       case *int16:
+               *v = int16(s.convertInt(tok, 16, 10))
+       case *int32:
+               *v = int32(s.convertInt(tok, 32, 10))
+       case *int64:
+               *v = s.convertInt(tok, intBits, 10)
+       case *uint:
+               *v = uint(s.convertUint(tok, intBits, 10))
+       case *uint8:
+               *v = uint8(s.convertUint(tok, 8, 10))
+       case *uint16:
+               *v = uint16(s.convertUint(tok, 16, 10))
+       case *uint32:
+               *v = uint32(s.convertUint(tok, 32, 10))
+       case *uint64:
+               *v = s.convertUint(tok, 64, 10)
+       case *uintptr:
+               *v = uintptr(s.convertUint(tok, uintptrBits, 10))
+       case *float:
+               if s.err == nil {
+                       *v, s.err = strconv.Atof(tok)
+               } else {
+                       *v = 0
+               }
+       case *float32:
+               if s.err == nil {
+                       *v, s.err = strconv.Atof32(tok)
+               } else {
+                       *v = 0
+               }
+       case *float64:
+               if s.err == nil {
+                       *v, s.err = strconv.Atof64(tok)
+               } else {
+                       *v = 0
+               }
+       case *string:
+               *v = tok
+       default:
+               t := reflect.Typeof(v)
+               str := t.String()
+               ptr, ok := t.(*reflect.PtrType)
+               if !ok {
+                       s.err = os.ErrorString("Scan: type not a pointer: " + str)
+                       return
+               }
+               switch ptr.Elem().(type) {
+               case *reflect.IntType, *reflect.Int8Type, *reflect.Int16Type, *reflect.Int32Type, *reflect.Int64Type:
+                       s.scanInteger(tok, v, 10)
+               case *reflect.UintType, *reflect.Uint8Type, *reflect.Uint16Type, *reflect.Uint32Type, *reflect.Uint64Type, *reflect.UintptrType:
+                       s.scanInteger(tok, v, 10)
+               default:
+                       s.err = os.ErrorString("Scan: can't handle type: " + t.String())
+               }
        }
-       return i
 }
 
-// doScan does the real work.  At the moment, it handles only pointers to basic types.
+// doScan does the real work for scanning without a format string.
+// At the moment, it handles only pointers to basic types.
 func (s *ss) doScan(a []interface{}) int {
-       for n, param := range a {
+       for fieldnum, field := range a {
                // If the parameter has its own Scan method, use that.
-               if v, ok := param.(Scanner); ok {
+               if v, ok := field.(Scanner); ok {
                        s.err = v.Scan(s)
                        if s.err != nil {
-                               return n
+                               return fieldnum
                        }
                        continue
                }
-               tok := s.token()
-               switch v := param.(type) {
-               case *bool:
-                       *v = s.scanBool(tok)
-               case *complex:
-                       *v = complex(s.scanComplex(tok, (*ss).scanFloat))
-               case *complex64:
-                       *v = complex64(s.scanComplex(tok, (*ss).scanFloat32))
-               case *complex128:
-                       *v = s.scanComplex(tok, (*ss).scanFloat64)
-               case *int:
-                       *v = int(s.scanInt(tok, intBits))
-               case *int8:
-                       *v = int8(s.scanInt(tok, 8))
-               case *int16:
-                       *v = int16(s.scanInt(tok, 16))
-               case *int32:
-                       *v = int32(s.scanInt(tok, 32))
-               case *int64:
-                       *v = s.scanInt(tok, 64)
-               case *uint:
-                       *v = uint(s.scanUint(tok, intBits))
-               case *uint8:
-                       *v = uint8(s.scanUint(tok, 8))
-               case *uint16:
-                       *v = uint16(s.scanUint(tok, 16))
-               case *uint32:
-                       *v = uint32(s.scanUint(tok, 32))
-               case *uint64:
-                       *v = s.scanUint(tok, 64)
-               case *uintptr:
-                       *v = uintptr(s.scanUint(tok, uintptrBits))
-               case *float:
-                       if s.err == nil {
-                               *v, s.err = strconv.Atof(tok)
-                       } else {
-                               *v = 0
-                       }
-               case *float32:
-                       if s.err == nil {
-                               *v, s.err = strconv.Atof32(tok)
-                       } else {
-                               *v = 0
-                       }
-               case *float64:
-                       if s.err == nil {
-                               *v, s.err = strconv.Atof64(tok)
-                       } else {
-                               *v = 0
-                       }
-               case *string:
-                       *v = tok
-               default:
-                       t := reflect.Typeof(v)
-                       str := t.String()
-                       if _, ok := t.(*reflect.PtrType); !ok {
-                               s.err = os.ErrorString("Scan: type not a pointer: " + str)
-                       } else {
-                               s.err = os.ErrorString("Scan: can't handle type: " + str)
-                       }
-               }
+               s.scanOne(field)
                if s.err != nil {
-                       return n
+                       return fieldnum
                }
        }
        // Check for newline if required.
@@ -469,3 +570,70 @@ func (s *ss) doScan(a []interface{}) int {
        }
        return len(a)
 }
+
+// doScanf does the real work when scanning with a format string.
+//  At the moment, it handles only pointers to basic types.
+func (s *ss) doScanf(format string, a []interface{}) int {
+       end := len(format) - 1
+       fieldnum := 0 // we process one item per non-trivial format
+       for i := 0; i <= end; {
+               c, w := utf8.DecodeRuneInString(format[i:])
+               if c != '%' || i == end {
+                       // TODO: WHAT NOW?
+                       i += w
+                       continue
+               }
+               i++
+               // TODO: FLAGS
+               c, w = utf8.DecodeRuneInString(format[i:])
+               i += w
+               // percent is special - absorbs no operand
+               if c == '%' {
+                       // TODO: WHAT NOW?
+                       continue
+               }
+               if fieldnum >= len(a) { // out of operands
+                       s.err = os.ErrorString("too few operands for format %" + format[i-w:])
+                       return fieldnum
+               }
+               field := a[fieldnum]
+               fieldnum++
+
+               // If the parameter has its own Scan method, use that.
+               if v, ok := field.(Scanner); ok {
+                       s.err = v.Scan(s)
+                       if s.err != nil {
+                               return fieldnum - 1
+                       }
+                       continue
+               }
+               if c == 'v' {
+                       // Default format works; just call doScan, but note that it will scan for the token
+                       s.scanOne(field)
+               } else {
+                       tok := s.token()
+                       switch c {
+                       case 't':
+                               if v, ok := field.(*bool); ok {
+                                       *v = s.scanBool(tok)
+                               } else {
+                                       s.typeError(field, "boolean")
+                               }
+                       case 'b':
+                               s.scanInteger(tok, field, 2)
+                       case 'o':
+                               s.scanInteger(tok, field, 8)
+                       case 'd':
+                               s.scanInteger(tok, field, 10)
+                       case 'x', 'X':
+                               s.scanInteger(tok, field, 16)
+                       default:
+                               s.err = os.ErrorString("unknown scanning verb %" + format[i-w:])
+                       }
+                       if s.err != nil {
+                               return fieldnum - 1
+                       }
+               }
+       }
+       return fieldnum
+}
index 19bb6d2a5bd0542c393ee6393088b96b3ecefc15..ca51cf0a219d6c311f00c026b0889abfd35a440f 100644 (file)
@@ -19,24 +19,58 @@ type ScanTest struct {
        out  interface{}
 }
 
-var boolVal bool
-var intVal int
-var int8Val int8
-var int16Val int16
-var int32Val int32
-var int64Val int64
-var uintVal uint
-var uint8Val uint8
-var uint16Val uint16
-var uint32Val uint32
-var uint64Val uint64
-var floatVal float
-var float32Val float32
-var float64Val float64
-var stringVal string
-var complexVal complex
-var complex64Val complex64
-var complex128Val complex128
+type ScanfTest struct {
+       format string
+       text   string
+       in     interface{}
+       out    interface{}
+}
+
+type (
+       renamedInt     int
+       renamedInt8    int8
+       renamedInt16   int16
+       renamedInt32   int32
+       renamedInt64   int64
+       renamedUint    uint
+       renamedUint8   uint8
+       renamedUint16  uint16
+       renamedUint32  uint32
+       renamedUint64  uint64
+       renamedUintptr uintptr
+)
+
+var (
+       boolVal           bool
+       intVal            int
+       int8Val           int8
+       int16Val          int16
+       int32Val          int32
+       int64Val          int64
+       uintVal           uint
+       uint8Val          uint8
+       uint16Val         uint16
+       uint32Val         uint32
+       uint64Val         uint64
+       floatVal          float
+       float32Val        float32
+       float64Val        float64
+       stringVal         string
+       complexVal        complex
+       complex64Val      complex64
+       complex128Val     complex128
+       renamedIntVal     renamedInt
+       renamedInt8Val    renamedInt8
+       renamedInt16Val   renamedInt16
+       renamedInt32Val   renamedInt32
+       renamedInt64Val   renamedInt64
+       renamedUintVal    renamedUint
+       renamedUint8Val   renamedUint8
+       renamedUint16Val  renamedUint16
+       renamedUint32Val  renamedUint32
+       renamedUint64Val  renamedUint64
+       renamedUintptrVal renamedUintptr
+)
 
 // Xs accepts any non-empty run of x's.
 var xPat = testing.MustCompile("x+")
@@ -92,10 +126,66 @@ var scanTests = []ScanTest{
        ScanTest{"-3.45e1-3i\n", &complex64Val, complex64(-3.45e1 - 3i)},
        ScanTest{"-.45e1-1e2i\n", &complex128Val, complex128(-.45e1 - 100i)},
 
+       // Renamed types
+       ScanTest{"101\n", &renamedIntVal, renamedInt(101)},
+       ScanTest{"102\n", &renamedIntVal, renamedInt(102)},
+       ScanTest{"103\n", &renamedUintVal, renamedUint(103)},
+       ScanTest{"104\n", &renamedUintVal, renamedUint(104)},
+       ScanTest{"105\n", &renamedInt8Val, renamedInt8(105)},
+       ScanTest{"106\n", &renamedInt16Val, renamedInt16(106)},
+       ScanTest{"107\n", &renamedInt32Val, renamedInt32(107)},
+       ScanTest{"108\n", &renamedInt64Val, renamedInt64(108)},
+       ScanTest{"109\n", &renamedUint8Val, renamedUint8(109)},
+       ScanTest{"110\n", &renamedUint16Val, renamedUint16(110)},
+       ScanTest{"111\n", &renamedUint32Val, renamedUint32(111)},
+       ScanTest{"112\n", &renamedUint64Val, renamedUint64(112)},
+       ScanTest{"113\n", &renamedUintptrVal, renamedUintptr(113)},
+
        // Custom scanner.
        ScanTest{"  xxx ", &xVal, Xs("xxx")},
 }
 
+var scanfTests = []ScanfTest{
+       ScanfTest{"%v", "FALSE\n", &boolVal, false},
+       ScanfTest{"%t", "true\n", &boolVal, true},
+       ScanfTest{"%v", "-71\n", &intVal, -71},
+       ScanfTest{"%d", "72\n", &intVal, 72},
+       ScanfTest{"%d", "73\n", &int8Val, int8(73)},
+       ScanfTest{"%d", "-74\n", &int16Val, int16(-74)},
+       ScanfTest{"%d", "75\n", &int32Val, int32(75)},
+       ScanfTest{"%d", "76\n", &int64Val, int64(76)},
+       ScanfTest{"%b", "1001001\n", &intVal, 73},
+       ScanfTest{"%o", "075\n", &intVal, 075},
+       ScanfTest{"%x", "a75\n", &intVal, 0xa75},
+       ScanfTest{"%v", "71\n", &uintVal, uint(71)},
+       ScanfTest{"%d", "72\n", &uintVal, uint(72)},
+       ScanfTest{"%d", "73\n", &uint8Val, uint8(73)},
+       ScanfTest{"%d", "74\n", &uint16Val, uint16(74)},
+       ScanfTest{"%d", "75\n", &uint32Val, uint32(75)},
+       ScanfTest{"%d", "76\n", &uint64Val, uint64(76)},
+       ScanfTest{"%b", "1001001\n", &uintVal, uint(73)},
+       ScanfTest{"%o", "075\n", &uintVal, uint(075)},
+       ScanfTest{"%x", "a75\n", &uintVal, uint(0xa75)},
+       ScanfTest{"%x", "A75\n", &uintVal, uint(0xa75)},
+
+       // Renamed types
+       ScanfTest{"%v", "101\n", &renamedIntVal, renamedInt(101)},
+       ScanfTest{"%d", "102\n", &renamedIntVal, renamedInt(102)},
+       ScanfTest{"%v", "103\n", &renamedUintVal, renamedUint(103)},
+       ScanfTest{"%d", "104\n", &renamedUintVal, renamedUint(104)},
+       ScanfTest{"%d", "105\n", &renamedInt8Val, renamedInt8(105)},
+       ScanfTest{"%d", "106\n", &renamedInt16Val, renamedInt16(106)},
+       ScanfTest{"%d", "107\n", &renamedInt32Val, renamedInt32(107)},
+       ScanfTest{"%d", "108\n", &renamedInt64Val, renamedInt64(108)},
+       ScanfTest{"%d", "109\n", &renamedUint8Val, renamedUint8(109)},
+       ScanfTest{"%d", "110\n", &renamedUint16Val, renamedUint16(110)},
+       ScanfTest{"%d", "111\n", &renamedUint32Val, renamedUint32(111)},
+       ScanfTest{"%d", "112\n", &renamedUint64Val, renamedUint64(112)},
+       ScanfTest{"%d", "113\n", &renamedUintptrVal, renamedUintptr(113)},
+
+       ScanfTest{"%x", "FFFFFFFF\n", &uint32Val, uint32(0xFFFFFFFF)},
+}
+
 var overflowTests = []ScanTest{
        ScanTest{"128", &int8Val, 0},
        ScanTest{"32768", &int16Val, 0},
@@ -142,6 +232,30 @@ func TestScanln(t *testing.T) {
        testScan(t, Fscanln)
 }
 
+func TestScanf(t *testing.T) {
+       for _, test := range scanfTests {
+               r := strings.NewReader(test.text)
+               n, err := XXXFscanf(r, test.format, test.in)
+               if err != nil {
+                       t.Errorf("got error scanning (%q, %q): %s", test.format, test.text, err)
+                       continue
+               }
+               if n != 1 {
+                       t.Errorf("count error on entry (%q, %q): got %d", test.format, test.text, n)
+                       continue
+               }
+               // The incoming value may be a pointer
+               v := reflect.NewValue(test.in)
+               if p, ok := v.(*reflect.PtrValue); ok {
+                       v = p.Elem()
+               }
+               val := v.Interface()
+               if !reflect.DeepEqual(val, test.out) {
+                       t.Errorf("scanning (%q, %q): expected %v got %v, type %T", test.format, test.text, test.out, val, val)
+               }
+       }
+}
+
 func TestScanOverflow(t *testing.T) {
        // different machines and different types report errors with different strings.
        re := testing.MustCompile("overflow|too large|out of range|not representable")