From ac51237affc016dd22f5b4f67dc8a2d09adf1fb2 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 29 Jan 2019 22:24:36 -0500 Subject: [PATCH] fmt: format 0b, 0o prefixes in %#b and %O This CL modifies fmt's printer to implement %#b and %O to emit leading 0b and 0o prefixes on binary and octal. (%#o is already taken and emits "0377"; %O emits "0o377".) See golang.org/design/19308-number-literals for background. For #19308. For #12711. Vet update is #29986. Change-Id: I7c38a4484c48a03abe9f6d45c7d981c7c314f583 Reviewed-on: https://go-review.googlesource.com/c/160246 Reviewed-by: Robert Griesemer Reviewed-by: Rob Pike --- src/fmt/doc.go | 5 +++-- src/fmt/fmt_test.go | 6 ++++++ src/fmt/format.go | 14 +++++++++++++- src/fmt/print.go | 18 +++++++++--------- 4 files changed, 31 insertions(+), 12 deletions(-) diff --git a/src/fmt/doc.go b/src/fmt/doc.go index c349f8e321..e0edff456c 100644 --- a/src/fmt/doc.go +++ b/src/fmt/doc.go @@ -26,6 +26,7 @@ %c the character represented by the corresponding Unicode code point %d base 10 %o base 8 + %O base 8 with 0o prefix %q a single-quoted character literal safely escaped with Go syntax. %x base 16, with lower-case letters for a-f %X base 16, with upper-case letters for A-F @@ -113,8 +114,8 @@ + always print a sign for numeric values; guarantee ASCII-only output for %q (%+q) - pad with spaces on the right rather than the left (left-justify the field) - # alternate format: add leading 0 for octal (%#o), 0x for hex (%#x); - 0X for hex (%#X); suppress 0x for %p (%#p); + # alternate format: add leading 0b for binary (%#b), 0 for octal (%#o), + 0x or 0X for hex (%#x or %#X); suppress 0x for %p (%#p); for %q, print a raw (backquoted) string if strconv.CanBackquote returns true; always print a decimal point for %e, %E, %f, %F, %g and %G; diff --git a/src/fmt/fmt_test.go b/src/fmt/fmt_test.go index 2d10c7a841..bbaf40a619 100644 --- a/src/fmt/fmt_test.go +++ b/src/fmt/fmt_test.go @@ -354,11 +354,17 @@ var fmtTests = []struct { {"%+d", -12345, "-12345"}, {"%b", 7, "111"}, {"%b", -6, "-110"}, + {"%#b", 7, "0b111"}, + {"%#b", -6, "-0b110"}, {"%b", ^uint32(0), "11111111111111111111111111111111"}, {"%b", ^uint64(0), "1111111111111111111111111111111111111111111111111111111111111111"}, {"%b", int64(-1 << 63), zeroFill("-1", 63, "")}, {"%o", 01234, "1234"}, + {"%o", -01234, "-1234"}, {"%#o", 01234, "01234"}, + {"%#o", -01234, "-01234"}, + {"%O", 01234, "0o1234"}, + {"%O", -01234, "-0o1234"}, {"%o", ^uint32(0), "37777777777"}, {"%o", ^uint64(0), "1777777777777777777777"}, {"%#X", 0, "0X0"}, diff --git a/src/fmt/format.go b/src/fmt/format.go index 6d93908095..24e7e9551a 100644 --- a/src/fmt/format.go +++ b/src/fmt/format.go @@ -191,7 +191,7 @@ func (f *fmt) fmtUnicode(u uint64) { } // fmtInteger formats signed and unsigned integers. -func (f *fmt) fmtInteger(u uint64, base int, isSigned bool, digits string) { +func (f *fmt) fmtInteger(u uint64, base int, isSigned bool, verb rune, digits string) { negative := isSigned && int64(u) < 0 if negative { u = -u @@ -275,6 +275,12 @@ func (f *fmt) fmtInteger(u uint64, base int, isSigned bool, digits string) { // Various prefixes: 0x, -, etc. if f.sharp { switch base { + case 2: + // Add a leading 0b. + i-- + buf[i] = 'b' + i-- + buf[i] = '0' case 8: if buf[i] != '0' { i-- @@ -288,6 +294,12 @@ func (f *fmt) fmtInteger(u uint64, base int, isSigned bool, digits string) { buf[i] = '0' } } + if verb == 'O' { + i-- + buf[i] = 'o' + i-- + buf[i] = '0' + } if negative { i-- diff --git a/src/fmt/print.go b/src/fmt/print.go index 9976b8d263..121c7c59e4 100644 --- a/src/fmt/print.go +++ b/src/fmt/print.go @@ -363,7 +363,7 @@ func (p *pp) fmtBool(v bool, verb rune) { func (p *pp) fmt0x64(v uint64, leading0x bool) { sharp := p.fmt.sharp p.fmt.sharp = leading0x - p.fmt.fmtInteger(v, 16, unsigned, ldigits) + p.fmt.fmtInteger(v, 16, unsigned, 'v', ldigits) p.fmt.sharp = sharp } @@ -374,18 +374,18 @@ func (p *pp) fmtInteger(v uint64, isSigned bool, verb rune) { if p.fmt.sharpV && !isSigned { p.fmt0x64(v, true) } else { - p.fmt.fmtInteger(v, 10, isSigned, ldigits) + p.fmt.fmtInteger(v, 10, isSigned, verb, ldigits) } case 'd': - p.fmt.fmtInteger(v, 10, isSigned, ldigits) + p.fmt.fmtInteger(v, 10, isSigned, verb, ldigits) case 'b': - p.fmt.fmtInteger(v, 2, isSigned, ldigits) - case 'o': - p.fmt.fmtInteger(v, 8, isSigned, ldigits) + p.fmt.fmtInteger(v, 2, isSigned, verb, ldigits) + case 'o', 'O': + p.fmt.fmtInteger(v, 8, isSigned, verb, ldigits) case 'x': - p.fmt.fmtInteger(v, 16, isSigned, ldigits) + p.fmt.fmtInteger(v, 16, isSigned, verb, ldigits) case 'X': - p.fmt.fmtInteger(v, 16, isSigned, udigits) + p.fmt.fmtInteger(v, 16, isSigned, verb, udigits) case 'c': p.fmt.fmtC(v) case 'q': @@ -483,7 +483,7 @@ func (p *pp) fmtBytes(v []byte, verb rune, typeString string) { if i > 0 { p.buf.WriteByte(' ') } - p.fmt.fmtInteger(uint64(c), 10, unsigned, ldigits) + p.fmt.fmtInteger(uint64(c), 10, unsigned, verb, ldigits) } p.buf.WriteByte(']') } -- 2.48.1