From: Rob Pike Date: Thu, 13 Nov 2008 23:20:52 +0000 (-0800) Subject: add a %v format to print an arbitrary value in its "println" form. X-Git-Tag: weekly.2009-11-06~2732 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=e2621b80374f74f07cd7e7c9265e2d20b242bdae;p=gostls13.git add a %v format to print an arbitrary value in its "println" form. also add code to print (pointers to) arrays, through %v. R=rsc DELTA=108 (70 added, 33 deleted, 5 changed) OCL=19184 CL=19192 --- diff --git a/src/lib/fmt/print.go b/src/lib/fmt/print.go index 361dfc5a2a..4bc3790f5e 100644 --- a/src/lib/fmt/print.go +++ b/src/lib/fmt/print.go @@ -255,6 +255,16 @@ func getPtr(v reflect.Value) (val uint64, ok bool) { return 0, false; } +func getArrayPtr(v reflect.Value) (val reflect.ArrayValue, ok bool) { + if v.Kind() == reflect.PtrKind { + v = v.(reflect.PtrValue).Sub(); + if v.Kind() == reflect.ArrayKind { + return v.(reflect.ArrayValue), true; + } + } + return nil, false; +} + // Convert ASCII to integer. n is 0 (and got is false) if no number present. func parsenum(s string, start, end int) (n int, got bool, newi int) { @@ -277,6 +287,56 @@ func parsenum(s string, start, end int) (n int, got bool, newi int) { return num, isnum, start; } +func (p *P) printField(field reflect.Value) (was_string bool) { + if stringer, ok := field.Interface().(String); ok { + p.addstr(stringer.String()); + return false; // this value is not a string + } + s := ""; + switch field.Kind() { + case reflect.BoolKind: + s = p.fmt.boolean(field.(reflect.BoolValue).Get()).str(); + case reflect.IntKind, reflect.Int8Kind, reflect.Int16Kind, reflect.Int32Kind, reflect.Int64Kind: + v, signed, ok := getInt(field); + s = p.fmt.d64(v).str(); + case reflect.UintKind, reflect.Uint8Kind, reflect.Uint16Kind, reflect.Uint32Kind, reflect.Uint64Kind: + v, signed, ok := getInt(field); + s = p.fmt.ud64(uint64(v)).str(); + case reflect.FloatKind, reflect.Float32Kind, reflect.Float64Kind, reflect.Float80Kind: + v, ok := getFloat(field); + s = p.fmt.g64(v).str(); + case reflect.StringKind: + v, ok := getString(field); + s = p.fmt.s(v).str(); + was_string = true; + case reflect.PtrKind: + // pointer to array? + if v, ok := getArrayPtr(field); ok { + p.addstr("&["); + for i := 0; i < v.Len(); i++ { + if i > 0 { + p.addstr(" "); + } + p.printField(v.Elem(i)); + } + p.addstr("]"); + break; + } + v, ok := getPtr(field); + p.add('0'); + p.add('x'); + s = p.fmt.uX64(v).str(); + case reflect.StructKind: + p.add('{'); + p.doprint(field, true, false); + p.add('}'); + default: + s = "?" + field.Type().String() + "?"; + } + p.addstr(s); + return was_string; +} + func (p *P) doprintf(format string, v reflect.StructValue) { p.ensure(len(format)); // a good starting size end := len(format) - 1; @@ -310,9 +370,11 @@ func (p *P) doprintf(format string, v reflect.StructValue) { } field := v.Field(fieldnum); fieldnum++; - if formatter, ok := field.Interface().(Format); ok { - formatter.Format(p, c); - continue; + if c != 'T' { // don't want thing to describe itself if we're asking for its type + if formatter, ok := field.Interface().(Format); ok { + formatter.Format(p, c); + continue; + } } s := ""; if p.wid_ok { @@ -414,6 +476,14 @@ func (p *P) doprintf(format string, v reflect.StructValue) { goto badtype } + // arbitrary value; do your best + case 'v': + p.printField(field); + + // the value's type + case 'T': + s = field.Type().String(); + default: badtype: s = "%" + string(c) + "(" + field.Type().String() + ")%"; @@ -437,7 +507,6 @@ func (p *P) doprint(v reflect.StructValue, addspace, addnewline bool) { for fieldnum := 0; fieldnum < v.Len(); fieldnum++ { // always add spaces if we're doing println field := v.Field(fieldnum); - s := ""; if fieldnum > 0 { if addspace { p.add(' ') @@ -446,40 +515,8 @@ func (p *P) doprint(v reflect.StructValue, addspace, addnewline bool) { p.add(' ') } } - if stringer, ok := field.Interface().(String); ok { - p.addstr(stringer.String()); - prev_string = false; // this value is not a string - continue; - } - switch field.Kind() { - case reflect.BoolKind: - s = p.fmt.boolean(field.(reflect.BoolValue).Get()).str(); - case reflect.IntKind, reflect.Int8Kind, reflect.Int16Kind, reflect.Int32Kind, reflect.Int64Kind: - v, signed, ok := getInt(field); - s = p.fmt.d64(v).str(); - case reflect.UintKind, reflect.Uint8Kind, reflect.Uint16Kind, reflect.Uint32Kind, reflect.Uint64Kind: - v, signed, ok := getInt(field); - s = p.fmt.ud64(uint64(v)).str(); - case reflect.FloatKind, reflect.Float32Kind, reflect.Float64Kind, reflect.Float80Kind: - v, ok := getFloat(field); - s = p.fmt.g64(v).str(); - case reflect.StringKind: - v, ok := getString(field); - s = p.fmt.s(v).str(); - case reflect.PtrKind: - v, ok := getPtr(field); - p.add('0'); - p.add('x'); - s = p.fmt.uX64(v).str(); - case reflect.StructKind: - p.add('{'); - p.doprint(field, true, false); - p.add('}'); - default: - s = "?" + field.Type().String() + "?"; - } - p.addstr(s); - prev_string = field.Kind() == reflect.StringKind; + was_string := p.printField(field); + prev_string = was_string; } if addnewline { p.add('\n')