blob: 6fa747c29c54a09233219c6cfcebbcfbef04c0c1 [file] [log] [blame]
Rob Pike418b97c2008-10-24 16:33:29 -07001// Copyright 2009 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
Rob Pikeb6ce2a72009-06-22 18:09:40 -07005/*
6 Package fmt implements formatted I/O with functions analogous
7 to C's printf. The format 'verbs' are derived from C's but
8 are simpler.
9
10 The verbs:
11
12 General:
Russ Coxa843b452009-08-31 16:38:30 -070013 %v the value in a default format.
Rob Pikeb6ce2a72009-06-22 18:09:40 -070014 when printing structs, the plus flag (%+v) adds field names
Russ Coxa843b452009-08-31 16:38:30 -070015 %#v a Go-syntax representation of the value
16 %T a Go-syntax representation of the type of the value
17
Rob Pikeb6ce2a72009-06-22 18:09:40 -070018 Boolean:
19 %t the word true or false
20 Integer:
21 %b base 2
22 %c the character represented by the corresponding Unicode code point
23 %d base 10
24 %o base 8
25 %x base 16, with lower-case letters for a-f
26 %X base 16, with upper-case letters for A-F
27 Floating-point:
28 %e scientific notation, e.g. -1234.456e+78
Russ Coxa843b452009-08-31 16:38:30 -070029 %E scientific notation, e.g. -1234.456E+78
Rob Pikeb6ce2a72009-06-22 18:09:40 -070030 %f decimal point but no exponent, e.g. 123.456
31 %g whichever of %e or %f produces more compact output
Russ Coxa843b452009-08-31 16:38:30 -070032 %G whichever of %E or %f produces more compact output
Rob Pikeb6ce2a72009-06-22 18:09:40 -070033 String and slice of bytes:
34 %s the uninterpreted bytes of the string or slice
35 %q a double-quoted string safely escaped with Go syntax
36 %x base 16 notation with two characters per byte
37 Pointer:
38 %p base 16 notation, with leading 0x
Rob Pikeb6ce2a72009-06-22 18:09:40 -070039
40 There is no 'u' flag. Integers are printed unsigned if they have unsigned type.
41 Similarly, there is no need to specify the size of the operand (int8, int64).
42
43 For numeric values, the width and precision flags control
44 formatting; width sets the width of the field, precision the
45 number of places after the decimal, if appropriate. The
46 format %6.2f prints 123.45.
47
48 Other flags:
49 + always print a sign for numeric values
50 - pad with spaces on the right rather than the left (left-justify the field)
51 # alternate format: add leading 0 for octal (%#o), 0x for hex (%#x);
52 suppress 0x for %p (%#p);
53 print a raw (backquoted) string if possible for %q (%#q)
54 ' ' (space) leave a space for elided sign in numbers (% d);
55 put spaces between bytes printing strings or slices in hex (% x)
56 0 pad with leading zeros rather than spaces
57
58 For each Printf-like function, there is also a Print function
59 that takes no format and is equivalent to saying %v for every
60 operand. Another variant Println inserts blanks between
61 operands and appends a newline.
62
Russ Cox0d400a72009-07-07 11:03:31 -070063 Regardless of the verb, if an operand is an interface value,
64 the internal concrete value is used, not the interface itself.
65 Thus:
66 var i interface{} = 23;
67 fmt.Printf("%v\n", i);
68 will print 23.
69
Rob Pike07a497f2009-07-30 16:57:46 -070070 If an operand implements interface Formatter, that interface
Rob Pikeb6ce2a72009-06-22 18:09:40 -070071 can be used for fine control of formatting.
72
73 If an operand implements method String() string that method
74 will be used for %v, %s, or Print etc.
75*/
Rob Pike418b97c2008-10-24 16:33:29 -070076package fmt
77
Rob Pikedb25e782008-10-26 08:27:50 -070078
Rob Pike418b97c2008-10-24 16:33:29 -070079import (
Rob Pike4c0e51c2009-12-06 12:03:52 -080080 "bytes";
Rob Pike23553952008-11-14 10:42:45 -080081 "io";
Rob Pike418b97c2008-10-24 16:33:29 -070082 "os";
Russ Cox1f6463f2009-04-16 20:52:37 -070083 "reflect";
Russ Cox36096242009-01-16 14:58:14 -080084 "utf8";
Rob Pike418b97c2008-10-24 16:33:29 -070085)
86
Rob Pike4c0e51c2009-12-06 12:03:52 -080087// Some constants in the form of bytes, to avoid string overhead.
88// Needlessly fastidious, I suppose.
89var (
90 trueBytes = []byte{'t', 'r', 'u', 'e'};
91 falseBytes = []byte{'f', 'a', 'l', 's', 'e'};
92 commaSpaceBytes = []byte{',', ' '};
93 nilAngleBytes = []byte{'<', 'n', 'i', 'l', '>'};
94 nilParenBytes = []byte{'(', 'n', 'i', 'l', ')'};
95 nilBytes = []byte{'n', 'i', 'l'};
96 mapBytes = []byte{'m', 'a', 'p', '['};
97 missingBytes = []byte{'m', 'i', 's', 's', 'i', 'n', 'g'};
98 extraBytes = []byte{'?', '(', 'e', 'x', 't', 'r', 'a', ' '};
99)
100
Rob Pike28ba9772009-06-23 15:20:30 -0700101// State represents the printer state passed to custom formatters.
Rob Pikec8b47c62009-05-08 11:22:57 -0700102// It provides access to the io.Writer interface plus information about
Rob Pike85647c92009-03-06 03:35:38 -0800103// the flags and options for the operand's format specifier.
Rob Pike28ba9772009-06-23 15:20:30 -0700104type State interface {
Rob Pike85647c92009-03-06 03:35:38 -0800105 // Write is the function to call to emit formatted output to be printed.
Rob Pikeaaf63f82009-04-17 00:08:24 -0700106 Write(b []byte) (ret int, err os.Error);
Rob Pike85647c92009-03-06 03:35:38 -0800107 // Width returns the value of the width option and whether it has been set.
Russ Coxecb863a2009-10-06 15:38:57 -0700108 Width() (wid int, ok bool);
Rob Pike85647c92009-03-06 03:35:38 -0800109 // Precision returns the value of the precision option and whether it has been set.
Russ Coxecb863a2009-10-06 15:38:57 -0700110 Precision() (prec int, ok bool);
Russ Coxbf67afc2008-12-11 16:53:33 -0800111
Rob Pike85647c92009-03-06 03:35:38 -0800112 // Flag returns whether the flag c, a character, has been set.
Russ Coxecb863a2009-10-06 15:38:57 -0700113 Flag(int) bool;
Rob Pikef15dfa72008-11-06 10:40:57 -0800114}
115
Russ Coxa843b452009-08-31 16:38:30 -0700116// Formatter is the interface implemented by values with a custom formatter.
Rob Pike85647c92009-03-06 03:35:38 -0800117// The implementation of Format may call Sprintf or Fprintf(f) etc.
118// to generate its output.
Rob Pike28ba9772009-06-23 15:20:30 -0700119type Formatter interface {
120 Format(f State, c int);
Rob Pike91212bd2008-11-06 11:38:44 -0800121}
122
Russ Coxa843b452009-08-31 16:38:30 -0700123// Stringer is implemented by any value that has a String method(),
124// which defines the ``native'' format for that value.
125// The String method is used to print values passed as an operand
126// to a %s or %v format or to an unformatted printer such as Print.
Rob Pikec8b47c62009-05-08 11:22:57 -0700127type Stringer interface {
Russ Coxecb863a2009-10-06 15:38:57 -0700128 String() string;
Rob Pikef15dfa72008-11-06 10:40:57 -0800129}
130
Russ Coxa843b452009-08-31 16:38:30 -0700131// GoStringer is implemented by any value that has a GoString() method,
132// which defines the Go syntax for that value.
133// The GoString method is used to print values passed as an operand
134// to a %#v format.
135type GoStringer interface {
Russ Coxecb863a2009-10-06 15:38:57 -0700136 GoString() string;
Russ Coxa843b452009-08-31 16:38:30 -0700137}
138
Rob Pike497bb9c2009-01-15 15:40:27 -0800139const allocSize = 32
Rob Pike418b97c2008-10-24 16:33:29 -0700140
Rob Pike497bb9c2009-01-15 15:40:27 -0800141type pp struct {
Rob Pike418b97c2008-10-24 16:33:29 -0700142 n int;
Rob Pike4c0e51c2009-12-06 12:03:52 -0800143 buf bytes.Buffer;
144 runeBuf [utf8.UTFMax]byte;
Rob Pike353ef802009-12-06 12:58:16 -0800145 fmt fmt;
Rob Pike418b97c2008-10-24 16:33:29 -0700146}
147
Rob Pike4c0e51c2009-12-06 12:03:52 -0800148// A leaky bucket of reusable pp structures.
149var ppFree = make(chan *pp, 100)
150
Rob Pikef91cd442009-12-06 15:01:07 -0800151// Allocate a new pp struct. Probably can grab the previous one from ppFree.
Rob Pikedb1656f2009-01-16 13:29:43 -0800152func newPrinter() *pp {
Rob Pike4c0e51c2009-12-06 12:03:52 -0800153 p, ok := <-ppFree;
154 if !ok {
155 p = new(pp)
156 }
Rob Pike353ef802009-12-06 12:58:16 -0800157 p.fmt.init(&p.buf);
Rob Pike418b97c2008-10-24 16:33:29 -0700158 return p;
159}
160
Rob Pikef91cd442009-12-06 15:01:07 -0800161// Save used pp structs in ppFree; avoids an allocation per invocation.
162func (p *pp) free() {
163 // Don't hold on to pp structs with large buffers.
164 if cap(p.buf.Bytes()) > 1024 {
165 return
166 }
167 p.buf.Reset();
168 _ = ppFree <- p;
169}
Rob Pikef15dfa72008-11-06 10:40:57 -0800170
Rob Pike4c0e51c2009-12-06 12:03:52 -0800171func (p *pp) Width() (wid int, ok bool) { return p.fmt.wid, p.fmt.widPresent }
172
173func (p *pp) Precision() (prec int, ok bool) { return p.fmt.prec, p.fmt.precPresent }
Russ Coxbf67afc2008-12-11 16:53:33 -0800174
Rob Pike497bb9c2009-01-15 15:40:27 -0800175func (p *pp) Flag(b int) bool {
Russ Coxbf67afc2008-12-11 16:53:33 -0800176 switch b {
177 case '-':
Robert Griesemer40621d52009-11-09 12:07:39 -0800178 return p.fmt.minus
Russ Coxbf67afc2008-12-11 16:53:33 -0800179 case '+':
Robert Griesemer40621d52009-11-09 12:07:39 -0800180 return p.fmt.plus
Russ Coxbf67afc2008-12-11 16:53:33 -0800181 case '#':
Robert Griesemer40621d52009-11-09 12:07:39 -0800182 return p.fmt.sharp
Russ Coxbf67afc2008-12-11 16:53:33 -0800183 case ' ':
Robert Griesemer40621d52009-11-09 12:07:39 -0800184 return p.fmt.space
Russ Coxbf67afc2008-12-11 16:53:33 -0800185 case '0':
Robert Griesemer40621d52009-11-09 12:07:39 -0800186 return p.fmt.zero
Russ Coxbf67afc2008-12-11 16:53:33 -0800187 }
Russ Coxecb863a2009-10-06 15:38:57 -0700188 return false;
Rob Pikef15dfa72008-11-06 10:40:57 -0800189}
190
Rob Pike497bb9c2009-01-15 15:40:27 -0800191func (p *pp) add(c int) {
Rob Pikef91cd442009-12-06 15:01:07 -0800192 if c < utf8.RuneSelf {
Rob Pike4c0e51c2009-12-06 12:03:52 -0800193 p.buf.WriteByte(byte(c))
Rob Pike418b97c2008-10-24 16:33:29 -0700194 } else {
Rob Pike4c0e51c2009-12-06 12:03:52 -0800195 w := utf8.EncodeRune(c, &p.runeBuf);
196 p.buf.Write(p.runeBuf[0:w]);
Rob Pike418b97c2008-10-24 16:33:29 -0700197 }
198}
199
Rob Pike4c0e51c2009-12-06 12:03:52 -0800200// Implement Write so we can call Fprintf on a pp (through State), for
Rob Pike3200b062008-11-04 13:57:21 -0800201// recursive use in custom verbs.
Rob Pikeaaf63f82009-04-17 00:08:24 -0700202func (p *pp) Write(b []byte) (ret int, err os.Error) {
Rob Pike4c0e51c2009-12-06 12:03:52 -0800203 return p.buf.Write(b)
Rob Pike418b97c2008-10-24 16:33:29 -0700204}
205
Rob Pike418b97c2008-10-24 16:33:29 -0700206// These routines end in 'f' and take a format string.
207
Rob Pike85647c92009-03-06 03:35:38 -0800208// Fprintf formats according to a format specifier and writes to w.
Rob Pikec8b47c62009-05-08 11:22:57 -0700209func Fprintf(w io.Writer, format string, a ...) (n int, error os.Error) {
Russ Cox0d400a72009-07-07 11:03:31 -0700210 v := reflect.NewValue(a).(*reflect.StructValue);
Rob Pikedb1656f2009-01-16 13:29:43 -0800211 p := newPrinter();
Rob Pike418b97c2008-10-24 16:33:29 -0700212 p.doprintf(format, v);
Rob Pike4c0e51c2009-12-06 12:03:52 -0800213 n64, error := p.buf.WriteTo(w);
214 p.free();
215 return int(n64), error;
Rob Pike418b97c2008-10-24 16:33:29 -0700216}
217
Rob Pike85647c92009-03-06 03:35:38 -0800218// Printf formats according to a format specifier and writes to standard output.
Rob Pikeaaf63f82009-04-17 00:08:24 -0700219func Printf(format string, v ...) (n int, errno os.Error) {
Rob Pike61f33022009-01-15 13:48:11 -0800220 n, errno = Fprintf(os.Stdout, format, v);
Rob Pike418b97c2008-10-24 16:33:29 -0700221 return n, errno;
222}
223
Rob Pike85647c92009-03-06 03:35:38 -0800224// Sprintf formats according to a format specifier and returns the resulting string.
Russ Cox839a6842009-01-20 14:40:40 -0800225func Sprintf(format string, a ...) string {
Russ Cox0d400a72009-07-07 11:03:31 -0700226 v := reflect.NewValue(a).(*reflect.StructValue);
Rob Pikedb1656f2009-01-16 13:29:43 -0800227 p := newPrinter();
Robert Griesemer3a2c0a92008-11-06 11:56:08 -0800228 p.doprintf(format, v);
Rob Pike4c0e51c2009-12-06 12:03:52 -0800229 s := p.buf.String();
230 p.free();
Rob Pike418b97c2008-10-24 16:33:29 -0700231 return s;
232}
233
Rob Pike85647c92009-03-06 03:35:38 -0800234// These routines do not take a format string
Rob Pike418b97c2008-10-24 16:33:29 -0700235
Rob Pike85647c92009-03-06 03:35:38 -0800236// Fprint formats using the default formats for its operands and writes to w.
237// Spaces are added between operands when neither is a string.
Rob Pikec8b47c62009-05-08 11:22:57 -0700238func Fprint(w io.Writer, a ...) (n int, error os.Error) {
Russ Cox0d400a72009-07-07 11:03:31 -0700239 v := reflect.NewValue(a).(*reflect.StructValue);
Rob Pikedb1656f2009-01-16 13:29:43 -0800240 p := newPrinter();
Rob Pike2d4f7ba2008-11-02 12:33:02 -0800241 p.doprint(v, false, false);
Rob Pike4c0e51c2009-12-06 12:03:52 -0800242 n64, error := p.buf.WriteTo(w);
243 p.free();
244 return int(n64), error;
Rob Pike418b97c2008-10-24 16:33:29 -0700245}
246
Rob Pike85647c92009-03-06 03:35:38 -0800247// Print formats using the default formats for its operands and writes to standard output.
248// Spaces are added between operands when neither is a string.
Rob Pikeaaf63f82009-04-17 00:08:24 -0700249func Print(v ...) (n int, errno os.Error) {
Rob Pike61f33022009-01-15 13:48:11 -0800250 n, errno = Fprint(os.Stdout, v);
Rob Pike418b97c2008-10-24 16:33:29 -0700251 return n, errno;
252}
253
Rob Pike85647c92009-03-06 03:35:38 -0800254// Sprint formats using the default formats for its operands and returns the resulting string.
255// Spaces are added between operands when neither is a string.
Russ Cox839a6842009-01-20 14:40:40 -0800256func Sprint(a ...) string {
Russ Cox0d400a72009-07-07 11:03:31 -0700257 v := reflect.NewValue(a).(*reflect.StructValue);
Rob Pikedb1656f2009-01-16 13:29:43 -0800258 p := newPrinter();
Robert Griesemer3a2c0a92008-11-06 11:56:08 -0800259 p.doprint(v, false, false);
Rob Pikef91cd442009-12-06 15:01:07 -0800260 s := p.buf.String();
Rob Pike4c0e51c2009-12-06 12:03:52 -0800261 p.free();
Rob Pikef91cd442009-12-06 15:01:07 -0800262 return s;
Rob Pike418b97c2008-10-24 16:33:29 -0700263}
264
265// These routines end in 'ln', do not take a format string,
266// always add spaces between operands, and add a newline
267// after the last operand.
268
Rob Pike85647c92009-03-06 03:35:38 -0800269// Fprintln formats using the default formats for its operands and writes to w.
270// Spaces are always added between operands and a newline is appended.
Rob Pikec8b47c62009-05-08 11:22:57 -0700271func Fprintln(w io.Writer, a ...) (n int, error os.Error) {
Russ Cox0d400a72009-07-07 11:03:31 -0700272 v := reflect.NewValue(a).(*reflect.StructValue);
Rob Pikedb1656f2009-01-16 13:29:43 -0800273 p := newPrinter();
Rob Pike2d4f7ba2008-11-02 12:33:02 -0800274 p.doprint(v, true, true);
Rob Pike4c0e51c2009-12-06 12:03:52 -0800275 n64, error := p.buf.WriteTo(w);
276 p.free();
277 return int(n64), error;
Rob Pike418b97c2008-10-24 16:33:29 -0700278}
279
Rob Pike85647c92009-03-06 03:35:38 -0800280// Println formats using the default formats for its operands and writes to standard output.
281// Spaces are always added between operands and a newline is appended.
Rob Pikeaaf63f82009-04-17 00:08:24 -0700282func Println(v ...) (n int, errno os.Error) {
Rob Pike61f33022009-01-15 13:48:11 -0800283 n, errno = Fprintln(os.Stdout, v);
Rob Pike418b97c2008-10-24 16:33:29 -0700284 return n, errno;
285}
286
Rob Pike85647c92009-03-06 03:35:38 -0800287// Sprintln formats using the default formats for its operands and returns the resulting string.
288// Spaces are always added between operands and a newline is appended.
Russ Cox839a6842009-01-20 14:40:40 -0800289func Sprintln(a ...) string {
Russ Cox0d400a72009-07-07 11:03:31 -0700290 v := reflect.NewValue(a).(*reflect.StructValue);
Rob Pikedb1656f2009-01-16 13:29:43 -0800291 p := newPrinter();
Robert Griesemer3a2c0a92008-11-06 11:56:08 -0800292 p.doprint(v, true, true);
Rob Pike4c0e51c2009-12-06 12:03:52 -0800293 s := p.buf.String();
294 p.free();
Rob Pike418b97c2008-10-24 16:33:29 -0700295 return s;
296}
297
Russ Cox387df5e2008-11-24 14:51:33 -0800298
299// Get the i'th arg of the struct value.
300// If the arg itself is an interface, return a value for
301// the thing inside the interface, not the interface itself.
Russ Cox0d400a72009-07-07 11:03:31 -0700302func getField(v *reflect.StructValue, i int) reflect.Value {
Russ Cox387df5e2008-11-24 14:51:33 -0800303 val := v.Field(i);
Russ Cox0d400a72009-07-07 11:03:31 -0700304 if i, ok := val.(*reflect.InterfaceValue); ok {
305 if inter := i.Interface(); inter != nil {
Robert Griesemer40621d52009-11-09 12:07:39 -0800306 return reflect.NewValue(inter)
Russ Cox0d400a72009-07-07 11:03:31 -0700307 }
Russ Cox387df5e2008-11-24 14:51:33 -0800308 }
309 return val;
310}
311
Rob Pike418b97c2008-10-24 16:33:29 -0700312// Getters for the fields of the argument structure.
313
Rob Pikef15dfa72008-11-06 10:40:57 -0800314func getBool(v reflect.Value) (val bool, ok bool) {
Russ Cox0d400a72009-07-07 11:03:31 -0700315 if b, ok := v.(*reflect.BoolValue); ok {
Robert Griesemer40621d52009-11-09 12:07:39 -0800316 return b.Get(), true
Rob Pikef15dfa72008-11-06 10:40:57 -0800317 }
Russ Cox0d400a72009-07-07 11:03:31 -0700318 return;
Rob Pikef15dfa72008-11-06 10:40:57 -0800319}
320
Rob Pike418b97c2008-10-24 16:33:29 -0700321func getInt(v reflect.Value) (val int64, signed, ok bool) {
Russ Cox0d400a72009-07-07 11:03:31 -0700322 switch v := v.(type) {
323 case *reflect.IntValue:
Robert Griesemer40621d52009-11-09 12:07:39 -0800324 return int64(v.Get()), true, true
Russ Cox0d400a72009-07-07 11:03:31 -0700325 case *reflect.Int8Value:
Robert Griesemer40621d52009-11-09 12:07:39 -0800326 return int64(v.Get()), true, true
Russ Cox0d400a72009-07-07 11:03:31 -0700327 case *reflect.Int16Value:
Robert Griesemer40621d52009-11-09 12:07:39 -0800328 return int64(v.Get()), true, true
Russ Cox0d400a72009-07-07 11:03:31 -0700329 case *reflect.Int32Value:
Robert Griesemer40621d52009-11-09 12:07:39 -0800330 return int64(v.Get()), true, true
Russ Cox0d400a72009-07-07 11:03:31 -0700331 case *reflect.Int64Value:
Robert Griesemer40621d52009-11-09 12:07:39 -0800332 return int64(v.Get()), true, true
Russ Cox0d400a72009-07-07 11:03:31 -0700333 case *reflect.UintValue:
Robert Griesemer40621d52009-11-09 12:07:39 -0800334 return int64(v.Get()), false, true
Russ Cox0d400a72009-07-07 11:03:31 -0700335 case *reflect.Uint8Value:
Robert Griesemer40621d52009-11-09 12:07:39 -0800336 return int64(v.Get()), false, true
Russ Cox0d400a72009-07-07 11:03:31 -0700337 case *reflect.Uint16Value:
Robert Griesemer40621d52009-11-09 12:07:39 -0800338 return int64(v.Get()), false, true
Russ Cox0d400a72009-07-07 11:03:31 -0700339 case *reflect.Uint32Value:
Robert Griesemer40621d52009-11-09 12:07:39 -0800340 return int64(v.Get()), false, true
Russ Cox0d400a72009-07-07 11:03:31 -0700341 case *reflect.Uint64Value:
Robert Griesemer40621d52009-11-09 12:07:39 -0800342 return int64(v.Get()), false, true
Russ Cox0d400a72009-07-07 11:03:31 -0700343 case *reflect.UintptrValue:
Robert Griesemer40621d52009-11-09 12:07:39 -0800344 return int64(v.Get()), false, true
Rob Pike418b97c2008-10-24 16:33:29 -0700345 }
Russ Cox0d400a72009-07-07 11:03:31 -0700346 return;
Rob Pike418b97c2008-10-24 16:33:29 -0700347}
348
349func getString(v reflect.Value) (val string, ok bool) {
Russ Cox0d400a72009-07-07 11:03:31 -0700350 if v, ok := v.(*reflect.StringValue); ok {
Robert Griesemer40621d52009-11-09 12:07:39 -0800351 return v.Get(), true
Rob Pike418b97c2008-10-24 16:33:29 -0700352 }
Russ Cox0d400a72009-07-07 11:03:31 -0700353 if bytes, ok := v.Interface().([]byte); ok {
Robert Griesemer40621d52009-11-09 12:07:39 -0800354 return string(bytes), true
Russ Cox0d400a72009-07-07 11:03:31 -0700355 }
356 return;
Rob Pike418b97c2008-10-24 16:33:29 -0700357}
358
Russ Cox079c00a2008-11-17 12:34:03 -0800359func getFloat32(v reflect.Value) (val float32, ok bool) {
Russ Cox0d400a72009-07-07 11:03:31 -0700360 switch v := v.(type) {
361 case *reflect.Float32Value:
Robert Griesemer40621d52009-11-09 12:07:39 -0800362 return float32(v.Get()), true
Russ Cox0d400a72009-07-07 11:03:31 -0700363 case *reflect.FloatValue:
Robert Griesemerbaba2922009-11-09 21:13:17 -0800364 if v.Type().Size()*8 == 32 {
Robert Griesemer40621d52009-11-09 12:07:39 -0800365 return float32(v.Get()), true
Russ Cox079c00a2008-11-17 12:34:03 -0800366 }
367 }
Russ Cox0d400a72009-07-07 11:03:31 -0700368 return;
Russ Cox079c00a2008-11-17 12:34:03 -0800369}
370
371func getFloat64(v reflect.Value) (val float64, ok bool) {
Russ Cox0d400a72009-07-07 11:03:31 -0700372 switch v := v.(type) {
373 case *reflect.FloatValue:
Robert Griesemerbaba2922009-11-09 21:13:17 -0800374 if v.Type().Size()*8 == 64 {
Robert Griesemer40621d52009-11-09 12:07:39 -0800375 return float64(v.Get()), true
Russ Cox079c00a2008-11-17 12:34:03 -0800376 }
Russ Cox0d400a72009-07-07 11:03:31 -0700377 case *reflect.Float64Value:
Robert Griesemer40621d52009-11-09 12:07:39 -0800378 return float64(v.Get()), true
Rob Pike418b97c2008-10-24 16:33:29 -0700379 }
Russ Cox0d400a72009-07-07 11:03:31 -0700380 return;
Rob Pike418b97c2008-10-24 16:33:29 -0700381}
382
Rob Pike50d06952008-12-09 15:41:21 -0800383func getPtr(v reflect.Value) (val uintptr, ok bool) {
Russ Cox0d400a72009-07-07 11:03:31 -0700384 switch v := v.(type) {
385 case *reflect.PtrValue:
Robert Griesemer40621d52009-11-09 12:07:39 -0800386 return uintptr(v.Get()), true
Rob Pike418b97c2008-10-24 16:33:29 -0700387 }
Russ Cox0d400a72009-07-07 11:03:31 -0700388 return;
Rob Pikeb0d62672008-12-22 11:04:17 -0800389}
390
Rob Pikef15dfa72008-11-06 10:40:57 -0800391// Convert ASCII to integer. n is 0 (and got is false) if no number present.
Rob Pike418b97c2008-10-24 16:33:29 -0700392
393func parsenum(s string, start, end int) (n int, got bool, newi int) {
394 if start >= end {
Robert Griesemer40621d52009-11-09 12:07:39 -0800395 return 0, false, end
Rob Pike418b97c2008-10-24 16:33:29 -0700396 }
Rob Pike418b97c2008-10-24 16:33:29 -0700397 isnum := false;
398 num := 0;
399 for '0' <= s[start] && s[start] <= '9' {
Russ Coxecb863a2009-10-06 15:38:57 -0700400 num = num*10 + int(s[start]-'0');
Rob Pike418b97c2008-10-24 16:33:29 -0700401 start++;
402 isnum = true;
403 }
404 return num, isnum, start;
405}
406
Russ Coxa843b452009-08-31 16:38:30 -0700407type uintptrGetter interface {
408 Get() uintptr;
409}
410
411func (p *pp) printField(field reflect.Value, plus, sharp bool, depth int) (was_string bool) {
Rob Pikeac09eb42008-12-11 12:59:49 -0800412 inter := field.Interface();
413 if inter != nil {
Russ Coxa843b452009-08-31 16:38:30 -0700414 switch {
415 default:
416 if stringer, ok := inter.(Stringer); ok {
Rob Pike4c0e51c2009-12-06 12:03:52 -0800417 p.buf.WriteString(stringer.String());
Russ Coxa843b452009-08-31 16:38:30 -0700418 return false; // this value is not a string
419 }
420 case sharp:
421 if stringer, ok := inter.(GoStringer); ok {
Rob Pike4c0e51c2009-12-06 12:03:52 -0800422 p.buf.WriteString(stringer.GoString());
Russ Coxa843b452009-08-31 16:38:30 -0700423 return false; // this value is not a string
424 }
Rob Pikeac09eb42008-12-11 12:59:49 -0800425 }
Robert Griesemer30c70882009-11-05 09:40:28 -0800426 }
Russ Coxa843b452009-08-31 16:38:30 -0700427BigSwitch:
Russ Cox0d400a72009-07-07 11:03:31 -0700428 switch f := field.(type) {
429 case *reflect.BoolValue:
Rob Pike353ef802009-12-06 12:58:16 -0800430 p.fmt.fmt_boolean(f.Get())
Russ Cox0d400a72009-07-07 11:03:31 -0700431 case *reflect.Float32Value:
Rob Pike353ef802009-12-06 12:58:16 -0800432 p.fmt.fmt_g32(f.Get())
Russ Cox0d400a72009-07-07 11:03:31 -0700433 case *reflect.Float64Value:
Rob Pike353ef802009-12-06 12:58:16 -0800434 p.fmt.fmt_g64(f.Get())
Russ Cox0d400a72009-07-07 11:03:31 -0700435 case *reflect.FloatValue:
Robert Griesemerbaba2922009-11-09 21:13:17 -0800436 if field.Type().Size()*8 == 32 {
Rob Pike353ef802009-12-06 12:58:16 -0800437 p.fmt.fmt_g32(float32(f.Get()))
Russ Cox079c00a2008-11-17 12:34:03 -0800438 } else {
Rob Pike353ef802009-12-06 12:58:16 -0800439 p.fmt.fmt_g64(float64(f.Get()))
Russ Cox079c00a2008-11-17 12:34:03 -0800440 }
Russ Cox0d400a72009-07-07 11:03:31 -0700441 case *reflect.StringValue:
Russ Coxa843b452009-08-31 16:38:30 -0700442 if sharp {
Rob Pike353ef802009-12-06 12:58:16 -0800443 p.fmt.fmt_q(f.Get())
Russ Coxa843b452009-08-31 16:38:30 -0700444 } else {
Rob Pike353ef802009-12-06 12:58:16 -0800445 p.fmt.fmt_s(f.Get());
Russ Coxa843b452009-08-31 16:38:30 -0700446 was_string = true;
Rob Pikee2621b82008-11-13 15:20:52 -0800447 }
Rob Pike3928a4e2009-07-09 17:30:07 -0700448 case *reflect.MapValue:
Russ Coxa843b452009-08-31 16:38:30 -0700449 if sharp {
Rob Pike4c0e51c2009-12-06 12:03:52 -0800450 p.buf.WriteString(field.Type().String());
451 p.buf.WriteByte('{');
Russ Coxa843b452009-08-31 16:38:30 -0700452 } else {
Rob Pike4c0e51c2009-12-06 12:03:52 -0800453 p.buf.Write(mapBytes)
Russ Coxa843b452009-08-31 16:38:30 -0700454 }
Rob Pike3928a4e2009-07-09 17:30:07 -0700455 keys := f.Keys();
456 for i, key := range keys {
457 if i > 0 {
Russ Coxa843b452009-08-31 16:38:30 -0700458 if sharp {
Rob Pike4c0e51c2009-12-06 12:03:52 -0800459 p.buf.Write(commaSpaceBytes)
Russ Coxa843b452009-08-31 16:38:30 -0700460 } else {
Rob Pike4c0e51c2009-12-06 12:03:52 -0800461 p.buf.WriteByte(' ')
Russ Coxa843b452009-08-31 16:38:30 -0700462 }
Rob Pike3928a4e2009-07-09 17:30:07 -0700463 }
Russ Coxa843b452009-08-31 16:38:30 -0700464 p.printField(key, plus, sharp, depth+1);
Rob Pike4c0e51c2009-12-06 12:03:52 -0800465 p.buf.WriteByte(':');
Russ Coxa843b452009-08-31 16:38:30 -0700466 p.printField(f.Elem(key), plus, sharp, depth+1);
Rob Pike3928a4e2009-07-09 17:30:07 -0700467 }
Russ Coxa843b452009-08-31 16:38:30 -0700468 if sharp {
Rob Pike4c0e51c2009-12-06 12:03:52 -0800469 p.buf.WriteByte('}')
Russ Coxa843b452009-08-31 16:38:30 -0700470 } else {
Rob Pike4c0e51c2009-12-06 12:03:52 -0800471 p.buf.WriteByte(']')
Russ Coxa843b452009-08-31 16:38:30 -0700472 }
Russ Cox0d400a72009-07-07 11:03:31 -0700473 case *reflect.StructValue:
Russ Coxa843b452009-08-31 16:38:30 -0700474 if sharp {
Rob Pike4c0e51c2009-12-06 12:03:52 -0800475 p.buf.WriteString(field.Type().String())
Russ Coxa843b452009-08-31 16:38:30 -0700476 }
Rob Pikee2621b82008-11-13 15:20:52 -0800477 p.add('{');
Russ Cox0d400a72009-07-07 11:03:31 -0700478 v := f;
479 t := v.Type().(*reflect.StructType);
Rob Pike353ef802009-12-06 12:58:16 -0800480 p.fmt.clearflags(); // clear flags for p.printField
Russ Coxecb863a2009-10-06 15:38:57 -0700481 for i := 0; i < v.NumField(); i++ {
Russ Coxbf67afc2008-12-11 16:53:33 -0800482 if i > 0 {
Russ Coxa843b452009-08-31 16:38:30 -0700483 if sharp {
Rob Pike4c0e51c2009-12-06 12:03:52 -0800484 p.buf.Write(commaSpaceBytes)
Russ Coxa843b452009-08-31 16:38:30 -0700485 } else {
Rob Pike4c0e51c2009-12-06 12:03:52 -0800486 p.buf.WriteByte(' ')
Russ Coxa843b452009-08-31 16:38:30 -0700487 }
Russ Coxbf67afc2008-12-11 16:53:33 -0800488 }
Russ Coxa843b452009-08-31 16:38:30 -0700489 if plus || sharp {
Russ Cox0d400a72009-07-07 11:03:31 -0700490 if f := t.Field(i); f.Name != "" {
Rob Pike4c0e51c2009-12-06 12:03:52 -0800491 p.buf.WriteString(f.Name);
492 p.buf.WriteByte(':');
Russ Coxbf67afc2008-12-11 16:53:33 -0800493 }
494 }
Russ Coxa843b452009-08-31 16:38:30 -0700495 p.printField(getField(v, i), plus, sharp, depth+1);
Russ Coxbf67afc2008-12-11 16:53:33 -0800496 }
Rob Pike4c0e51c2009-12-06 12:03:52 -0800497 p.buf.WriteByte('}');
Russ Cox0d400a72009-07-07 11:03:31 -0700498 case *reflect.InterfaceValue:
499 value := f.Elem();
Russ Coxac6ebfd2009-04-06 21:28:04 -0700500 if value == nil {
Russ Coxa843b452009-08-31 16:38:30 -0700501 if sharp {
Rob Pike4c0e51c2009-12-06 12:03:52 -0800502 p.buf.WriteString(field.Type().String());
503 p.buf.Write(nilParenBytes);
Russ Coxa843b452009-08-31 16:38:30 -0700504 } else {
Rob Pike4c0e51c2009-12-06 12:03:52 -0800505 p.buf.Write(nilAngleBytes)
Russ Coxa843b452009-08-31 16:38:30 -0700506 }
Rob Pikeac09eb42008-12-11 12:59:49 -0800507 } else {
Robert Griesemer40621d52009-11-09 12:07:39 -0800508 return p.printField(value, plus, sharp, depth+1)
Rob Pikeac09eb42008-12-11 12:59:49 -0800509 }
Russ Coxa843b452009-08-31 16:38:30 -0700510 case reflect.ArrayOrSliceValue:
511 if sharp {
Rob Pike4c0e51c2009-12-06 12:03:52 -0800512 p.buf.WriteString(field.Type().String());
513 p.buf.WriteByte('{');
Russ Coxa843b452009-08-31 16:38:30 -0700514 } else {
Rob Pike4c0e51c2009-12-06 12:03:52 -0800515 p.buf.WriteByte('[')
Russ Coxa843b452009-08-31 16:38:30 -0700516 }
517 for i := 0; i < f.Len(); i++ {
518 if i > 0 {
519 if sharp {
Rob Pike4c0e51c2009-12-06 12:03:52 -0800520 p.buf.Write(commaSpaceBytes)
Russ Coxa843b452009-08-31 16:38:30 -0700521 } else {
Rob Pike4c0e51c2009-12-06 12:03:52 -0800522 p.buf.WriteByte(' ')
Russ Coxa843b452009-08-31 16:38:30 -0700523 }
524 }
525 p.printField(f.Elem(i), plus, sharp, depth+1);
526 }
527 if sharp {
Rob Pike4c0e51c2009-12-06 12:03:52 -0800528 p.buf.WriteByte('}')
Russ Coxa843b452009-08-31 16:38:30 -0700529 } else {
Rob Pike4c0e51c2009-12-06 12:03:52 -0800530 p.buf.WriteByte(']')
Russ Coxa843b452009-08-31 16:38:30 -0700531 }
532 case *reflect.PtrValue:
533 v := f.Get();
534 // pointer to array or slice or struct? ok at top level
535 // but not embedded (avoid loops)
536 if v != 0 && depth == 0 {
537 switch a := f.Elem().(type) {
538 case reflect.ArrayOrSliceValue:
Rob Pike4c0e51c2009-12-06 12:03:52 -0800539 p.buf.WriteByte('&');
Russ Coxa843b452009-08-31 16:38:30 -0700540 p.printField(a, plus, sharp, depth+1);
541 break BigSwitch;
542 case *reflect.StructValue:
Rob Pike4c0e51c2009-12-06 12:03:52 -0800543 p.buf.WriteByte('&');
Russ Coxa843b452009-08-31 16:38:30 -0700544 p.printField(a, plus, sharp, depth+1);
545 break BigSwitch;
546 }
547 }
548 if sharp {
Rob Pike4c0e51c2009-12-06 12:03:52 -0800549 p.buf.WriteByte('(');
550 p.buf.WriteString(field.Type().String());
551 p.buf.WriteByte(')');
552 p.buf.WriteByte('(');
Russ Coxa843b452009-08-31 16:38:30 -0700553 if v == 0 {
Rob Pike4c0e51c2009-12-06 12:03:52 -0800554 p.buf.Write(nilBytes)
Russ Coxa843b452009-08-31 16:38:30 -0700555 } else {
556 p.fmt.sharp = true;
Rob Pike353ef802009-12-06 12:58:16 -0800557 p.fmt.fmt_ux64(uint64(v));
Russ Coxa843b452009-08-31 16:38:30 -0700558 }
Rob Pike4c0e51c2009-12-06 12:03:52 -0800559 p.buf.WriteByte(')');
Russ Coxa843b452009-08-31 16:38:30 -0700560 break;
561 }
562 if v == 0 {
Rob Pike4c0e51c2009-12-06 12:03:52 -0800563 p.buf.Write(nilAngleBytes);
Russ Coxa843b452009-08-31 16:38:30 -0700564 break;
565 }
Russ Coxecb863a2009-10-06 15:38:57 -0700566 p.fmt.sharp = true; // turn 0x on
Rob Pike353ef802009-12-06 12:58:16 -0800567 p.fmt.fmt_ux64(uint64(v));
Russ Coxa843b452009-08-31 16:38:30 -0700568 case uintptrGetter:
569 v := f.Get();
570 if sharp {
Rob Pike4c0e51c2009-12-06 12:03:52 -0800571 p.buf.WriteByte('(');
572 p.buf.WriteString(field.Type().String());
573 p.buf.WriteByte(')');
574 p.buf.WriteByte('(');
Russ Coxa843b452009-08-31 16:38:30 -0700575 if v == 0 {
Rob Pike4c0e51c2009-12-06 12:03:52 -0800576 p.buf.Write(nilBytes)
Russ Coxa843b452009-08-31 16:38:30 -0700577 } else {
578 p.fmt.sharp = true;
Rob Pike353ef802009-12-06 12:58:16 -0800579 p.fmt.fmt_ux64(uint64(v));
Russ Coxa843b452009-08-31 16:38:30 -0700580 }
Rob Pike4c0e51c2009-12-06 12:03:52 -0800581 p.buf.WriteByte(')');
Russ Coxa843b452009-08-31 16:38:30 -0700582 } else {
Russ Coxecb863a2009-10-06 15:38:57 -0700583 p.fmt.sharp = true; // turn 0x on
Rob Pike353ef802009-12-06 12:58:16 -0800584 p.fmt.fmt_ux64(uint64(f.Get()));
Russ Coxa843b452009-08-31 16:38:30 -0700585 }
Rob Pikee2621b82008-11-13 15:20:52 -0800586 default:
Russ Cox0d400a72009-07-07 11:03:31 -0700587 v, signed, ok := getInt(field);
588 if ok {
589 if signed {
Rob Pike353ef802009-12-06 12:58:16 -0800590 p.fmt.fmt_d64(v)
Russ Cox0d400a72009-07-07 11:03:31 -0700591 } else {
Russ Coxa843b452009-08-31 16:38:30 -0700592 if sharp {
593 p.fmt.sharp = true; // turn on 0x
Rob Pike353ef802009-12-06 12:58:16 -0800594 p.fmt.fmt_ux64(uint64(v));
Russ Coxa843b452009-08-31 16:38:30 -0700595 } else {
Rob Pike353ef802009-12-06 12:58:16 -0800596 p.fmt.fmt_ud64(uint64(v))
Russ Coxa843b452009-08-31 16:38:30 -0700597 }
Russ Cox0d400a72009-07-07 11:03:31 -0700598 }
599 break;
600 }
Rob Pike4c0e51c2009-12-06 12:03:52 -0800601 p.buf.WriteByte('?');
602 p.buf.WriteString(field.Type().String());
603 p.buf.WriteByte('?');
Rob Pikee2621b82008-11-13 15:20:52 -0800604 }
Rob Pikee2621b82008-11-13 15:20:52 -0800605 return was_string;
606}
607
Russ Cox0d400a72009-07-07 11:03:31 -0700608func (p *pp) doprintf(format string, v *reflect.StructValue) {
Robert Griesemerbaba2922009-11-09 21:13:17 -0800609 end := len(format) - 1;
Rob Pike418b97c2008-10-24 16:33:29 -0700610 fieldnum := 0; // we process one field per non-trivial format
Russ Coxecb863a2009-10-06 15:38:57 -0700611 for i := 0; i <= end; {
Russ Cox9ac44492009-11-20 11:45:05 -0800612 c, w := utf8.DecodeRuneInString(format[i:]);
Rob Pike418b97c2008-10-24 16:33:29 -0700613 if c != '%' || i == end {
Rob Pike4c0e51c2009-12-06 12:03:52 -0800614 if w == 1 {
615 p.buf.WriteByte(byte(c))
616 } else {
617 p.buf.WriteString(format[i : i+w])
618 }
Rob Pike418b97c2008-10-24 16:33:29 -0700619 i += w;
620 continue;
621 }
Russ Cox387df5e2008-11-24 14:51:33 -0800622 i++;
Russ Coxbf67afc2008-12-11 16:53:33 -0800623 // flags and widths
Rob Pike353ef802009-12-06 12:58:16 -0800624 p.fmt.clearflags();
Russ Coxecb863a2009-10-06 15:38:57 -0700625 F: for ; i < end; i++ {
Russ Cox387df5e2008-11-24 14:51:33 -0800626 switch format[i] {
627 case '#':
Robert Griesemer40621d52009-11-09 12:07:39 -0800628 p.fmt.sharp = true
Russ Cox387df5e2008-11-24 14:51:33 -0800629 case '0':
Robert Griesemer40621d52009-11-09 12:07:39 -0800630 p.fmt.zero = true
Russ Cox387df5e2008-11-24 14:51:33 -0800631 case '+':
Robert Griesemer40621d52009-11-09 12:07:39 -0800632 p.fmt.plus = true
Russ Cox387df5e2008-11-24 14:51:33 -0800633 case '-':
Robert Griesemer40621d52009-11-09 12:07:39 -0800634 p.fmt.minus = true
Russ Cox387df5e2008-11-24 14:51:33 -0800635 case ' ':
Robert Griesemer40621d52009-11-09 12:07:39 -0800636 p.fmt.space = true
Russ Cox387df5e2008-11-24 14:51:33 -0800637 default:
Robert Griesemer40621d52009-11-09 12:07:39 -0800638 break F
Russ Cox387df5e2008-11-24 14:51:33 -0800639 }
640 }
641 // do we have 20 (width)?
Rob Pike4c0e51c2009-12-06 12:03:52 -0800642 p.fmt.wid, p.fmt.widPresent, i = parsenum(format, i, end);
Russ Cox387df5e2008-11-24 14:51:33 -0800643 // do we have .20 (precision)?
Rob Pike418b97c2008-10-24 16:33:29 -0700644 if i < end && format[i] == '.' {
Rob Pike4c0e51c2009-12-06 12:03:52 -0800645 p.fmt.prec, p.fmt.precPresent, i = parsenum(format, i+1, end)
Rob Pike418b97c2008-10-24 16:33:29 -0700646 }
Russ Cox9ac44492009-11-20 11:45:05 -0800647 c, w = utf8.DecodeRuneInString(format[i:]);
Rob Pike418b97c2008-10-24 16:33:29 -0700648 i += w;
649 // percent is special - absorbs no operand
650 if c == '%' {
Rob Pike4c0e51c2009-12-06 12:03:52 -0800651 p.buf.WriteByte('%'); // TODO: should we bother with width & prec?
Rob Pike418b97c2008-10-24 16:33:29 -0700652 continue;
653 }
Russ Cox0d400a72009-07-07 11:03:31 -0700654 if fieldnum >= v.NumField() { // out of operands
Rob Pike4c0e51c2009-12-06 12:03:52 -0800655 p.buf.WriteByte('%');
Rob Pikef15dfa72008-11-06 10:40:57 -0800656 p.add(c);
Rob Pike4c0e51c2009-12-06 12:03:52 -0800657 p.buf.Write(missingBytes);
Rob Pike418b97c2008-10-24 16:33:29 -0700658 continue;
659 }
Russ Cox387df5e2008-11-24 14:51:33 -0800660 field := getField(v, fieldnum);
Rob Pike418b97c2008-10-24 16:33:29 -0700661 fieldnum++;
Russ Coxa843b452009-08-31 16:38:30 -0700662
663 // Try formatter except for %T,
664 // which is special and handled internally.
Rob Pikeac09eb42008-12-11 12:59:49 -0800665 inter := field.Interface();
Russ Coxa843b452009-08-31 16:38:30 -0700666 if inter != nil && c != 'T' {
Rob Pike28ba9772009-06-23 15:20:30 -0700667 if formatter, ok := inter.(Formatter); ok {
Rob Pikee2621b82008-11-13 15:20:52 -0800668 formatter.Format(p, c);
669 continue;
670 }
Rob Pikef15dfa72008-11-06 10:40:57 -0800671 }
Russ Coxa843b452009-08-31 16:38:30 -0700672
Rob Pike418b97c2008-10-24 16:33:29 -0700673 switch c {
Russ Cox8f2bf202009-09-10 14:18:53 -0700674 // bool
675 case 't':
676 if v, ok := getBool(field); ok {
677 if v {
Rob Pike4c0e51c2009-12-06 12:03:52 -0800678 p.buf.Write(trueBytes)
Rob Pike59f029c2008-11-01 16:37:53 -0700679 } else {
Rob Pike4c0e51c2009-12-06 12:03:52 -0800680 p.buf.Write(falseBytes)
Rob Pike59f029c2008-11-01 16:37:53 -0700681 }
Russ Cox8f2bf202009-09-10 14:18:53 -0700682 } else {
Robert Griesemer40621d52009-11-09 12:07:39 -0800683 goto badtype
Russ Cox8f2bf202009-09-10 14:18:53 -0700684 }
Rob Pike59f029c2008-11-01 16:37:53 -0700685
Russ Cox8f2bf202009-09-10 14:18:53 -0700686 // int
687 case 'b':
Russ Coxca6a0fe2009-09-15 09:41:59 -0700688 if v, _, ok := getInt(field); ok {
Rob Pike353ef802009-12-06 12:58:16 -0800689 p.fmt.fmt_b64(uint64(v)) // always unsigned
Russ Cox8f2bf202009-09-10 14:18:53 -0700690 } else if v, ok := getFloat32(field); ok {
Rob Pike353ef802009-12-06 12:58:16 -0800691 p.fmt.fmt_fb32(v)
Russ Cox8f2bf202009-09-10 14:18:53 -0700692 } else if v, ok := getFloat64(field); ok {
Rob Pike353ef802009-12-06 12:58:16 -0800693 p.fmt.fmt_fb64(v)
Russ Cox8f2bf202009-09-10 14:18:53 -0700694 } else {
Robert Griesemer40621d52009-11-09 12:07:39 -0800695 goto badtype
Russ Cox8f2bf202009-09-10 14:18:53 -0700696 }
697 case 'c':
Russ Coxca6a0fe2009-09-15 09:41:59 -0700698 if v, _, ok := getInt(field); ok {
Rob Pike353ef802009-12-06 12:58:16 -0800699 p.fmt.fmt_c(int(v))
Russ Cox8f2bf202009-09-10 14:18:53 -0700700 } else {
Robert Griesemer40621d52009-11-09 12:07:39 -0800701 goto badtype
Russ Cox8f2bf202009-09-10 14:18:53 -0700702 }
703 case 'd':
704 if v, signed, ok := getInt(field); ok {
705 if signed {
Rob Pike353ef802009-12-06 12:58:16 -0800706 p.fmt.fmt_d64(v)
Rob Pike418b97c2008-10-24 16:33:29 -0700707 } else {
Rob Pike353ef802009-12-06 12:58:16 -0800708 p.fmt.fmt_ud64(uint64(v))
Rob Pikef15dfa72008-11-06 10:40:57 -0800709 }
Russ Cox8f2bf202009-09-10 14:18:53 -0700710 } else {
Robert Griesemer40621d52009-11-09 12:07:39 -0800711 goto badtype
Russ Cox8f2bf202009-09-10 14:18:53 -0700712 }
713 case 'o':
714 if v, signed, ok := getInt(field); ok {
715 if signed {
Rob Pike353ef802009-12-06 12:58:16 -0800716 p.fmt.fmt_o64(v)
Rob Pikef15dfa72008-11-06 10:40:57 -0800717 } else {
Rob Pike353ef802009-12-06 12:58:16 -0800718 p.fmt.fmt_uo64(uint64(v))
Rob Pike418b97c2008-10-24 16:33:29 -0700719 }
Russ Cox8f2bf202009-09-10 14:18:53 -0700720 } else {
Robert Griesemer40621d52009-11-09 12:07:39 -0800721 goto badtype
Russ Cox8f2bf202009-09-10 14:18:53 -0700722 }
723 case 'x':
724 if v, signed, ok := getInt(field); ok {
725 if signed {
Rob Pike353ef802009-12-06 12:58:16 -0800726 p.fmt.fmt_x64(v)
Rob Pike418b97c2008-10-24 16:33:29 -0700727 } else {
Rob Pike353ef802009-12-06 12:58:16 -0800728 p.fmt.fmt_ux64(uint64(v))
Rob Pike418b97c2008-10-24 16:33:29 -0700729 }
Russ Cox8f2bf202009-09-10 14:18:53 -0700730 } else if v, ok := getString(field); ok {
Rob Pike353ef802009-12-06 12:58:16 -0800731 p.fmt.fmt_sx(v)
Russ Cox8f2bf202009-09-10 14:18:53 -0700732 } else {
Robert Griesemer40621d52009-11-09 12:07:39 -0800733 goto badtype
Russ Cox8f2bf202009-09-10 14:18:53 -0700734 }
735 case 'X':
736 if v, signed, ok := getInt(field); ok {
737 if signed {
Rob Pike353ef802009-12-06 12:58:16 -0800738 p.fmt.fmt_X64(v)
Rob Pike418b97c2008-10-24 16:33:29 -0700739 } else {
Rob Pike353ef802009-12-06 12:58:16 -0800740 p.fmt.fmt_uX64(uint64(v))
Rob Pike418b97c2008-10-24 16:33:29 -0700741 }
Russ Cox8f2bf202009-09-10 14:18:53 -0700742 } else if v, ok := getString(field); ok {
Rob Pike353ef802009-12-06 12:58:16 -0800743 p.fmt.fmt_sX(v)
Russ Cox8f2bf202009-09-10 14:18:53 -0700744 } else {
Robert Griesemer40621d52009-11-09 12:07:39 -0800745 goto badtype
Russ Cox8f2bf202009-09-10 14:18:53 -0700746 }
Rob Pike418b97c2008-10-24 16:33:29 -0700747
Russ Cox8f2bf202009-09-10 14:18:53 -0700748 // float
749 case 'e':
750 if v, ok := getFloat32(field); ok {
Rob Pike353ef802009-12-06 12:58:16 -0800751 p.fmt.fmt_e32(v)
Russ Cox8f2bf202009-09-10 14:18:53 -0700752 } else if v, ok := getFloat64(field); ok {
Rob Pike353ef802009-12-06 12:58:16 -0800753 p.fmt.fmt_e64(v)
Russ Cox8f2bf202009-09-10 14:18:53 -0700754 } else {
Robert Griesemer40621d52009-11-09 12:07:39 -0800755 goto badtype
Russ Cox8f2bf202009-09-10 14:18:53 -0700756 }
757 case 'E':
758 if v, ok := getFloat32(field); ok {
Rob Pike353ef802009-12-06 12:58:16 -0800759 p.fmt.fmt_E32(v)
Russ Cox8f2bf202009-09-10 14:18:53 -0700760 } else if v, ok := getFloat64(field); ok {
Rob Pike353ef802009-12-06 12:58:16 -0800761 p.fmt.fmt_E64(v)
Russ Cox8f2bf202009-09-10 14:18:53 -0700762 } else {
Robert Griesemer40621d52009-11-09 12:07:39 -0800763 goto badtype
Russ Cox8f2bf202009-09-10 14:18:53 -0700764 }
765 case 'f':
766 if v, ok := getFloat32(field); ok {
Rob Pike353ef802009-12-06 12:58:16 -0800767 p.fmt.fmt_f32(v)
Russ Cox8f2bf202009-09-10 14:18:53 -0700768 } else if v, ok := getFloat64(field); ok {
Rob Pike353ef802009-12-06 12:58:16 -0800769 p.fmt.fmt_f64(v)
Russ Cox8f2bf202009-09-10 14:18:53 -0700770 } else {
Robert Griesemer40621d52009-11-09 12:07:39 -0800771 goto badtype
Russ Cox8f2bf202009-09-10 14:18:53 -0700772 }
773 case 'g':
774 if v, ok := getFloat32(field); ok {
Rob Pike353ef802009-12-06 12:58:16 -0800775 p.fmt.fmt_g32(v)
Russ Cox8f2bf202009-09-10 14:18:53 -0700776 } else if v, ok := getFloat64(field); ok {
Rob Pike353ef802009-12-06 12:58:16 -0800777 p.fmt.fmt_g64(v)
Russ Cox8f2bf202009-09-10 14:18:53 -0700778 } else {
Robert Griesemer40621d52009-11-09 12:07:39 -0800779 goto badtype
Russ Cox8f2bf202009-09-10 14:18:53 -0700780 }
781 case 'G':
782 if v, ok := getFloat32(field); ok {
Rob Pike353ef802009-12-06 12:58:16 -0800783 p.fmt.fmt_G32(v)
Russ Cox8f2bf202009-09-10 14:18:53 -0700784 } else if v, ok := getFloat64(field); ok {
Rob Pike353ef802009-12-06 12:58:16 -0800785 p.fmt.fmt_G64(v)
Russ Cox8f2bf202009-09-10 14:18:53 -0700786 } else {
Robert Griesemer40621d52009-11-09 12:07:39 -0800787 goto badtype
Russ Cox8f2bf202009-09-10 14:18:53 -0700788 }
Rob Pike418b97c2008-10-24 16:33:29 -0700789
Russ Cox8f2bf202009-09-10 14:18:53 -0700790 // string
791 case 's':
792 if inter != nil {
793 // if object implements String, use the result.
794 if stringer, ok := inter.(Stringer); ok {
Rob Pike353ef802009-12-06 12:58:16 -0800795 p.fmt.fmt_s(stringer.String());
Russ Cox8f2bf202009-09-10 14:18:53 -0700796 break;
Rob Pike85647c92009-03-06 03:35:38 -0800797 }
Russ Cox8f2bf202009-09-10 14:18:53 -0700798 }
799 if v, ok := getString(field); ok {
Rob Pike353ef802009-12-06 12:58:16 -0800800 p.fmt.fmt_s(v)
Russ Cox8f2bf202009-09-10 14:18:53 -0700801 } else {
Robert Griesemer40621d52009-11-09 12:07:39 -0800802 goto badtype
Russ Cox8f2bf202009-09-10 14:18:53 -0700803 }
804 case 'q':
805 if v, ok := getString(field); ok {
Rob Pike353ef802009-12-06 12:58:16 -0800806 p.fmt.fmt_q(v)
Russ Cox8f2bf202009-09-10 14:18:53 -0700807 } else {
Robert Griesemer40621d52009-11-09 12:07:39 -0800808 goto badtype
Russ Cox8f2bf202009-09-10 14:18:53 -0700809 }
810
811 // pointer
812 case 'p':
813 if v, ok := getPtr(field); ok {
814 if v == 0 {
Rob Pike4c0e51c2009-12-06 12:03:52 -0800815 p.buf.Write(nilAngleBytes)
Rob Pike418b97c2008-10-24 16:33:29 -0700816 } else {
Rob Pike353ef802009-12-06 12:58:16 -0800817 p.fmt.fmt_s("0x");
818 p.fmt.fmt_uX64(uint64(v));
Rob Pike418b97c2008-10-24 16:33:29 -0700819 }
Russ Cox8f2bf202009-09-10 14:18:53 -0700820 } else {
Robert Griesemer40621d52009-11-09 12:07:39 -0800821 goto badtype
Russ Cox8f2bf202009-09-10 14:18:53 -0700822 }
Rob Pike418b97c2008-10-24 16:33:29 -0700823
Russ Cox8f2bf202009-09-10 14:18:53 -0700824 // arbitrary value; do your best
825 case 'v':
826 plus, sharp := p.fmt.plus, p.fmt.sharp;
827 p.fmt.plus = false;
828 p.fmt.sharp = false;
829 p.printField(field, plus, sharp, 0);
Rob Pike418b97c2008-10-24 16:33:29 -0700830
Russ Cox8f2bf202009-09-10 14:18:53 -0700831 // the value's type
832 case 'T':
Rob Pike4c0e51c2009-12-06 12:03:52 -0800833 p.buf.WriteString(field.Type().String())
Rob Pikee2621b82008-11-13 15:20:52 -0800834
Russ Cox8f2bf202009-09-10 14:18:53 -0700835 default:
836 badtype:
Rob Pike4c0e51c2009-12-06 12:03:52 -0800837 p.buf.WriteByte('%');
838 p.add(c);
839 p.buf.WriteByte('(');
840 p.buf.WriteString(field.Type().String());
841 p.buf.WriteByte('=');
Russ Cox8f2bf202009-09-10 14:18:53 -0700842 p.printField(field, false, false, 0);
Rob Pike4c0e51c2009-12-06 12:03:52 -0800843 p.buf.WriteByte(')');
Rob Pike418b97c2008-10-24 16:33:29 -0700844 }
Rob Pike418b97c2008-10-24 16:33:29 -0700845 }
Russ Cox0d400a72009-07-07 11:03:31 -0700846 if fieldnum < v.NumField() {
Rob Pike4c0e51c2009-12-06 12:03:52 -0800847 p.buf.Write(extraBytes);
Russ Cox0d400a72009-07-07 11:03:31 -0700848 for ; fieldnum < v.NumField(); fieldnum++ {
Rob Pikec6540d32009-08-28 13:02:34 -0700849 field := getField(v, fieldnum);
Rob Pike4c0e51c2009-12-06 12:03:52 -0800850 p.buf.WriteString(field.Type().String());
851 p.buf.WriteByte('=');
Russ Coxa843b452009-08-31 16:38:30 -0700852 p.printField(field, false, false, 0);
Russ Coxecb863a2009-10-06 15:38:57 -0700853 if fieldnum+1 < v.NumField() {
Rob Pike4c0e51c2009-12-06 12:03:52 -0800854 p.buf.Write(commaSpaceBytes)
Rob Pikef15dfa72008-11-06 10:40:57 -0800855 }
856 }
Rob Pike4c0e51c2009-12-06 12:03:52 -0800857 p.buf.WriteByte(')');
Rob Pikef15dfa72008-11-06 10:40:57 -0800858 }
Rob Pike418b97c2008-10-24 16:33:29 -0700859}
860
Russ Cox0d400a72009-07-07 11:03:31 -0700861func (p *pp) doprint(v *reflect.StructValue, addspace, addnewline bool) {
Rob Pike418b97c2008-10-24 16:33:29 -0700862 prev_string := false;
Russ Coxecb863a2009-10-06 15:38:57 -0700863 for fieldnum := 0; fieldnum < v.NumField(); fieldnum++ {
Rob Pike418b97c2008-10-24 16:33:29 -0700864 // always add spaces if we're doing println
Russ Cox387df5e2008-11-24 14:51:33 -0800865 field := getField(v, fieldnum);
Rob Pike2d4f7ba2008-11-02 12:33:02 -0800866 if fieldnum > 0 {
Russ Cox0d400a72009-07-07 11:03:31 -0700867 _, is_string := field.(*reflect.StringValue);
868 if addspace || !is_string && !prev_string {
Rob Pike4c0e51c2009-12-06 12:03:52 -0800869 p.buf.WriteByte(' ')
Rob Pike418b97c2008-10-24 16:33:29 -0700870 }
Rob Pike418b97c2008-10-24 16:33:29 -0700871 }
Russ Coxa843b452009-08-31 16:38:30 -0700872 prev_string = p.printField(field, false, false, 0);
Rob Pike418b97c2008-10-24 16:33:29 -0700873 }
Rob Pike2d4f7ba2008-11-02 12:33:02 -0800874 if addnewline {
Rob Pike4c0e51c2009-12-06 12:03:52 -0800875 p.buf.WriteByte('\n')
Rob Pike418b97c2008-10-24 16:33:29 -0700876 }
877}