]> Cypherpunks repositories - gostls13.git/commitdiff
fmt.Scan: scan []byte arguments
authorRob Pike <r@golang.org>
Wed, 2 Jun 2010 23:28:01 +0000 (16:28 -0700)
committerRob Pike <r@golang.org>
Wed, 2 Jun 2010 23:28:01 +0000 (16:28 -0700)
R=rsc
CC=golang-dev
https://golang.org/cl/1486041

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

index c45438c4eeebf923045ae230c6520c0807d1e6fb..bb6990ae9727472b95df29fb6284c499f162beef 100644 (file)
 package fmt
 
 // BUG: format precision and flags are not yet implemented for scanning.
-// BUG: %sqx are not yet implemented for scanning byte slices.
 
 import (
        "bytes"
index 2708568579e3830073ceb4f336a6b4eae36d074d..87ec695fb5db0e225309b0acf53416effc79ccc9 100644 (file)
@@ -649,6 +649,10 @@ func (s *ss) scanOne(verb int, field interface{}) {
                }
        case *string:
                *v = s.convertString(verb)
+       case *[]byte:
+               // We scan to string and convert so we get a copy of the data.
+               // If we scanned to bytes, the slice would point at the buffer.
+               *v = []byte(s.convertString(verb))
        default:
                val := reflect.NewValue(v)
                ptr, ok := val.(*reflect.PtrValue)
@@ -683,6 +687,17 @@ func (s *ss) scanOne(verb int, field interface{}) {
                        v.Set(uintptr(s.scanUint(verb, uintptrBits)))
                case *reflect.StringValue:
                        v.Set(s.convertString(verb))
+               case *reflect.SliceValue:
+                       // For now, can only handle (renamed) []byte.
+                       typ := v.Type().(*reflect.SliceType)
+                       if _, ok := typ.Elem().(*reflect.Uint8Type); !ok {
+                               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.Uint8Value).Set(str[i])
+                       }
                case *reflect.FloatValue:
                        v.Set(float(s.convertFloat(s.token())))
                case *reflect.Float32Value:
@@ -696,6 +711,7 @@ func (s *ss) scanOne(verb int, field interface{}) {
                case *reflect.Complex128Value:
                        v.Set(s.scanComplex(verb, (*ss).convertFloat64))
                default:
+               CantHandle:
                        s.errorString("Scan: can't handle type: " + val.Type().String())
                }
        }
@@ -738,12 +754,12 @@ func (s *ss) doScan(a []interface{}) (numProcessed int, err os.Error) {
        return
 }
 
-// advance determines whether the next characters in the input matches
+// advance determines whether the next characters in the input match
 // those of the format.  It returns the number of bytes (sic) consumed
 // in the format. Newlines included, all runs of space characters in
-// either input or format behave as a single space. This routines also
-// handles the %% case.  If the return value is zero, either the format
-// is sitting on a % or the input is empty.
+// either input or format behave as a single space. This routine also
+// handles the %% case.  If the return value is zero, either format
+// starts with a % (with no following %) or the input is empty.
 func (s *ss) advance(format string) (i int) {
        for i < len(format) {
                fmtc, w := utf8.DecodeRuneInString(format[i:])
@@ -797,9 +813,9 @@ func (s *ss) doScanf(format string, a []interface{}) (numProcessed int, err os.E
                        i += w
                        continue
                }
-               // Either we have a percent character or we ran out of input.
+               // Either we failed to advance, we have a percent character, or we ran out of input.
                if format[i] != '%' {
-                       // Out of format.  Have we run out of input?
+                       // Can't advance format.  Do we have arguments still to process?
                        if i < len(a) {
                                s.errorString("too many arguments for format")
                        }
index cd19903ebb35ca081c7dd55e29cdc780108db0fa..6ea5ec95fd4fc19947a97a6c5c6c85477ce2eda0 100644 (file)
@@ -40,6 +40,7 @@ type (
        renamedUint64     uint64
        renamedUintptr    uintptr
        renamedString     string
+       renamedBytes      []byte
        renamedFloat      float
        renamedFloat32    float32
        renamedFloat64    float64
@@ -64,6 +65,7 @@ var (
        float32Val           float32
        float64Val           float64
        stringVal            string
+       bytesVal             []byte
        complexVal           complex
        complex64Val         complex64
        complex128Val        complex128
@@ -80,6 +82,7 @@ var (
        renamedUint64Val     renamedUint64
        renamedUintptrVal    renamedUintptr
        renamedStringVal     renamedString
+       renamedBytesVal      renamedBytes
        renamedFloatVal      renamedFloat
        renamedFloat32Val    renamedFloat32
        renamedFloat64Val    renamedFloat64
@@ -140,6 +143,7 @@ var scanTests = []ScanTest{
        ScanTest{"2.3e1\n", &float32Val, float32(2.3e1)},
        ScanTest{"2.3e2\n", &float64Val, float64(2.3e2)},
        ScanTest{"2.35\n", &stringVal, "2.35"},
+       ScanTest{"2345678\n", &bytesVal, []byte("2345678")},
        ScanTest{"(3.4e1-2i)\n", &complexVal, 3.4e1 - 2i},
        ScanTest{"-3.45e1-3i\n", &complex64Val, complex64(-3.45e1 - 3i)},
        ScanTest{"-.45e1-1e2i\n", &complex128Val, complex128(-.45e1 - 100i)},
@@ -162,6 +166,7 @@ var scanTests = []ScanTest{
        ScanTest{"112\n", &renamedUint64Val, renamedUint64(112)},
        ScanTest{"113\n", &renamedUintptrVal, renamedUintptr(113)},
        ScanTest{"114\n", &renamedStringVal, renamedString("114")},
+       ScanTest{"115\n", &renamedBytesVal, renamedBytes([]byte("115"))},
 
        // Custom scanner.
        ScanTest{"  xxx ", &xVal, Xs("xxx")},
@@ -196,6 +201,12 @@ var scanfTests = []ScanfTest{
        ScanfTest{"%q", `"quoted\twith\\do\u0075bl\x65s"` + "\n", &stringVal, "quoted\twith\\doubles"},
        ScanfTest{"%q", "`quoted with backs`\n", &stringVal, "quoted with backs"},
 
+       // Byte slices
+       ScanfTest{"%s", "bytes-%s\n", &bytesVal, []byte("bytes-%s")},
+       ScanfTest{"%x", "62797465732d2578\n", &bytesVal, []byte("bytes-%x")},
+       ScanfTest{"%q", `"bytes\rwith\vdo\u0075bl\x65s"` + "\n", &bytesVal, []byte("bytes\rwith\vdoubles")},
+       ScanfTest{"%q", "`bytes with backs`\n", &bytesVal, []byte("bytes with backs")},
+
        // Renamed types
        ScanfTest{"%v\n", "true\n", &renamedBoolVal, renamedBool(true)},
        ScanfTest{"%t\n", "F\n", &renamedBoolVal, renamedBool(false)},
@@ -213,6 +224,7 @@ var scanfTests = []ScanfTest{
        ScanfTest{"%d", "112\n", &renamedUint64Val, renamedUint64(112)},
        ScanfTest{"%d", "113\n", &renamedUintptrVal, renamedUintptr(113)},
        ScanfTest{"%s", "114\n", &renamedStringVal, renamedString("114")},
+       ScanfTest{"%q", "\"1155\"\n", &renamedBytesVal, renamedBytes([]byte("1155"))},
        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)},