mirror of https://github.com/golang/go.git
fmt: handle negative width/prec when supplied as an argument
Negative width arguments now left align the way a minus-width in the format string aligns. The minus in the format string overrides the sign of the argument as in C. Precision behavior is modified to include an error if the argument is negative. This differs from a negative precision in a format string which just terminates the format. Additional checks for large magnitude widths and precisions are added to make the runtime behavior (failure, but with different error messages), more consistent between format string specified width/precision and argument specified width/precision. Fixes #11376 Change-Id: I8c7ed21088e9c18128a45d4c487c5ab9fafd13ef Reviewed-on: https://go-review.googlesource.com/11405 Reviewed-by: Rob Pike <r@golang.org> Run-TryBot: Rob Pike <r@golang.org>
This commit is contained in:
parent
2bcdb5a5d9
commit
4e834cff4f
|
|
@ -832,6 +832,10 @@ var reorderTests = []struct {
|
|||
{"%[5]d %[2]d %d", SE{1, 2, 3}, "%!d(BADINDEX) 2 3"},
|
||||
{"%d %[3]d %d", SE{1, 2}, "1 %!d(BADINDEX) 2"}, // Erroneous index does not affect sequence.
|
||||
{"%.[]", SE{}, "%!](BADINDEX)"}, // Issue 10675
|
||||
{"%.-3d", SE{42}, "%!-(int=42)3d"}, // TODO: Should this set return better error messages?
|
||||
{"%2147483648d", SE{42}, "%!(NOVERB)%!(EXTRA int=42)"},
|
||||
{"%-2147483648d", SE{42}, "%!(NOVERB)%!(EXTRA int=42)"},
|
||||
{"%.2147483648d", SE{42}, "%!(NOVERB)%!(EXTRA int=42)"},
|
||||
}
|
||||
|
||||
func TestReorder(t *testing.T) {
|
||||
|
|
@ -1158,14 +1162,20 @@ var startests = []struct {
|
|||
out string
|
||||
}{
|
||||
{"%*d", args(4, 42), " 42"},
|
||||
{"%-*d", args(4, 42), "42 "},
|
||||
{"%*d", args(-4, 42), "42 "},
|
||||
{"%-*d", args(-4, 42), "42 "},
|
||||
{"%.*d", args(4, 42), "0042"},
|
||||
{"%*.*d", args(8, 4, 42), " 0042"},
|
||||
{"%0*d", args(4, 42), "0042"},
|
||||
{"%-*d", args(4, 42), "42 "},
|
||||
|
||||
// erroneous
|
||||
{"%*d", args(nil, 42), "%!(BADWIDTH)42"},
|
||||
{"%*d", args(int(1e7), 42), "%!(BADWIDTH)42"},
|
||||
{"%*d", args(int(-1e7), 42), "%!(BADWIDTH)42"},
|
||||
{"%.*d", args(nil, 42), "%!(BADPREC)42"},
|
||||
{"%.*d", args(-1, 42), "%!(BADPREC)42"},
|
||||
{"%.*d", args(int(1e7), 42), "%!(BADPREC)42"},
|
||||
{"%*d", args(5, "foo"), "%!d(string= foo)"},
|
||||
{"%*% %d", args(20, 5), "% 5"},
|
||||
{"%*", args(4), "%!(NOVERB)"},
|
||||
|
|
|
|||
|
|
@ -285,15 +285,20 @@ func getField(v reflect.Value, i int) reflect.Value {
|
|||
return val
|
||||
}
|
||||
|
||||
// tooLarge reports whether the magnitude of the integer is
|
||||
// too large to be used as a formatting width or precision.
|
||||
func tooLarge(x int) bool {
|
||||
const max int = 1e6
|
||||
return x > max || x < -max
|
||||
}
|
||||
|
||||
// parsenum converts ASCII to integer. num is 0 (and isnum is false) if no number present.
|
||||
func parsenum(s string, start, end int) (num int, isnum bool, newi int) {
|
||||
if start >= end {
|
||||
return 0, false, end
|
||||
}
|
||||
for newi = start; newi < end && '0' <= s[newi] && s[newi] <= '9'; newi++ {
|
||||
const maxInt32 = 1<<31 - 1 // 31 bits is plenty for a width.
|
||||
max := maxInt32/10 - 1
|
||||
if num > max {
|
||||
if tooLarge(num) {
|
||||
return 0, false, end // Overflow; crazy long number most likely.
|
||||
}
|
||||
num = num*10 + int(s[newi]-'0')
|
||||
|
|
@ -1025,6 +1030,10 @@ func intFromArg(a []interface{}, argNum int) (num int, isInt bool, newArgNum int
|
|||
if argNum < len(a) {
|
||||
num, isInt = a[argNum].(int)
|
||||
newArgNum = argNum + 1
|
||||
if tooLarge(num) {
|
||||
num = 0
|
||||
isInt = false
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
@ -1119,9 +1128,17 @@ func (p *pp) doPrintf(format string, a []interface{}) {
|
|||
if i < end && format[i] == '*' {
|
||||
i++
|
||||
p.fmt.wid, p.fmt.widPresent, argNum = intFromArg(a, argNum)
|
||||
|
||||
if !p.fmt.widPresent {
|
||||
p.buf.Write(badWidthBytes)
|
||||
}
|
||||
|
||||
// We have a negative width, so take its value and ensure
|
||||
// that the minus flag is set
|
||||
if p.fmt.wid < 0 {
|
||||
p.fmt.wid = -p.fmt.wid
|
||||
p.fmt.minus = true
|
||||
}
|
||||
afterIndex = false
|
||||
} else {
|
||||
p.fmt.wid, p.fmt.widPresent, i = parsenum(format, i, end)
|
||||
|
|
@ -1140,6 +1157,11 @@ func (p *pp) doPrintf(format string, a []interface{}) {
|
|||
if i < end && format[i] == '*' {
|
||||
i++
|
||||
p.fmt.prec, p.fmt.precPresent, argNum = intFromArg(a, argNum)
|
||||
// Negative precision arguments don't make sense
|
||||
if p.fmt.prec < 0 {
|
||||
p.fmt.prec = 0
|
||||
p.fmt.precPresent = false
|
||||
}
|
||||
if !p.fmt.precPresent {
|
||||
p.buf.Write(badPrecBytes)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue