Commit 29499858 authored by Rob Pike's avatar Rob Pike

fmt: give correct error for % at end of string when scanning

Previously it said, "bad verb %% for ...", which is not only wrong,
it's ironic as the fix is to use %% rather than % at the end of the
string. Diagnose the case where a simple % is at EOF.

If there's anything after the percent, the error is already good
but this CL also puts quotes around the verb designation ('%d' etc.)
to make it even clearer, especially when there is a space involved.

Fixes #12315.

Change-Id: I31d30659965e940d0bd9ce92a475aab3e2369ef0
Reviewed-on: https://go-review.googlesource.com/17150Reviewed-by: 's avatarIan Lance Taylor <iant@golang.org>
parent af8cd3f6
...@@ -538,7 +538,7 @@ func (s *ss) okVerb(verb rune, okVerbs, typ string) bool { ...@@ -538,7 +538,7 @@ func (s *ss) okVerb(verb rune, okVerbs, typ string) bool {
return true return true
} }
} }
s.errorString("bad verb %" + string(verb) + " for " + typ) s.errorString("bad verb '%" + string(verb) + "' for " + typ)
return false return false
} }
...@@ -1078,6 +1078,10 @@ func (s *ss) advance(format string) (i int) { ...@@ -1078,6 +1078,10 @@ func (s *ss) advance(format string) (i int) {
for i < len(format) { for i < len(format) {
fmtc, w := utf8.DecodeRuneInString(format[i:]) fmtc, w := utf8.DecodeRuneInString(format[i:])
if fmtc == '%' { if fmtc == '%' {
// % at end of string is an error.
if i+w == len(format) {
s.errorString("missing verb: % at end of format string")
}
// %% acts like a real percent // %% acts like a real percent
nextc, _ := utf8.DecodeRuneInString(format[i+w:]) // will not match % if string is empty nextc, _ := utf8.DecodeRuneInString(format[i+w:]) // will not match % if string is empty
if nextc != '%' { if nextc != '%' {
...@@ -1179,7 +1183,7 @@ func (s *ss) doScanf(format string, a []interface{}) (numProcessed int, err erro ...@@ -1179,7 +1183,7 @@ func (s *ss) doScanf(format string, a []interface{}) (numProcessed int, err erro
} }
if numProcessed >= len(a) { // out of operands if numProcessed >= len(a) { // out of operands
s.errorString("too few operands for format %" + format[i-w:]) s.errorString("too few operands for format '%" + format[i-w:] + "'")
break break
} }
arg := a[numProcessed] arg := a[numProcessed]
......
...@@ -293,6 +293,7 @@ var scanfTests = []ScanfTest{ ...@@ -293,6 +293,7 @@ var scanfTests = []ScanfTest{
// Interesting formats // Interesting formats
{"here is\tthe value:%d", "here is the\tvalue:118\n", &intVal, 118}, {"here is\tthe value:%d", "here is the\tvalue:118\n", &intVal, 118},
{"%% %%:%d", "% %:119\n", &intVal, 119}, {"%% %%:%d", "% %:119\n", &intVal, 119},
{"%d%%", "42%", &intVal, 42}, // %% at end of string.
// Corner cases // Corner cases
{"%x", "FFFFFFFF\n", &uint32Val, uint32(0xFFFFFFFF)}, {"%x", "FFFFFFFF\n", &uint32Val, uint32(0xFFFFFFFF)},
...@@ -358,6 +359,8 @@ var multiTests = []ScanfMultiTest{ ...@@ -358,6 +359,8 @@ var multiTests = []ScanfMultiTest{
{"%d %d", "23 18 27", args(&i, &j, &k), args(23, 18), "too many operands"}, {"%d %d", "23 18 27", args(&i, &j, &k), args(23, 18), "too many operands"},
{"%c", "\u0100", args(&int8Val), nil, "overflow"}, {"%c", "\u0100", args(&int8Val), nil, "overflow"},
{"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), "too few operands for format '% '"}, // Slightly odd error, but correct.
// 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