Commit a843b454 authored by Russ Cox's avatar Russ Cox

fmt: add verbs:

	%E - upper case %e
	%G - upper case %g
	%#v - Go syntax

R=r
DELTA=332  (238 added, 47 deleted, 47 changed)
OCL=34091
CL=34145
parent e5962971
...@@ -10,6 +10,7 @@ import ( ...@@ -10,6 +10,7 @@ import (
"math"; "math";
"strings"; "strings";
"testing"; "testing";
"unsafe";
) )
func TestFmtInterface(t *testing.T) { func TestFmtInterface(t *testing.T) {
...@@ -32,6 +33,15 @@ const b64 uint64 = 1<<64 - 1 ...@@ -32,6 +33,15 @@ const b64 uint64 = 1<<64 - 1
var array = []int{1, 2, 3, 4, 5} var array = []int{1, 2, 3, 4, 5}
var iarray = []interface{}{1, "hello", 2.5, nil} var iarray = []interface{}{1, "hello", 2.5, nil}
type A struct {
i int;
j uint;
s string;
x []int;
}
var b byte;
var fmttests = []fmtTest{ var fmttests = []fmtTest{
// basic string // basic string
fmtTest{ "%s", "abc", "abc" }, fmtTest{ "%s", "abc", "abc" },
...@@ -79,15 +89,9 @@ var fmttests = []fmtTest{ ...@@ -79,15 +89,9 @@ var fmttests = []fmtTest{
fmtTest{ "%+d", -12345, "-12345" }, fmtTest{ "%+d", -12345, "-12345" },
fmtTest{ "% d", 12345, " 12345" }, fmtTest{ "% d", 12345, " 12345" },
// arrays
fmtTest{ "%v", array, "[1 2 3 4 5]" },
fmtTest{ "%v", iarray, "[1 hello 2.5 <nil>]" },
fmtTest{ "%v", &array, "&[1 2 3 4 5]" },
fmtTest{ "%v", &iarray, "&[1 hello 2.5 <nil>]" },
// erroneous formats // erroneous formats
fmtTest{ "", 2, "?(extra int=2)" }, fmtTest{ "", 2, "?(extra int=2)" },
fmtTest{ "%d", "hello", "%d(string=hello)%" }, fmtTest{ "%d", "hello", "%d(string=hello)" },
// old test/fmt_test.go // old test/fmt_test.go
fmtTest{ "%d", 1234, "1234" }, fmtTest{ "%d", 1234, "1234" },
...@@ -123,6 +127,17 @@ var fmttests = []fmtTest{ ...@@ -123,6 +127,17 @@ var fmttests = []fmtTest{
fmtTest{ "%g", float64(-7), "-7" }, fmtTest{ "%g", float64(-7), "-7" },
fmtTest{ "%g", float64(-1e-9), "-1e-09", }, fmtTest{ "%g", float64(-1e-9), "-1e-09", },
fmtTest{ "%g", float32(-1e-9), "-1e-09" }, fmtTest{ "%g", float32(-1e-9), "-1e-09" },
fmtTest{ "%E", float64(1), "1.000000E+00" },
fmtTest{ "%E", float64(1234.5678e3), "1.234568E+06" },
fmtTest{ "%E", float64(1234.5678e-8), "1.234568E-05" },
fmtTest{ "%E", float64(-7), "-7.000000E+00" },
fmtTest{ "%E", float64(-1e-9), "-1.000000E-09" },
fmtTest{ "%G", float64(1234.5678e3), "1.2345678E+06" },
fmtTest{ "%G", float32(1234.5678e3), "1.2345678E+06" },
fmtTest{ "%G", float64(1234.5678e-8), "1.2345678E-05" },
fmtTest{ "%G", float64(-7), "-7" },
fmtTest{ "%G", float64(-1e-9), "-1E-09", },
fmtTest{ "%G", float32(-1e-9), "-1E-09" },
fmtTest{ "%c", 'x', "x" }, fmtTest{ "%c", 'x', "x" },
fmtTest{ "%c", 0xe4, "ä" }, fmtTest{ "%c", 0xe4, "ä" },
fmtTest{ "%c", 0x672c, "本" }, fmtTest{ "%c", 0x672c, "本" },
...@@ -158,11 +173,39 @@ var fmttests = []fmtTest{ ...@@ -158,11 +173,39 @@ var fmttests = []fmtTest{
fmtTest{ "%20e", math.Inf(1), " +Inf" }, fmtTest{ "%20e", math.Inf(1), " +Inf" },
fmtTest{ "%-20f", math.Inf(-1), "-Inf " }, fmtTest{ "%-20f", math.Inf(-1), "-Inf " },
fmtTest{ "%20g", math.NaN(), " NaN" }, fmtTest{ "%20g", math.NaN(), " NaN" },
// arrays
fmtTest{ "%v", array, "[1 2 3 4 5]" },
fmtTest{ "%v", iarray, "[1 hello 2.5 <nil>]" },
fmtTest{ "%v", &array, "&[1 2 3 4 5]" },
fmtTest{ "%v", &iarray, "&[1 hello 2.5 <nil>]" },
// structs
fmtTest{ "%v", A{1,2,"a",[]int{1,2}}, `{1 2 a [1 2]}` },
fmtTest{ "%+v", A{1,2,"a",[]int{1,2}}, `{i:1 j:2 s:a x:[1 2]}` },
// go syntax
fmtTest{ "%#v", A{1,2,"a",[]int{1,2}}, `fmt_test.A{i:1, j:0x2, s:"a", x:[]int{1, 2}}` },
fmtTest{ "%#v", &b, "(*uint8)(PTR)" },
fmtTest{ "%#v", TestFmtInterface, "(func(*testing.T))(PTR)" },
fmtTest{ "%#v", make(chan int), "(chan int)(PTR)" },
fmtTest{ "%#v", uint64(1<<64-1), "0xffffffffffffffff" },
fmtTest{ "%#v", 1000000000, "1000000000" },
} }
func TestSprintf(t *testing.T) { func TestSprintf(t *testing.T) {
for i, tt := range fmttests { for i, tt := range fmttests {
s := Sprintf(tt.fmt, tt.val); s := Sprintf(tt.fmt, tt.val);
if i := strings.Index(s, "0x"); i >= 0 && strings.Index(tt.out, "PTR") >= 0 {
j := i+2;
for ; j < len(s); j++ {
c := s[j];
if (c < '0' || c > '9') && (c < 'a' || c > 'f') {
break;
}
}
s = s[0:i] + "PTR" + s[j:len(s)];
}
if s != tt.out { if s != tt.out {
if ss, ok := tt.val.(string); ok { if ss, ok := tt.val.(string); ok {
// Don't requote the already-quoted strings. // Don't requote the already-quoted strings.
......
...@@ -465,6 +465,11 @@ func (f *Fmt) Fmt_e64(v float64) *Fmt { ...@@ -465,6 +465,11 @@ func (f *Fmt) Fmt_e64(v float64) *Fmt {
return fmtString(f, strconv.Ftoa64(v, 'e', doPrec(f, 6))); return fmtString(f, strconv.Ftoa64(v, 'e', doPrec(f, 6)));
} }
// Fmt_E64 formats a float64 in the form -1.23E+12.
func (f *Fmt) Fmt_E64(v float64) *Fmt {
return fmtString(f, strconv.Ftoa64(v, 'E', doPrec(f, 6)));
}
// Fmt_f64 formats a float64 in the form -1.23. // Fmt_f64 formats a float64 in the form -1.23.
func (f *Fmt) Fmt_f64(v float64) *Fmt { func (f *Fmt) Fmt_f64(v float64) *Fmt {
return fmtString(f, strconv.Ftoa64(v, 'f', doPrec(f, 6))); return fmtString(f, strconv.Ftoa64(v, 'f', doPrec(f, 6)));
...@@ -475,6 +480,11 @@ func (f *Fmt) Fmt_g64(v float64) *Fmt { ...@@ -475,6 +480,11 @@ func (f *Fmt) Fmt_g64(v float64) *Fmt {
return fmtString(f, strconv.Ftoa64(v, 'g', doPrec(f, -1))); return fmtString(f, strconv.Ftoa64(v, 'g', doPrec(f, -1)));
} }
// Fmt_g64 formats a float64 in the 'f' or 'E' form according to size.
func (f *Fmt) Fmt_G64(v float64) *Fmt {
return fmtString(f, strconv.Ftoa64(v, 'G', doPrec(f, -1)));
}
// Fmt_fb64 formats a float64 in the form -123p3 (exponent is power of 2). // Fmt_fb64 formats a float64 in the form -123p3 (exponent is power of 2).
func (f *Fmt) Fmt_fb64(v float64) *Fmt { func (f *Fmt) Fmt_fb64(v float64) *Fmt {
return fmtString(f, strconv.Ftoa64(v, 'b', 0)); return fmtString(f, strconv.Ftoa64(v, 'b', 0));
...@@ -489,6 +499,11 @@ func (f *Fmt) Fmt_e32(v float32) *Fmt { ...@@ -489,6 +499,11 @@ func (f *Fmt) Fmt_e32(v float32) *Fmt {
return fmtString(f, strconv.Ftoa32(v, 'e', doPrec(f, 6))); return fmtString(f, strconv.Ftoa32(v, 'e', doPrec(f, 6)));
} }
// Fmt_E32 formats a float32 in the form -1.23E+12.
func (f *Fmt) Fmt_E32(v float32) *Fmt {
return fmtString(f, strconv.Ftoa32(v, 'e', doPrec(f, 6)));
}
// Fmt_f32 formats a float32 in the form -1.23. // Fmt_f32 formats a float32 in the form -1.23.
func (f *Fmt) Fmt_f32(v float32) *Fmt { func (f *Fmt) Fmt_f32(v float32) *Fmt {
return fmtString(f, strconv.Ftoa32(v, 'f', doPrec(f, 6))); return fmtString(f, strconv.Ftoa32(v, 'f', doPrec(f, 6)));
...@@ -499,6 +514,11 @@ func (f *Fmt) Fmt_g32(v float32) *Fmt { ...@@ -499,6 +514,11 @@ func (f *Fmt) Fmt_g32(v float32) *Fmt {
return fmtString(f, strconv.Ftoa32(v, 'g', doPrec(f, -1))); return fmtString(f, strconv.Ftoa32(v, 'g', doPrec(f, -1)));
} }
// Fmt_G32 formats a float32 in the 'f' or 'E' form according to size.
func (f *Fmt) Fmt_G32(v float32) *Fmt {
return fmtString(f, strconv.Ftoa32(v, 'G', doPrec(f, -1)));
}
// Fmt_fb32 formats a float32 in the form -123p3 (exponent is power of 2). // Fmt_fb32 formats a float32 in the form -123p3 (exponent is power of 2).
func (f *Fmt) Fmt_fb32(v float32) *Fmt { func (f *Fmt) Fmt_fb32(v float32) *Fmt {
return fmtString(f, strconv.Ftoa32(v, 'b', 0)); return fmtString(f, strconv.Ftoa32(v, 'b', 0));
......
...@@ -10,8 +10,11 @@ ...@@ -10,8 +10,11 @@
The verbs: The verbs:
General: General:
%v for any operand type, the value in a default format. %v the value in a default format.
when printing structs, the plus flag (%+v) adds field names when printing structs, the plus flag (%+v) adds field names
%#v a Go-syntax representation of the value
%T a Go-syntax representation of the type of the value
Boolean: Boolean:
%t the word true or false %t the word true or false
Integer: Integer:
...@@ -23,16 +26,16 @@ ...@@ -23,16 +26,16 @@
%X base 16, with upper-case letters for A-F %X base 16, with upper-case letters for A-F
Floating-point: Floating-point:
%e scientific notation, e.g. -1234.456e+78 %e scientific notation, e.g. -1234.456e+78
%E scientific notation, e.g. -1234.456E+78
%f decimal point but no exponent, e.g. 123.456 %f decimal point but no exponent, e.g. 123.456
%g whichever of %e or %f produces more compact output %g whichever of %e or %f produces more compact output
%G whichever of %E or %f produces more compact output
String and slice of bytes: String and slice of bytes:
%s the uninterpreted bytes of the string or slice %s the uninterpreted bytes of the string or slice
%q a double-quoted string safely escaped with Go syntax %q a double-quoted string safely escaped with Go syntax
%x base 16 notation with two characters per byte %x base 16 notation with two characters per byte
Pointer: Pointer:
%p base 16 notation, with leading 0x %p base 16 notation, with leading 0x
Type:
%T a Go-syntax representation of the type of the operand
There is no 'u' flag. Integers are printed unsigned if they have unsigned type. There is no 'u' flag. Integers are printed unsigned if they have unsigned type.
Similarly, there is no need to specify the size of the operand (int8, int64). Similarly, there is no need to specify the size of the operand (int8, int64).
...@@ -95,21 +98,29 @@ type State interface { ...@@ -95,21 +98,29 @@ type State interface {
Flag(int) bool; Flag(int) bool;
} }
// Formatter is the interface implemented by objects with a custom formatter. // Formatter is the interface implemented by values with a custom formatter.
// The implementation of Format may call Sprintf or Fprintf(f) etc. // The implementation of Format may call Sprintf or Fprintf(f) etc.
// to generate its output. // to generate its output.
type Formatter interface { type Formatter interface {
Format(f State, c int); Format(f State, c int);
} }
// String represents any object being printed that has a String() method that // Stringer is implemented by any value that has a String method(),
// returns a string, which defines the ``native'' format for that object. // which defines the ``native'' format for that value.
// Any such object will be printed using that method if passed // The String method is used to print values passed as an operand
// as operand to a %s or %v format or to an unformatted printer such as Print. // to a %s or %v format or to an unformatted printer such as Print.
type Stringer interface { type Stringer interface {
String() string String() string
} }
// GoStringer is implemented by any value that has a GoString() method,
// which defines the Go syntax for that value.
// The GoString method is used to print values passed as an operand
// to a %#v format.
type GoStringer interface {
GoString() string
}
const runeSelf = utf8.RuneSelf const runeSelf = utf8.RuneSelf
const allocSize = 32 const allocSize = 32
...@@ -392,15 +403,28 @@ func parsenum(s string, start, end int) (n int, got bool, newi int) { ...@@ -392,15 +403,28 @@ func parsenum(s string, start, end int) (n int, got bool, newi int) {
return num, isnum, start; return num, isnum, start;
} }
func (p *pp) printField(field reflect.Value) (was_string bool) { type uintptrGetter interface {
Get() uintptr;
}
func (p *pp) printField(field reflect.Value, plus, sharp bool, depth int) (was_string bool) {
inter := field.Interface(); inter := field.Interface();
if inter != nil { if inter != nil {
switch {
default:
if stringer, ok := inter.(Stringer); ok { if stringer, ok := inter.(Stringer); ok {
p.addstr(stringer.String()); p.addstr(stringer.String());
return false; // this value is not a string return false; // this value is not a string
} }
case sharp:
if stringer, ok := inter.(GoStringer); ok {
p.addstr(stringer.GoString());
return false; // this value is not a string
}
}
} }
s := ""; s := "";
BigSwitch:
switch f := field.(type) { switch f := field.(type) {
case *reflect.BoolValue: case *reflect.BoolValue:
s = p.fmt.Fmt_boolean(f.Get()).Str(); s = p.fmt.Fmt_boolean(f.Get()).Str();
...@@ -415,80 +439,161 @@ func (p *pp) printField(field reflect.Value) (was_string bool) { ...@@ -415,80 +439,161 @@ func (p *pp) printField(field reflect.Value) (was_string bool) {
s = p.fmt.Fmt_g64(float64(f.Get())).Str(); s = p.fmt.Fmt_g64(float64(f.Get())).Str();
} }
case *reflect.StringValue: case *reflect.StringValue:
if sharp {
s = p.fmt.Fmt_q(f.Get()).Str();
} else {
s = p.fmt.Fmt_s(f.Get()).Str(); s = p.fmt.Fmt_s(f.Get()).Str();
was_string = true; was_string = true;
case *reflect.PtrValue:
v := f.Get();
if v == 0 {
s = "<nil>";
break;
}
// pointer to array?
if a, ok := f.Elem().(reflect.ArrayOrSliceValue); ok {
p.addstr("&");
p.printField(a);
break;
} }
p.fmt.sharp = !p.fmt.sharp; // turn 0x on by default
s = p.fmt.Fmt_ux64(uint64(v)).Str();
case reflect.ArrayOrSliceValue:
p.addstr("[");
for i := 0; i < f.Len(); i++ {
if i > 0 {
p.addstr(" ");
}
p.printField(f.Elem(i));
}
p.addstr("]");
case *reflect.MapValue: case *reflect.MapValue:
if sharp {
p.addstr(field.Type().String());
p.addstr("{");
} else {
p.addstr("map["); p.addstr("map[");
}
keys := f.Keys(); keys := f.Keys();
for i, key := range keys { for i, key := range keys {
if i > 0 { if i > 0 {
if sharp {
p.addstr(", ");
} else {
p.addstr(" "); p.addstr(" ");
} }
p.printField(key); }
p.printField(key, plus, sharp, depth+1);
p.addstr(":"); p.addstr(":");
p.printField(f.Elem(key)); p.printField(f.Elem(key), plus, sharp, depth+1);
} }
if sharp {
p.addstr("}");
} else {
p.addstr("]"); p.addstr("]");
}
case *reflect.StructValue: case *reflect.StructValue:
if sharp {
p.addstr(field.Type().String());
}
p.add('{'); p.add('{');
v := f; v := f;
t := v.Type().(*reflect.StructType); t := v.Type().(*reflect.StructType);
donames := p.fmt.plus;
p.fmt.clearflags(); // clear flags for p.printField p.fmt.clearflags(); // clear flags for p.printField
for i := 0; i < v.NumField(); i++ { for i := 0; i < v.NumField(); i++ {
if i > 0 { if i > 0 {
p.add(' ') if sharp {
p.addstr(", ");
} else {
p.addstr(" ");
} }
if donames { }
if plus || sharp {
if f := t.Field(i); f.Name != "" { if f := t.Field(i); f.Name != "" {
p.addstr(f.Name); p.addstr(f.Name);
p.add(':'); p.add(':');
} }
} }
p.printField(getField(v, i)); p.printField(getField(v, i), plus, sharp, depth+1);
} }
p.add('}'); p.addstr("}");
case *reflect.InterfaceValue: case *reflect.InterfaceValue:
value := f.Elem(); value := f.Elem();
if value == nil { if value == nil {
if sharp {
p.addstr(field.Type().String());
p.addstr("(nil)");
} else {
s = "<nil>" s = "<nil>"
}
} else { } else {
return p.printField(value); return p.printField(value, plus, sharp, depth+1);
}
case reflect.ArrayOrSliceValue:
if sharp {
p.addstr(field.Type().String());
p.addstr("{");
} else {
p.addstr("[");
}
for i := 0; i < f.Len(); i++ {
if i > 0 {
if sharp {
p.addstr(", ");
} else {
p.addstr(" ");
}
}
p.printField(f.Elem(i), plus, sharp, depth+1);
}
if sharp {
p.addstr("}");
} else {
p.addstr("]");
}
case *reflect.PtrValue:
v := f.Get();
// pointer to array or slice or struct? ok at top level
// but not embedded (avoid loops)
if v != 0 && depth == 0 {
switch a := f.Elem().(type) {
case reflect.ArrayOrSliceValue:
p.addstr("&");
p.printField(a, plus, sharp, depth+1);
break BigSwitch;
case *reflect.StructValue:
p.addstr("&");
p.printField(a, plus, sharp, depth+1);
break BigSwitch;
}
}
if sharp {
p.addstr("(");
p.addstr(field.Type().String());
p.addstr(")(");
if v == 0 {
p.addstr("nil");
} else {
p.fmt.sharp = true;
p.addstr(p.fmt.Fmt_ux64(uint64(v)).Str());
}
p.addstr(")");
break;
}
if v == 0 {
s = "<nil>";
break;
}
p.fmt.sharp = true; // turn 0x on
s = p.fmt.Fmt_ux64(uint64(v)).Str();
case uintptrGetter:
v := f.Get();
if sharp {
p.addstr("(");
p.addstr(field.Type().String());
p.addstr(")(");
if v == 0 {
p.addstr("nil");
} else {
p.fmt.sharp = true;
p.addstr(p.fmt.Fmt_ux64(uint64(v)).Str());
}
p.addstr(")");
} else {
p.fmt.sharp = true; // turn 0x on
p.addstr(p.fmt.Fmt_ux64(uint64(f.Get())).Str());
} }
case *reflect.UintptrValue:
p.fmt.sharp = !p.fmt.sharp; // turn 0x on by default
s = p.fmt.Fmt_ux64(uint64(f.Get())).Str();
default: default:
v, signed, ok := getInt(field); v, signed, ok := getInt(field);
if ok { if ok {
if signed { if signed {
s = p.fmt.Fmt_d64(v).Str(); s = p.fmt.Fmt_d64(v).Str();
} else {
if sharp {
p.fmt.sharp = true; // turn on 0x
s = p.fmt.Fmt_ux64(uint64(v)).Str();
} else { } else {
s = p.fmt.Fmt_ud64(uint64(v)).Str(); s = p.fmt.Fmt_ud64(uint64(v)).Str();
} }
}
break; break;
} }
s = "?" + field.Type().String() + "?"; s = "?" + field.Type().String() + "?";
...@@ -548,13 +653,17 @@ func (p *pp) doprintf(format string, v *reflect.StructValue) { ...@@ -548,13 +653,17 @@ func (p *pp) doprintf(format string, v *reflect.StructValue) {
} }
field := getField(v, fieldnum); field := getField(v, fieldnum);
fieldnum++; fieldnum++;
// Try formatter except for %T,
// which is special and handled internally.
inter := field.Interface(); inter := field.Interface();
if inter != nil && c != 'T' { // don't want thing to describe itself if we're asking for its type if inter != nil && c != 'T' {
if formatter, ok := inter.(Formatter); ok { if formatter, ok := inter.(Formatter); ok {
formatter.Format(p, c); formatter.Format(p, c);
continue; continue;
} }
} }
s := ""; s := "";
switch c { switch c {
// bool // bool
...@@ -640,6 +749,14 @@ func (p *pp) doprintf(format string, v *reflect.StructValue) { ...@@ -640,6 +749,14 @@ func (p *pp) doprintf(format string, v *reflect.StructValue) {
} else { } else {
goto badtype goto badtype
} }
case 'E':
if v, ok := getFloat32(field); ok {
s = p.fmt.Fmt_E32(v).Str()
} else if v, ok := getFloat64(field); ok {
s = p.fmt.Fmt_E64(v).Str()
} else {
goto badtype
}
case 'f': case 'f':
if v, ok := getFloat32(field); ok { if v, ok := getFloat32(field); ok {
s = p.fmt.Fmt_f32(v).Str() s = p.fmt.Fmt_f32(v).Str()
...@@ -656,6 +773,14 @@ func (p *pp) doprintf(format string, v *reflect.StructValue) { ...@@ -656,6 +773,14 @@ func (p *pp) doprintf(format string, v *reflect.StructValue) {
} else { } else {
goto badtype goto badtype
} }
case 'G':
if v, ok := getFloat32(field); ok {
s = p.fmt.Fmt_G32(v).Str()
} else if v, ok := getFloat64(field); ok {
s = p.fmt.Fmt_G64(v).Str()
} else {
goto badtype
}
// string // string
case 's': case 's':
...@@ -692,7 +817,10 @@ func (p *pp) doprintf(format string, v *reflect.StructValue) { ...@@ -692,7 +817,10 @@ func (p *pp) doprintf(format string, v *reflect.StructValue) {
// arbitrary value; do your best // arbitrary value; do your best
case 'v': case 'v':
p.printField(field); plus, sharp := p.fmt.plus, p.fmt.sharp;
p.fmt.plus = false;
p.fmt.sharp = false;
p.printField(field, plus, sharp, 0);
// the value's type // the value's type
case 'T': case 'T':
...@@ -702,8 +830,8 @@ func (p *pp) doprintf(format string, v *reflect.StructValue) { ...@@ -702,8 +830,8 @@ func (p *pp) doprintf(format string, v *reflect.StructValue) {
badtype: badtype:
s = "%" + string(c) + "(" + field.Type().String() + "="; s = "%" + string(c) + "(" + field.Type().String() + "=";
p.addstr(s); p.addstr(s);
p.printField(field); p.printField(field, false, false, 0);
s= ")%"; s = ")";
} }
p.addstr(s); p.addstr(s);
} }
...@@ -713,7 +841,7 @@ func (p *pp) doprintf(format string, v *reflect.StructValue) { ...@@ -713,7 +841,7 @@ func (p *pp) doprintf(format string, v *reflect.StructValue) {
field := getField(v, fieldnum); field := getField(v, fieldnum);
p.addstr(field.Type().String()); p.addstr(field.Type().String());
p.addstr("="); p.addstr("=");
p.printField(field); p.printField(field, false, false, 0);
if fieldnum + 1 < v.NumField() { if fieldnum + 1 < v.NumField() {
p.addstr(", "); p.addstr(", ");
} }
...@@ -733,7 +861,7 @@ func (p *pp) doprint(v *reflect.StructValue, addspace, addnewline bool) { ...@@ -733,7 +861,7 @@ func (p *pp) doprint(v *reflect.StructValue, addspace, addnewline bool) {
p.add(' '); p.add(' ');
} }
} }
prev_string = p.printField(field); prev_string = p.printField(field, false, false, 0);
} }
if addnewline { if addnewline {
p.add('\n') p.add('\n')
......
...@@ -115,20 +115,20 @@ func genericFtoa(bits uint64, fmt byte, prec int, flt *floatInfo) string { ...@@ -115,20 +115,20 @@ func genericFtoa(bits uint64, fmt byte, prec int, flt *floatInfo) string {
shortest = true; shortest = true;
roundShortest(d, mant, exp, flt); roundShortest(d, mant, exp, flt);
switch fmt { switch fmt {
case 'e': case 'e', 'E':
prec = d.nd - 1; prec = d.nd - 1;
case 'f': case 'f':
prec = max(d.nd - d.dp, 0); prec = max(d.nd - d.dp, 0);
case 'g': case 'g', 'G':
prec = d.nd; prec = d.nd;
} }
} else { } else {
switch fmt { switch fmt {
case 'e': case 'e', 'E':
d.Round(prec+1); d.Round(prec+1);
case 'f': case 'f':
d.Round(d.dp+prec); d.Round(d.dp+prec);
case 'g': case 'g', 'G':
if prec == 0 { if prec == 0 {
prec = 1; prec = 1;
} }
...@@ -137,11 +137,11 @@ func genericFtoa(bits uint64, fmt byte, prec int, flt *floatInfo) string { ...@@ -137,11 +137,11 @@ func genericFtoa(bits uint64, fmt byte, prec int, flt *floatInfo) string {
} }
switch fmt { switch fmt {
case 'e': case 'e', 'E':
return fmtE(neg, d, prec); return fmtE(neg, d, prec, fmt);
case 'f': case 'f':
return fmtF(neg, d, prec); return fmtF(neg, d, prec);
case 'g': case 'g', 'G':
// trailing zeros are removed. // trailing zeros are removed.
if prec > d.nd { if prec > d.nd {
prec = d.nd; prec = d.nd;
...@@ -155,7 +155,7 @@ func genericFtoa(bits uint64, fmt byte, prec int, flt *floatInfo) string { ...@@ -155,7 +155,7 @@ func genericFtoa(bits uint64, fmt byte, prec int, flt *floatInfo) string {
} }
exp := d.dp - 1; exp := d.dp - 1;
if exp < -4 || exp >= eprec { if exp < -4 || exp >= eprec {
return fmtE(neg, d, prec - 1); return fmtE(neg, d, prec - 1, fmt + 'e' - 'g');
} }
return fmtF(neg, d, max(prec - d.dp, 0)); return fmtF(neg, d, max(prec - d.dp, 0));
} }
...@@ -251,7 +251,7 @@ func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) { ...@@ -251,7 +251,7 @@ func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) {
} }
// %e: -d.ddddde±dd // %e: -d.ddddde±dd
func fmtE(neg bool, d *decimal, prec int) string { func fmtE(neg bool, d *decimal, prec int, fmt byte) string {
buf := make([]byte, 3+max(prec, 0)+30); // "-0." + prec digits + exp buf := make([]byte, 3+max(prec, 0)+30); // "-0." + prec digits + exp
w := 0; // write index w := 0; // write index
...@@ -284,7 +284,7 @@ func fmtE(neg bool, d *decimal, prec int) string { ...@@ -284,7 +284,7 @@ func fmtE(neg bool, d *decimal, prec int) string {
} }
// e± // e±
buf[w] = 'e'; buf[w] = fmt;
w++; w++;
exp := d.dp - 1; exp := d.dp - 1;
if d.nd == 0 { // special case: 0 has exponent 0 if d.nd == 0 { // special case: 0 has exponent 0
......
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