Commit 4f70c151 authored by Rob Pike's avatar Rob Pike

fmt: fix handling of %% verb in Scanf

There were a couple of bugs, including not requiring a percent and
returning the wrong error for a bad format containing %%.

Both are addressed by fixing the first.

Fixes #34180.

Change-Id: If96c0c0258bcb95eec49871437d719cb9d399d9b
Reviewed-on: https://go-review.googlesource.com/c/go/+/202879
Run-TryBot: Emmanuel Odeke <emm.odeke@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarRobert Griesemer <gri@golang.org>
parent 8f30d251
...@@ -940,6 +940,15 @@ const ( ...@@ -940,6 +940,15 @@ const (
uintptrBits = 32 << (^uintptr(0) >> 63) uintptrBits = 32 << (^uintptr(0) >> 63)
) )
// scanPercent scans a literal percent character.
func (s *ss) scanPercent() {
s.SkipSpace()
s.notEOF()
if !s.accept("%") {
s.errorString("missing literal %")
}
}
// 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 rune, arg interface{}) { func (s *ss) scanOne(verb rune, arg interface{}) {
s.buf = s.buf[:0] s.buf = s.buf[:0]
...@@ -1203,6 +1212,10 @@ func (s *ss) doScanf(format string, a []interface{}) (numProcessed int, err erro ...@@ -1203,6 +1212,10 @@ func (s *ss) doScanf(format string, a []interface{}) (numProcessed int, err erro
if c != 'c' { if c != 'c' {
s.SkipSpace() s.SkipSpace()
} }
if c == '%' {
s.scanPercent()
continue // Do not consume an argument.
}
s.argLimit = s.limit s.argLimit = s.limit
if f := s.count + s.maxWid; f < s.argLimit { if f := s.count + s.maxWid; f < s.argLimit {
s.argLimit = f s.argLimit = f
......
...@@ -325,6 +325,8 @@ var scanfTests = []ScanfTest{ ...@@ -325,6 +325,8 @@ var scanfTests = []ScanfTest{
{"%c", " ", &uintVal, uint(' ')}, // %c must accept a blank. {"%c", " ", &uintVal, uint(' ')}, // %c must accept a blank.
{"%c", "\t", &uintVal, uint('\t')}, // %c must accept any space. {"%c", "\t", &uintVal, uint('\t')}, // %c must accept any space.
{"%c", "\n", &uintVal, uint('\n')}, // %c must accept any space. {"%c", "\n", &uintVal, uint('\n')}, // %c must accept any space.
{"%d%%", "23%\n", &uintVal, uint(23)}, // %% matches literal %.
{"%%%d", "%23\n", &uintVal, uint(23)}, // %% matches literal %.
// space handling // space handling
{"%d", "27", &intVal, 27}, {"%d", "27", &intVal, 27},
...@@ -467,6 +469,9 @@ var multiTests = []ScanfMultiTest{ ...@@ -467,6 +469,9 @@ var multiTests = []ScanfMultiTest{
{"X%d", "10X", args(&intVal), nil, "input does not match format"}, {"X%d", "10X", args(&intVal), nil, "input does not match format"},
{"%d%", "42%", args(&intVal), args(42), "missing verb: % at end of format string"}, {"%d%", "42%", args(&intVal), args(42), "missing verb: % at end of format string"},
{"%d% ", "42%", args(&intVal), args(42), "too few operands for format '% '"}, // Slightly odd error, but correct. {"%d% ", "42%", args(&intVal), args(42), "too few operands for format '% '"}, // Slightly odd error, but correct.
{"%%%d", "xxx 42", args(&intVal), args(42), "missing literal %"},
{"%%%d", "x42", args(&intVal), args(42), "missing literal %"},
{"%%%d", "42", args(&intVal), args(42), "missing literal %"},
// Bad UTF-8: should see every byte. // Bad UTF-8: should see every byte.
{"%c%c%c", "\xc2X\xc2", args(&r1, &r2, &r3), args(utf8.RuneError, 'X', utf8.RuneError), ""}, {"%c%c%c", "\xc2X\xc2", args(&r1, &r2, &r3), args(utf8.RuneError, 'X', utf8.RuneError), ""},
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment