Commit ac51237a authored by Russ Cox's avatar Russ Cox

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/160246Reviewed-by: default avatarRobert Griesemer <gri@golang.org>
Reviewed-by: default avatarRob Pike <r@golang.org>
parent e1a6d1fc
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
%c the character represented by the corresponding Unicode code point %c the character represented by the corresponding Unicode code point
%d base 10 %d base 10
%o base 8 %o base 8
%O base 8 with 0o prefix
%q a single-quoted character literal safely escaped with Go syntax. %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 lower-case letters for a-f
%X base 16, with upper-case letters for A-F %X base 16, with upper-case letters for A-F
...@@ -113,8 +114,8 @@ ...@@ -113,8 +114,8 @@
+ always print a sign for numeric values; + always print a sign for numeric values;
guarantee ASCII-only output for %q (%+q) guarantee ASCII-only output for %q (%+q)
- pad with spaces on the right rather than the left (left-justify the field) - 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); # alternate format: add leading 0b for binary (%#b), 0 for octal (%#o),
0X for hex (%#X); suppress 0x for %p (%#p); 0x or 0X for hex (%#x or %#X); suppress 0x for %p (%#p);
for %q, print a raw (backquoted) string if strconv.CanBackquote for %q, print a raw (backquoted) string if strconv.CanBackquote
returns true; returns true;
always print a decimal point for %e, %E, %f, %F, %g and %G; always print a decimal point for %e, %E, %f, %F, %g and %G;
......
...@@ -354,11 +354,17 @@ var fmtTests = []struct { ...@@ -354,11 +354,17 @@ var fmtTests = []struct {
{"%+d", -12345, "-12345"}, {"%+d", -12345, "-12345"},
{"%b", 7, "111"}, {"%b", 7, "111"},
{"%b", -6, "-110"}, {"%b", -6, "-110"},
{"%#b", 7, "0b111"},
{"%#b", -6, "-0b110"},
{"%b", ^uint32(0), "11111111111111111111111111111111"}, {"%b", ^uint32(0), "11111111111111111111111111111111"},
{"%b", ^uint64(0), "1111111111111111111111111111111111111111111111111111111111111111"}, {"%b", ^uint64(0), "1111111111111111111111111111111111111111111111111111111111111111"},
{"%b", int64(-1 << 63), zeroFill("-1", 63, "")}, {"%b", int64(-1 << 63), zeroFill("-1", 63, "")},
{"%o", 01234, "1234"}, {"%o", 01234, "1234"},
{"%o", -01234, "-1234"},
{"%#o", 01234, "01234"}, {"%#o", 01234, "01234"},
{"%#o", -01234, "-01234"},
{"%O", 01234, "0o1234"},
{"%O", -01234, "-0o1234"},
{"%o", ^uint32(0), "37777777777"}, {"%o", ^uint32(0), "37777777777"},
{"%o", ^uint64(0), "1777777777777777777777"}, {"%o", ^uint64(0), "1777777777777777777777"},
{"%#X", 0, "0X0"}, {"%#X", 0, "0X0"},
......
...@@ -191,7 +191,7 @@ func (f *fmt) fmtUnicode(u uint64) { ...@@ -191,7 +191,7 @@ func (f *fmt) fmtUnicode(u uint64) {
} }
// fmtInteger formats signed and unsigned integers. // 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 negative := isSigned && int64(u) < 0
if negative { if negative {
u = -u u = -u
...@@ -275,6 +275,12 @@ func (f *fmt) fmtInteger(u uint64, base int, isSigned bool, digits string) { ...@@ -275,6 +275,12 @@ func (f *fmt) fmtInteger(u uint64, base int, isSigned bool, digits string) {
// Various prefixes: 0x, -, etc. // Various prefixes: 0x, -, etc.
if f.sharp { if f.sharp {
switch base { switch base {
case 2:
// Add a leading 0b.
i--
buf[i] = 'b'
i--
buf[i] = '0'
case 8: case 8:
if buf[i] != '0' { if buf[i] != '0' {
i-- i--
...@@ -288,6 +294,12 @@ func (f *fmt) fmtInteger(u uint64, base int, isSigned bool, digits string) { ...@@ -288,6 +294,12 @@ func (f *fmt) fmtInteger(u uint64, base int, isSigned bool, digits string) {
buf[i] = '0' buf[i] = '0'
} }
} }
if verb == 'O' {
i--
buf[i] = 'o'
i--
buf[i] = '0'
}
if negative { if negative {
i-- i--
......
...@@ -363,7 +363,7 @@ func (p *pp) fmtBool(v bool, verb rune) { ...@@ -363,7 +363,7 @@ func (p *pp) fmtBool(v bool, verb rune) {
func (p *pp) fmt0x64(v uint64, leading0x bool) { func (p *pp) fmt0x64(v uint64, leading0x bool) {
sharp := p.fmt.sharp sharp := p.fmt.sharp
p.fmt.sharp = leading0x p.fmt.sharp = leading0x
p.fmt.fmtInteger(v, 16, unsigned, ldigits) p.fmt.fmtInteger(v, 16, unsigned, 'v', ldigits)
p.fmt.sharp = sharp p.fmt.sharp = sharp
} }
...@@ -374,18 +374,18 @@ func (p *pp) fmtInteger(v uint64, isSigned bool, verb rune) { ...@@ -374,18 +374,18 @@ func (p *pp) fmtInteger(v uint64, isSigned bool, verb rune) {
if p.fmt.sharpV && !isSigned { if p.fmt.sharpV && !isSigned {
p.fmt0x64(v, true) p.fmt0x64(v, true)
} else { } else {
p.fmt.fmtInteger(v, 10, isSigned, ldigits) p.fmt.fmtInteger(v, 10, isSigned, verb, ldigits)
} }
case 'd': case 'd':
p.fmt.fmtInteger(v, 10, isSigned, ldigits) p.fmt.fmtInteger(v, 10, isSigned, verb, ldigits)
case 'b': case 'b':
p.fmt.fmtInteger(v, 2, isSigned, ldigits) p.fmt.fmtInteger(v, 2, isSigned, verb, ldigits)
case 'o': case 'o', 'O':
p.fmt.fmtInteger(v, 8, isSigned, ldigits) p.fmt.fmtInteger(v, 8, isSigned, verb, ldigits)
case 'x': case 'x':
p.fmt.fmtInteger(v, 16, isSigned, ldigits) p.fmt.fmtInteger(v, 16, isSigned, verb, ldigits)
case 'X': case 'X':
p.fmt.fmtInteger(v, 16, isSigned, udigits) p.fmt.fmtInteger(v, 16, isSigned, verb, udigits)
case 'c': case 'c':
p.fmt.fmtC(v) p.fmt.fmtC(v)
case 'q': case 'q':
...@@ -483,7 +483,7 @@ func (p *pp) fmtBytes(v []byte, verb rune, typeString string) { ...@@ -483,7 +483,7 @@ func (p *pp) fmtBytes(v []byte, verb rune, typeString string) {
if i > 0 { if i > 0 {
p.buf.WriteByte(' ') p.buf.WriteByte(' ')
} }
p.fmt.fmtInteger(uint64(c), 10, unsigned, ldigits) p.fmt.fmtInteger(uint64(c), 10, unsigned, verb, ldigits)
} }
p.buf.WriteByte(']') p.buf.WriteByte(']')
} }
......
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