Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 1 | // 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 Pike | b6ce2a7 | 2009-06-22 18:09:40 -0700 | [diff] [blame] | 5 | /* |
| 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 Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 13 | %v the value in a default format. |
Rob Pike | b6ce2a7 | 2009-06-22 18:09:40 -0700 | [diff] [blame] | 14 | when printing structs, the plus flag (%+v) adds field names |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 15 | %#v a Go-syntax representation of the value |
| 16 | %T a Go-syntax representation of the type of the value |
| 17 | |
Rob Pike | b6ce2a7 | 2009-06-22 18:09:40 -0700 | [diff] [blame] | 18 | 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 Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 29 | %E scientific notation, e.g. -1234.456E+78 |
Rob Pike | b6ce2a7 | 2009-06-22 18:09:40 -0700 | [diff] [blame] | 30 | %f decimal point but no exponent, e.g. 123.456 |
| 31 | %g whichever of %e or %f produces more compact output |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 32 | %G whichever of %E or %f produces more compact output |
Rob Pike | b6ce2a7 | 2009-06-22 18:09:40 -0700 | [diff] [blame] | 33 | 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 Pike | b6ce2a7 | 2009-06-22 18:09:40 -0700 | [diff] [blame] | 39 | |
| 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 Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 63 | 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 Pike | 07a497f | 2009-07-30 16:57:46 -0700 | [diff] [blame] | 70 | If an operand implements interface Formatter, that interface |
Rob Pike | b6ce2a7 | 2009-06-22 18:09:40 -0700 | [diff] [blame] | 71 | 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 Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 76 | package fmt |
| 77 | |
Rob Pike | db25e78 | 2008-10-26 08:27:50 -0700 | [diff] [blame] | 78 | |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 79 | import ( |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 80 | "bytes"; |
Rob Pike | 2355395 | 2008-11-14 10:42:45 -0800 | [diff] [blame] | 81 | "io"; |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 82 | "os"; |
Russ Cox | 1f6463f | 2009-04-16 20:52:37 -0700 | [diff] [blame] | 83 | "reflect"; |
Russ Cox | 3609624 | 2009-01-16 14:58:14 -0800 | [diff] [blame] | 84 | "utf8"; |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 85 | ) |
| 86 | |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 87 | // Some constants in the form of bytes, to avoid string overhead. |
| 88 | // Needlessly fastidious, I suppose. |
| 89 | var ( |
| 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 Pike | 28ba977 | 2009-06-23 15:20:30 -0700 | [diff] [blame] | 101 | // State represents the printer state passed to custom formatters. |
Rob Pike | c8b47c6 | 2009-05-08 11:22:57 -0700 | [diff] [blame] | 102 | // It provides access to the io.Writer interface plus information about |
Rob Pike | 85647c9 | 2009-03-06 03:35:38 -0800 | [diff] [blame] | 103 | // the flags and options for the operand's format specifier. |
Rob Pike | 28ba977 | 2009-06-23 15:20:30 -0700 | [diff] [blame] | 104 | type State interface { |
Rob Pike | 85647c9 | 2009-03-06 03:35:38 -0800 | [diff] [blame] | 105 | // Write is the function to call to emit formatted output to be printed. |
Rob Pike | aaf63f8 | 2009-04-17 00:08:24 -0700 | [diff] [blame] | 106 | Write(b []byte) (ret int, err os.Error); |
Rob Pike | 85647c9 | 2009-03-06 03:35:38 -0800 | [diff] [blame] | 107 | // Width returns the value of the width option and whether it has been set. |
Russ Cox | ecb863a | 2009-10-06 15:38:57 -0700 | [diff] [blame] | 108 | Width() (wid int, ok bool); |
Rob Pike | 85647c9 | 2009-03-06 03:35:38 -0800 | [diff] [blame] | 109 | // Precision returns the value of the precision option and whether it has been set. |
Russ Cox | ecb863a | 2009-10-06 15:38:57 -0700 | [diff] [blame] | 110 | Precision() (prec int, ok bool); |
Russ Cox | bf67afc | 2008-12-11 16:53:33 -0800 | [diff] [blame] | 111 | |
Rob Pike | 85647c9 | 2009-03-06 03:35:38 -0800 | [diff] [blame] | 112 | // Flag returns whether the flag c, a character, has been set. |
Russ Cox | ecb863a | 2009-10-06 15:38:57 -0700 | [diff] [blame] | 113 | Flag(int) bool; |
Rob Pike | f15dfa7 | 2008-11-06 10:40:57 -0800 | [diff] [blame] | 114 | } |
| 115 | |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 116 | // Formatter is the interface implemented by values with a custom formatter. |
Rob Pike | 85647c9 | 2009-03-06 03:35:38 -0800 | [diff] [blame] | 117 | // The implementation of Format may call Sprintf or Fprintf(f) etc. |
| 118 | // to generate its output. |
Rob Pike | 28ba977 | 2009-06-23 15:20:30 -0700 | [diff] [blame] | 119 | type Formatter interface { |
| 120 | Format(f State, c int); |
Rob Pike | 91212bd | 2008-11-06 11:38:44 -0800 | [diff] [blame] | 121 | } |
| 122 | |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 123 | // 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 Pike | c8b47c6 | 2009-05-08 11:22:57 -0700 | [diff] [blame] | 127 | type Stringer interface { |
Russ Cox | ecb863a | 2009-10-06 15:38:57 -0700 | [diff] [blame] | 128 | String() string; |
Rob Pike | f15dfa7 | 2008-11-06 10:40:57 -0800 | [diff] [blame] | 129 | } |
| 130 | |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 131 | // 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. |
| 135 | type GoStringer interface { |
Russ Cox | ecb863a | 2009-10-06 15:38:57 -0700 | [diff] [blame] | 136 | GoString() string; |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 137 | } |
| 138 | |
Rob Pike | 497bb9c | 2009-01-15 15:40:27 -0800 | [diff] [blame] | 139 | const allocSize = 32 |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 140 | |
Rob Pike | 497bb9c | 2009-01-15 15:40:27 -0800 | [diff] [blame] | 141 | type pp struct { |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 142 | n int; |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 143 | buf bytes.Buffer; |
| 144 | runeBuf [utf8.UTFMax]byte; |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 145 | fmt fmt; |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 146 | } |
| 147 | |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 148 | // A leaky bucket of reusable pp structures. |
| 149 | var ppFree = make(chan *pp, 100) |
| 150 | |
Rob Pike | f91cd44 | 2009-12-06 15:01:07 -0800 | [diff] [blame] | 151 | // Allocate a new pp struct. Probably can grab the previous one from ppFree. |
Rob Pike | db1656f | 2009-01-16 13:29:43 -0800 | [diff] [blame] | 152 | func newPrinter() *pp { |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 153 | p, ok := <-ppFree; |
| 154 | if !ok { |
| 155 | p = new(pp) |
| 156 | } |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 157 | p.fmt.init(&p.buf); |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 158 | return p; |
| 159 | } |
| 160 | |
Rob Pike | f91cd44 | 2009-12-06 15:01:07 -0800 | [diff] [blame] | 161 | // Save used pp structs in ppFree; avoids an allocation per invocation. |
| 162 | func (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 Pike | f15dfa7 | 2008-11-06 10:40:57 -0800 | [diff] [blame] | 170 | |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 171 | func (p *pp) Width() (wid int, ok bool) { return p.fmt.wid, p.fmt.widPresent } |
| 172 | |
| 173 | func (p *pp) Precision() (prec int, ok bool) { return p.fmt.prec, p.fmt.precPresent } |
Russ Cox | bf67afc | 2008-12-11 16:53:33 -0800 | [diff] [blame] | 174 | |
Rob Pike | 497bb9c | 2009-01-15 15:40:27 -0800 | [diff] [blame] | 175 | func (p *pp) Flag(b int) bool { |
Russ Cox | bf67afc | 2008-12-11 16:53:33 -0800 | [diff] [blame] | 176 | switch b { |
| 177 | case '-': |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 178 | return p.fmt.minus |
Russ Cox | bf67afc | 2008-12-11 16:53:33 -0800 | [diff] [blame] | 179 | case '+': |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 180 | return p.fmt.plus |
Russ Cox | bf67afc | 2008-12-11 16:53:33 -0800 | [diff] [blame] | 181 | case '#': |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 182 | return p.fmt.sharp |
Russ Cox | bf67afc | 2008-12-11 16:53:33 -0800 | [diff] [blame] | 183 | case ' ': |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 184 | return p.fmt.space |
Russ Cox | bf67afc | 2008-12-11 16:53:33 -0800 | [diff] [blame] | 185 | case '0': |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 186 | return p.fmt.zero |
Russ Cox | bf67afc | 2008-12-11 16:53:33 -0800 | [diff] [blame] | 187 | } |
Russ Cox | ecb863a | 2009-10-06 15:38:57 -0700 | [diff] [blame] | 188 | return false; |
Rob Pike | f15dfa7 | 2008-11-06 10:40:57 -0800 | [diff] [blame] | 189 | } |
| 190 | |
Rob Pike | 497bb9c | 2009-01-15 15:40:27 -0800 | [diff] [blame] | 191 | func (p *pp) add(c int) { |
Rob Pike | f91cd44 | 2009-12-06 15:01:07 -0800 | [diff] [blame] | 192 | if c < utf8.RuneSelf { |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 193 | p.buf.WriteByte(byte(c)) |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 194 | } else { |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 195 | w := utf8.EncodeRune(c, &p.runeBuf); |
| 196 | p.buf.Write(p.runeBuf[0:w]); |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 197 | } |
| 198 | } |
| 199 | |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 200 | // Implement Write so we can call Fprintf on a pp (through State), for |
Rob Pike | 3200b06 | 2008-11-04 13:57:21 -0800 | [diff] [blame] | 201 | // recursive use in custom verbs. |
Rob Pike | aaf63f8 | 2009-04-17 00:08:24 -0700 | [diff] [blame] | 202 | func (p *pp) Write(b []byte) (ret int, err os.Error) { |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 203 | return p.buf.Write(b) |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 204 | } |
| 205 | |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 206 | // These routines end in 'f' and take a format string. |
| 207 | |
Rob Pike | 85647c9 | 2009-03-06 03:35:38 -0800 | [diff] [blame] | 208 | // Fprintf formats according to a format specifier and writes to w. |
Rob Pike | c8b47c6 | 2009-05-08 11:22:57 -0700 | [diff] [blame] | 209 | func Fprintf(w io.Writer, format string, a ...) (n int, error os.Error) { |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 210 | v := reflect.NewValue(a).(*reflect.StructValue); |
Rob Pike | db1656f | 2009-01-16 13:29:43 -0800 | [diff] [blame] | 211 | p := newPrinter(); |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 212 | p.doprintf(format, v); |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 213 | n64, error := p.buf.WriteTo(w); |
| 214 | p.free(); |
| 215 | return int(n64), error; |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 216 | } |
| 217 | |
Rob Pike | 85647c9 | 2009-03-06 03:35:38 -0800 | [diff] [blame] | 218 | // Printf formats according to a format specifier and writes to standard output. |
Rob Pike | aaf63f8 | 2009-04-17 00:08:24 -0700 | [diff] [blame] | 219 | func Printf(format string, v ...) (n int, errno os.Error) { |
Rob Pike | 61f3302 | 2009-01-15 13:48:11 -0800 | [diff] [blame] | 220 | n, errno = Fprintf(os.Stdout, format, v); |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 221 | return n, errno; |
| 222 | } |
| 223 | |
Rob Pike | 85647c9 | 2009-03-06 03:35:38 -0800 | [diff] [blame] | 224 | // Sprintf formats according to a format specifier and returns the resulting string. |
Russ Cox | 839a684 | 2009-01-20 14:40:40 -0800 | [diff] [blame] | 225 | func Sprintf(format string, a ...) string { |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 226 | v := reflect.NewValue(a).(*reflect.StructValue); |
Rob Pike | db1656f | 2009-01-16 13:29:43 -0800 | [diff] [blame] | 227 | p := newPrinter(); |
Robert Griesemer | 3a2c0a9 | 2008-11-06 11:56:08 -0800 | [diff] [blame] | 228 | p.doprintf(format, v); |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 229 | s := p.buf.String(); |
| 230 | p.free(); |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 231 | return s; |
| 232 | } |
| 233 | |
Rob Pike | 85647c9 | 2009-03-06 03:35:38 -0800 | [diff] [blame] | 234 | // These routines do not take a format string |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 235 | |
Rob Pike | 85647c9 | 2009-03-06 03:35:38 -0800 | [diff] [blame] | 236 | // 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 Pike | c8b47c6 | 2009-05-08 11:22:57 -0700 | [diff] [blame] | 238 | func Fprint(w io.Writer, a ...) (n int, error os.Error) { |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 239 | v := reflect.NewValue(a).(*reflect.StructValue); |
Rob Pike | db1656f | 2009-01-16 13:29:43 -0800 | [diff] [blame] | 240 | p := newPrinter(); |
Rob Pike | 2d4f7ba | 2008-11-02 12:33:02 -0800 | [diff] [blame] | 241 | p.doprint(v, false, false); |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 242 | n64, error := p.buf.WriteTo(w); |
| 243 | p.free(); |
| 244 | return int(n64), error; |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 245 | } |
| 246 | |
Rob Pike | 85647c9 | 2009-03-06 03:35:38 -0800 | [diff] [blame] | 247 | // 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 Pike | aaf63f8 | 2009-04-17 00:08:24 -0700 | [diff] [blame] | 249 | func Print(v ...) (n int, errno os.Error) { |
Rob Pike | 61f3302 | 2009-01-15 13:48:11 -0800 | [diff] [blame] | 250 | n, errno = Fprint(os.Stdout, v); |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 251 | return n, errno; |
| 252 | } |
| 253 | |
Rob Pike | 85647c9 | 2009-03-06 03:35:38 -0800 | [diff] [blame] | 254 | // 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 Cox | 839a684 | 2009-01-20 14:40:40 -0800 | [diff] [blame] | 256 | func Sprint(a ...) string { |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 257 | v := reflect.NewValue(a).(*reflect.StructValue); |
Rob Pike | db1656f | 2009-01-16 13:29:43 -0800 | [diff] [blame] | 258 | p := newPrinter(); |
Robert Griesemer | 3a2c0a9 | 2008-11-06 11:56:08 -0800 | [diff] [blame] | 259 | p.doprint(v, false, false); |
Rob Pike | f91cd44 | 2009-12-06 15:01:07 -0800 | [diff] [blame] | 260 | s := p.buf.String(); |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 261 | p.free(); |
Rob Pike | f91cd44 | 2009-12-06 15:01:07 -0800 | [diff] [blame] | 262 | return s; |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 263 | } |
| 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 Pike | 85647c9 | 2009-03-06 03:35:38 -0800 | [diff] [blame] | 269 | // 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 Pike | c8b47c6 | 2009-05-08 11:22:57 -0700 | [diff] [blame] | 271 | func Fprintln(w io.Writer, a ...) (n int, error os.Error) { |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 272 | v := reflect.NewValue(a).(*reflect.StructValue); |
Rob Pike | db1656f | 2009-01-16 13:29:43 -0800 | [diff] [blame] | 273 | p := newPrinter(); |
Rob Pike | 2d4f7ba | 2008-11-02 12:33:02 -0800 | [diff] [blame] | 274 | p.doprint(v, true, true); |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 275 | n64, error := p.buf.WriteTo(w); |
| 276 | p.free(); |
| 277 | return int(n64), error; |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 278 | } |
| 279 | |
Rob Pike | 85647c9 | 2009-03-06 03:35:38 -0800 | [diff] [blame] | 280 | // 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 Pike | aaf63f8 | 2009-04-17 00:08:24 -0700 | [diff] [blame] | 282 | func Println(v ...) (n int, errno os.Error) { |
Rob Pike | 61f3302 | 2009-01-15 13:48:11 -0800 | [diff] [blame] | 283 | n, errno = Fprintln(os.Stdout, v); |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 284 | return n, errno; |
| 285 | } |
| 286 | |
Rob Pike | 85647c9 | 2009-03-06 03:35:38 -0800 | [diff] [blame] | 287 | // 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 Cox | 839a684 | 2009-01-20 14:40:40 -0800 | [diff] [blame] | 289 | func Sprintln(a ...) string { |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 290 | v := reflect.NewValue(a).(*reflect.StructValue); |
Rob Pike | db1656f | 2009-01-16 13:29:43 -0800 | [diff] [blame] | 291 | p := newPrinter(); |
Robert Griesemer | 3a2c0a9 | 2008-11-06 11:56:08 -0800 | [diff] [blame] | 292 | p.doprint(v, true, true); |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 293 | s := p.buf.String(); |
| 294 | p.free(); |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 295 | return s; |
| 296 | } |
| 297 | |
Russ Cox | 387df5e | 2008-11-24 14:51:33 -0800 | [diff] [blame] | 298 | |
| 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 Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 302 | func getField(v *reflect.StructValue, i int) reflect.Value { |
Russ Cox | 387df5e | 2008-11-24 14:51:33 -0800 | [diff] [blame] | 303 | val := v.Field(i); |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 304 | if i, ok := val.(*reflect.InterfaceValue); ok { |
| 305 | if inter := i.Interface(); inter != nil { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 306 | return reflect.NewValue(inter) |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 307 | } |
Russ Cox | 387df5e | 2008-11-24 14:51:33 -0800 | [diff] [blame] | 308 | } |
| 309 | return val; |
| 310 | } |
| 311 | |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 312 | // Getters for the fields of the argument structure. |
| 313 | |
Rob Pike | f15dfa7 | 2008-11-06 10:40:57 -0800 | [diff] [blame] | 314 | func getBool(v reflect.Value) (val bool, ok bool) { |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 315 | if b, ok := v.(*reflect.BoolValue); ok { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 316 | return b.Get(), true |
Rob Pike | f15dfa7 | 2008-11-06 10:40:57 -0800 | [diff] [blame] | 317 | } |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 318 | return; |
Rob Pike | f15dfa7 | 2008-11-06 10:40:57 -0800 | [diff] [blame] | 319 | } |
| 320 | |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 321 | func getInt(v reflect.Value) (val int64, signed, ok bool) { |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 322 | switch v := v.(type) { |
| 323 | case *reflect.IntValue: |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 324 | return int64(v.Get()), true, true |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 325 | case *reflect.Int8Value: |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 326 | return int64(v.Get()), true, true |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 327 | case *reflect.Int16Value: |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 328 | return int64(v.Get()), true, true |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 329 | case *reflect.Int32Value: |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 330 | return int64(v.Get()), true, true |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 331 | case *reflect.Int64Value: |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 332 | return int64(v.Get()), true, true |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 333 | case *reflect.UintValue: |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 334 | return int64(v.Get()), false, true |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 335 | case *reflect.Uint8Value: |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 336 | return int64(v.Get()), false, true |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 337 | case *reflect.Uint16Value: |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 338 | return int64(v.Get()), false, true |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 339 | case *reflect.Uint32Value: |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 340 | return int64(v.Get()), false, true |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 341 | case *reflect.Uint64Value: |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 342 | return int64(v.Get()), false, true |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 343 | case *reflect.UintptrValue: |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 344 | return int64(v.Get()), false, true |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 345 | } |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 346 | return; |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 347 | } |
| 348 | |
| 349 | func getString(v reflect.Value) (val string, ok bool) { |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 350 | if v, ok := v.(*reflect.StringValue); ok { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 351 | return v.Get(), true |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 352 | } |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 353 | if bytes, ok := v.Interface().([]byte); ok { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 354 | return string(bytes), true |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 355 | } |
| 356 | return; |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 357 | } |
| 358 | |
Russ Cox | 079c00a | 2008-11-17 12:34:03 -0800 | [diff] [blame] | 359 | func getFloat32(v reflect.Value) (val float32, ok bool) { |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 360 | switch v := v.(type) { |
| 361 | case *reflect.Float32Value: |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 362 | return float32(v.Get()), true |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 363 | case *reflect.FloatValue: |
Robert Griesemer | baba292 | 2009-11-09 21:13:17 -0800 | [diff] [blame] | 364 | if v.Type().Size()*8 == 32 { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 365 | return float32(v.Get()), true |
Russ Cox | 079c00a | 2008-11-17 12:34:03 -0800 | [diff] [blame] | 366 | } |
| 367 | } |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 368 | return; |
Russ Cox | 079c00a | 2008-11-17 12:34:03 -0800 | [diff] [blame] | 369 | } |
| 370 | |
| 371 | func getFloat64(v reflect.Value) (val float64, ok bool) { |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 372 | switch v := v.(type) { |
| 373 | case *reflect.FloatValue: |
Robert Griesemer | baba292 | 2009-11-09 21:13:17 -0800 | [diff] [blame] | 374 | if v.Type().Size()*8 == 64 { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 375 | return float64(v.Get()), true |
Russ Cox | 079c00a | 2008-11-17 12:34:03 -0800 | [diff] [blame] | 376 | } |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 377 | case *reflect.Float64Value: |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 378 | return float64(v.Get()), true |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 379 | } |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 380 | return; |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 381 | } |
| 382 | |
Rob Pike | 50d0695 | 2008-12-09 15:41:21 -0800 | [diff] [blame] | 383 | func getPtr(v reflect.Value) (val uintptr, ok bool) { |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 384 | switch v := v.(type) { |
| 385 | case *reflect.PtrValue: |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 386 | return uintptr(v.Get()), true |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 387 | } |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 388 | return; |
Rob Pike | b0d6267 | 2008-12-22 11:04:17 -0800 | [diff] [blame] | 389 | } |
| 390 | |
Rob Pike | f15dfa7 | 2008-11-06 10:40:57 -0800 | [diff] [blame] | 391 | // Convert ASCII to integer. n is 0 (and got is false) if no number present. |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 392 | |
| 393 | func parsenum(s string, start, end int) (n int, got bool, newi int) { |
| 394 | if start >= end { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 395 | return 0, false, end |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 396 | } |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 397 | isnum := false; |
| 398 | num := 0; |
| 399 | for '0' <= s[start] && s[start] <= '9' { |
Russ Cox | ecb863a | 2009-10-06 15:38:57 -0700 | [diff] [blame] | 400 | num = num*10 + int(s[start]-'0'); |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 401 | start++; |
| 402 | isnum = true; |
| 403 | } |
| 404 | return num, isnum, start; |
| 405 | } |
| 406 | |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 407 | type uintptrGetter interface { |
| 408 | Get() uintptr; |
| 409 | } |
| 410 | |
| 411 | func (p *pp) printField(field reflect.Value, plus, sharp bool, depth int) (was_string bool) { |
Rob Pike | ac09eb4 | 2008-12-11 12:59:49 -0800 | [diff] [blame] | 412 | inter := field.Interface(); |
| 413 | if inter != nil { |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 414 | switch { |
| 415 | default: |
| 416 | if stringer, ok := inter.(Stringer); ok { |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 417 | p.buf.WriteString(stringer.String()); |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 418 | return false; // this value is not a string |
| 419 | } |
| 420 | case sharp: |
| 421 | if stringer, ok := inter.(GoStringer); ok { |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 422 | p.buf.WriteString(stringer.GoString()); |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 423 | return false; // this value is not a string |
| 424 | } |
Rob Pike | ac09eb4 | 2008-12-11 12:59:49 -0800 | [diff] [blame] | 425 | } |
Robert Griesemer | 30c7088 | 2009-11-05 09:40:28 -0800 | [diff] [blame] | 426 | } |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 427 | BigSwitch: |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 428 | switch f := field.(type) { |
| 429 | case *reflect.BoolValue: |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 430 | p.fmt.fmt_boolean(f.Get()) |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 431 | case *reflect.Float32Value: |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 432 | p.fmt.fmt_g32(f.Get()) |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 433 | case *reflect.Float64Value: |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 434 | p.fmt.fmt_g64(f.Get()) |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 435 | case *reflect.FloatValue: |
Robert Griesemer | baba292 | 2009-11-09 21:13:17 -0800 | [diff] [blame] | 436 | if field.Type().Size()*8 == 32 { |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 437 | p.fmt.fmt_g32(float32(f.Get())) |
Russ Cox | 079c00a | 2008-11-17 12:34:03 -0800 | [diff] [blame] | 438 | } else { |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 439 | p.fmt.fmt_g64(float64(f.Get())) |
Russ Cox | 079c00a | 2008-11-17 12:34:03 -0800 | [diff] [blame] | 440 | } |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 441 | case *reflect.StringValue: |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 442 | if sharp { |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 443 | p.fmt.fmt_q(f.Get()) |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 444 | } else { |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 445 | p.fmt.fmt_s(f.Get()); |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 446 | was_string = true; |
Rob Pike | e2621b8 | 2008-11-13 15:20:52 -0800 | [diff] [blame] | 447 | } |
Rob Pike | 3928a4e | 2009-07-09 17:30:07 -0700 | [diff] [blame] | 448 | case *reflect.MapValue: |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 449 | if sharp { |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 450 | p.buf.WriteString(field.Type().String()); |
| 451 | p.buf.WriteByte('{'); |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 452 | } else { |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 453 | p.buf.Write(mapBytes) |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 454 | } |
Rob Pike | 3928a4e | 2009-07-09 17:30:07 -0700 | [diff] [blame] | 455 | keys := f.Keys(); |
| 456 | for i, key := range keys { |
| 457 | if i > 0 { |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 458 | if sharp { |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 459 | p.buf.Write(commaSpaceBytes) |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 460 | } else { |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 461 | p.buf.WriteByte(' ') |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 462 | } |
Rob Pike | 3928a4e | 2009-07-09 17:30:07 -0700 | [diff] [blame] | 463 | } |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 464 | p.printField(key, plus, sharp, depth+1); |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 465 | p.buf.WriteByte(':'); |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 466 | p.printField(f.Elem(key), plus, sharp, depth+1); |
Rob Pike | 3928a4e | 2009-07-09 17:30:07 -0700 | [diff] [blame] | 467 | } |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 468 | if sharp { |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 469 | p.buf.WriteByte('}') |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 470 | } else { |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 471 | p.buf.WriteByte(']') |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 472 | } |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 473 | case *reflect.StructValue: |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 474 | if sharp { |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 475 | p.buf.WriteString(field.Type().String()) |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 476 | } |
Rob Pike | e2621b8 | 2008-11-13 15:20:52 -0800 | [diff] [blame] | 477 | p.add('{'); |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 478 | v := f; |
| 479 | t := v.Type().(*reflect.StructType); |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 480 | p.fmt.clearflags(); // clear flags for p.printField |
Russ Cox | ecb863a | 2009-10-06 15:38:57 -0700 | [diff] [blame] | 481 | for i := 0; i < v.NumField(); i++ { |
Russ Cox | bf67afc | 2008-12-11 16:53:33 -0800 | [diff] [blame] | 482 | if i > 0 { |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 483 | if sharp { |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 484 | p.buf.Write(commaSpaceBytes) |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 485 | } else { |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 486 | p.buf.WriteByte(' ') |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 487 | } |
Russ Cox | bf67afc | 2008-12-11 16:53:33 -0800 | [diff] [blame] | 488 | } |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 489 | if plus || sharp { |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 490 | if f := t.Field(i); f.Name != "" { |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 491 | p.buf.WriteString(f.Name); |
| 492 | p.buf.WriteByte(':'); |
Russ Cox | bf67afc | 2008-12-11 16:53:33 -0800 | [diff] [blame] | 493 | } |
| 494 | } |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 495 | p.printField(getField(v, i), plus, sharp, depth+1); |
Russ Cox | bf67afc | 2008-12-11 16:53:33 -0800 | [diff] [blame] | 496 | } |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 497 | p.buf.WriteByte('}'); |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 498 | case *reflect.InterfaceValue: |
| 499 | value := f.Elem(); |
Russ Cox | ac6ebfd | 2009-04-06 21:28:04 -0700 | [diff] [blame] | 500 | if value == nil { |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 501 | if sharp { |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 502 | p.buf.WriteString(field.Type().String()); |
| 503 | p.buf.Write(nilParenBytes); |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 504 | } else { |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 505 | p.buf.Write(nilAngleBytes) |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 506 | } |
Rob Pike | ac09eb4 | 2008-12-11 12:59:49 -0800 | [diff] [blame] | 507 | } else { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 508 | return p.printField(value, plus, sharp, depth+1) |
Rob Pike | ac09eb4 | 2008-12-11 12:59:49 -0800 | [diff] [blame] | 509 | } |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 510 | case reflect.ArrayOrSliceValue: |
| 511 | if sharp { |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 512 | p.buf.WriteString(field.Type().String()); |
| 513 | p.buf.WriteByte('{'); |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 514 | } else { |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 515 | p.buf.WriteByte('[') |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 516 | } |
| 517 | for i := 0; i < f.Len(); i++ { |
| 518 | if i > 0 { |
| 519 | if sharp { |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 520 | p.buf.Write(commaSpaceBytes) |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 521 | } else { |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 522 | p.buf.WriteByte(' ') |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 523 | } |
| 524 | } |
| 525 | p.printField(f.Elem(i), plus, sharp, depth+1); |
| 526 | } |
| 527 | if sharp { |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 528 | p.buf.WriteByte('}') |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 529 | } else { |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 530 | p.buf.WriteByte(']') |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 531 | } |
| 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 Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 539 | p.buf.WriteByte('&'); |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 540 | p.printField(a, plus, sharp, depth+1); |
| 541 | break BigSwitch; |
| 542 | case *reflect.StructValue: |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 543 | p.buf.WriteByte('&'); |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 544 | p.printField(a, plus, sharp, depth+1); |
| 545 | break BigSwitch; |
| 546 | } |
| 547 | } |
| 548 | if sharp { |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 549 | p.buf.WriteByte('('); |
| 550 | p.buf.WriteString(field.Type().String()); |
| 551 | p.buf.WriteByte(')'); |
| 552 | p.buf.WriteByte('('); |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 553 | if v == 0 { |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 554 | p.buf.Write(nilBytes) |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 555 | } else { |
| 556 | p.fmt.sharp = true; |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 557 | p.fmt.fmt_ux64(uint64(v)); |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 558 | } |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 559 | p.buf.WriteByte(')'); |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 560 | break; |
| 561 | } |
| 562 | if v == 0 { |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 563 | p.buf.Write(nilAngleBytes); |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 564 | break; |
| 565 | } |
Russ Cox | ecb863a | 2009-10-06 15:38:57 -0700 | [diff] [blame] | 566 | p.fmt.sharp = true; // turn 0x on |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 567 | p.fmt.fmt_ux64(uint64(v)); |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 568 | case uintptrGetter: |
| 569 | v := f.Get(); |
| 570 | if sharp { |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 571 | p.buf.WriteByte('('); |
| 572 | p.buf.WriteString(field.Type().String()); |
| 573 | p.buf.WriteByte(')'); |
| 574 | p.buf.WriteByte('('); |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 575 | if v == 0 { |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 576 | p.buf.Write(nilBytes) |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 577 | } else { |
| 578 | p.fmt.sharp = true; |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 579 | p.fmt.fmt_ux64(uint64(v)); |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 580 | } |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 581 | p.buf.WriteByte(')'); |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 582 | } else { |
Russ Cox | ecb863a | 2009-10-06 15:38:57 -0700 | [diff] [blame] | 583 | p.fmt.sharp = true; // turn 0x on |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 584 | p.fmt.fmt_ux64(uint64(f.Get())); |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 585 | } |
Rob Pike | e2621b8 | 2008-11-13 15:20:52 -0800 | [diff] [blame] | 586 | default: |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 587 | v, signed, ok := getInt(field); |
| 588 | if ok { |
| 589 | if signed { |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 590 | p.fmt.fmt_d64(v) |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 591 | } else { |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 592 | if sharp { |
| 593 | p.fmt.sharp = true; // turn on 0x |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 594 | p.fmt.fmt_ux64(uint64(v)); |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 595 | } else { |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 596 | p.fmt.fmt_ud64(uint64(v)) |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 597 | } |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 598 | } |
| 599 | break; |
| 600 | } |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 601 | p.buf.WriteByte('?'); |
| 602 | p.buf.WriteString(field.Type().String()); |
| 603 | p.buf.WriteByte('?'); |
Rob Pike | e2621b8 | 2008-11-13 15:20:52 -0800 | [diff] [blame] | 604 | } |
Rob Pike | e2621b8 | 2008-11-13 15:20:52 -0800 | [diff] [blame] | 605 | return was_string; |
| 606 | } |
| 607 | |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 608 | func (p *pp) doprintf(format string, v *reflect.StructValue) { |
Robert Griesemer | baba292 | 2009-11-09 21:13:17 -0800 | [diff] [blame] | 609 | end := len(format) - 1; |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 610 | fieldnum := 0; // we process one field per non-trivial format |
Russ Cox | ecb863a | 2009-10-06 15:38:57 -0700 | [diff] [blame] | 611 | for i := 0; i <= end; { |
Russ Cox | 9ac4449 | 2009-11-20 11:45:05 -0800 | [diff] [blame] | 612 | c, w := utf8.DecodeRuneInString(format[i:]); |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 613 | if c != '%' || i == end { |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 614 | if w == 1 { |
| 615 | p.buf.WriteByte(byte(c)) |
| 616 | } else { |
| 617 | p.buf.WriteString(format[i : i+w]) |
| 618 | } |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 619 | i += w; |
| 620 | continue; |
| 621 | } |
Russ Cox | 387df5e | 2008-11-24 14:51:33 -0800 | [diff] [blame] | 622 | i++; |
Russ Cox | bf67afc | 2008-12-11 16:53:33 -0800 | [diff] [blame] | 623 | // flags and widths |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 624 | p.fmt.clearflags(); |
Russ Cox | ecb863a | 2009-10-06 15:38:57 -0700 | [diff] [blame] | 625 | F: for ; i < end; i++ { |
Russ Cox | 387df5e | 2008-11-24 14:51:33 -0800 | [diff] [blame] | 626 | switch format[i] { |
| 627 | case '#': |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 628 | p.fmt.sharp = true |
Russ Cox | 387df5e | 2008-11-24 14:51:33 -0800 | [diff] [blame] | 629 | case '0': |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 630 | p.fmt.zero = true |
Russ Cox | 387df5e | 2008-11-24 14:51:33 -0800 | [diff] [blame] | 631 | case '+': |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 632 | p.fmt.plus = true |
Russ Cox | 387df5e | 2008-11-24 14:51:33 -0800 | [diff] [blame] | 633 | case '-': |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 634 | p.fmt.minus = true |
Russ Cox | 387df5e | 2008-11-24 14:51:33 -0800 | [diff] [blame] | 635 | case ' ': |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 636 | p.fmt.space = true |
Russ Cox | 387df5e | 2008-11-24 14:51:33 -0800 | [diff] [blame] | 637 | default: |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 638 | break F |
Russ Cox | 387df5e | 2008-11-24 14:51:33 -0800 | [diff] [blame] | 639 | } |
| 640 | } |
| 641 | // do we have 20 (width)? |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 642 | p.fmt.wid, p.fmt.widPresent, i = parsenum(format, i, end); |
Russ Cox | 387df5e | 2008-11-24 14:51:33 -0800 | [diff] [blame] | 643 | // do we have .20 (precision)? |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 644 | if i < end && format[i] == '.' { |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 645 | p.fmt.prec, p.fmt.precPresent, i = parsenum(format, i+1, end) |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 646 | } |
Russ Cox | 9ac4449 | 2009-11-20 11:45:05 -0800 | [diff] [blame] | 647 | c, w = utf8.DecodeRuneInString(format[i:]); |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 648 | i += w; |
| 649 | // percent is special - absorbs no operand |
| 650 | if c == '%' { |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 651 | p.buf.WriteByte('%'); // TODO: should we bother with width & prec? |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 652 | continue; |
| 653 | } |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 654 | if fieldnum >= v.NumField() { // out of operands |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 655 | p.buf.WriteByte('%'); |
Rob Pike | f15dfa7 | 2008-11-06 10:40:57 -0800 | [diff] [blame] | 656 | p.add(c); |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 657 | p.buf.Write(missingBytes); |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 658 | continue; |
| 659 | } |
Russ Cox | 387df5e | 2008-11-24 14:51:33 -0800 | [diff] [blame] | 660 | field := getField(v, fieldnum); |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 661 | fieldnum++; |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 662 | |
| 663 | // Try formatter except for %T, |
| 664 | // which is special and handled internally. |
Rob Pike | ac09eb4 | 2008-12-11 12:59:49 -0800 | [diff] [blame] | 665 | inter := field.Interface(); |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 666 | if inter != nil && c != 'T' { |
Rob Pike | 28ba977 | 2009-06-23 15:20:30 -0700 | [diff] [blame] | 667 | if formatter, ok := inter.(Formatter); ok { |
Rob Pike | e2621b8 | 2008-11-13 15:20:52 -0800 | [diff] [blame] | 668 | formatter.Format(p, c); |
| 669 | continue; |
| 670 | } |
Rob Pike | f15dfa7 | 2008-11-06 10:40:57 -0800 | [diff] [blame] | 671 | } |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 672 | |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 673 | switch c { |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 674 | // bool |
| 675 | case 't': |
| 676 | if v, ok := getBool(field); ok { |
| 677 | if v { |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 678 | p.buf.Write(trueBytes) |
Rob Pike | 59f029c | 2008-11-01 16:37:53 -0700 | [diff] [blame] | 679 | } else { |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 680 | p.buf.Write(falseBytes) |
Rob Pike | 59f029c | 2008-11-01 16:37:53 -0700 | [diff] [blame] | 681 | } |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 682 | } else { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 683 | goto badtype |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 684 | } |
Rob Pike | 59f029c | 2008-11-01 16:37:53 -0700 | [diff] [blame] | 685 | |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 686 | // int |
| 687 | case 'b': |
Russ Cox | ca6a0fe | 2009-09-15 09:41:59 -0700 | [diff] [blame] | 688 | if v, _, ok := getInt(field); ok { |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 689 | p.fmt.fmt_b64(uint64(v)) // always unsigned |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 690 | } else if v, ok := getFloat32(field); ok { |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 691 | p.fmt.fmt_fb32(v) |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 692 | } else if v, ok := getFloat64(field); ok { |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 693 | p.fmt.fmt_fb64(v) |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 694 | } else { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 695 | goto badtype |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 696 | } |
| 697 | case 'c': |
Russ Cox | ca6a0fe | 2009-09-15 09:41:59 -0700 | [diff] [blame] | 698 | if v, _, ok := getInt(field); ok { |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 699 | p.fmt.fmt_c(int(v)) |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 700 | } else { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 701 | goto badtype |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 702 | } |
| 703 | case 'd': |
| 704 | if v, signed, ok := getInt(field); ok { |
| 705 | if signed { |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 706 | p.fmt.fmt_d64(v) |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 707 | } else { |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 708 | p.fmt.fmt_ud64(uint64(v)) |
Rob Pike | f15dfa7 | 2008-11-06 10:40:57 -0800 | [diff] [blame] | 709 | } |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 710 | } else { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 711 | goto badtype |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 712 | } |
| 713 | case 'o': |
| 714 | if v, signed, ok := getInt(field); ok { |
| 715 | if signed { |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 716 | p.fmt.fmt_o64(v) |
Rob Pike | f15dfa7 | 2008-11-06 10:40:57 -0800 | [diff] [blame] | 717 | } else { |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 718 | p.fmt.fmt_uo64(uint64(v)) |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 719 | } |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 720 | } else { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 721 | goto badtype |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 722 | } |
| 723 | case 'x': |
| 724 | if v, signed, ok := getInt(field); ok { |
| 725 | if signed { |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 726 | p.fmt.fmt_x64(v) |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 727 | } else { |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 728 | p.fmt.fmt_ux64(uint64(v)) |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 729 | } |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 730 | } else if v, ok := getString(field); ok { |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 731 | p.fmt.fmt_sx(v) |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 732 | } else { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 733 | goto badtype |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 734 | } |
| 735 | case 'X': |
| 736 | if v, signed, ok := getInt(field); ok { |
| 737 | if signed { |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 738 | p.fmt.fmt_X64(v) |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 739 | } else { |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 740 | p.fmt.fmt_uX64(uint64(v)) |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 741 | } |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 742 | } else if v, ok := getString(field); ok { |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 743 | p.fmt.fmt_sX(v) |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 744 | } else { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 745 | goto badtype |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 746 | } |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 747 | |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 748 | // float |
| 749 | case 'e': |
| 750 | if v, ok := getFloat32(field); ok { |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 751 | p.fmt.fmt_e32(v) |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 752 | } else if v, ok := getFloat64(field); ok { |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 753 | p.fmt.fmt_e64(v) |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 754 | } else { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 755 | goto badtype |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 756 | } |
| 757 | case 'E': |
| 758 | if v, ok := getFloat32(field); ok { |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 759 | p.fmt.fmt_E32(v) |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 760 | } else if v, ok := getFloat64(field); ok { |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 761 | p.fmt.fmt_E64(v) |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 762 | } else { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 763 | goto badtype |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 764 | } |
| 765 | case 'f': |
| 766 | if v, ok := getFloat32(field); ok { |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 767 | p.fmt.fmt_f32(v) |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 768 | } else if v, ok := getFloat64(field); ok { |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 769 | p.fmt.fmt_f64(v) |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 770 | } else { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 771 | goto badtype |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 772 | } |
| 773 | case 'g': |
| 774 | if v, ok := getFloat32(field); ok { |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 775 | p.fmt.fmt_g32(v) |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 776 | } else if v, ok := getFloat64(field); ok { |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 777 | p.fmt.fmt_g64(v) |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 778 | } else { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 779 | goto badtype |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 780 | } |
| 781 | case 'G': |
| 782 | if v, ok := getFloat32(field); ok { |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 783 | p.fmt.fmt_G32(v) |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 784 | } else if v, ok := getFloat64(field); ok { |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 785 | p.fmt.fmt_G64(v) |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 786 | } else { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 787 | goto badtype |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 788 | } |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 789 | |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 790 | // string |
| 791 | case 's': |
| 792 | if inter != nil { |
| 793 | // if object implements String, use the result. |
| 794 | if stringer, ok := inter.(Stringer); ok { |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 795 | p.fmt.fmt_s(stringer.String()); |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 796 | break; |
Rob Pike | 85647c9 | 2009-03-06 03:35:38 -0800 | [diff] [blame] | 797 | } |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 798 | } |
| 799 | if v, ok := getString(field); ok { |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 800 | p.fmt.fmt_s(v) |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 801 | } else { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 802 | goto badtype |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 803 | } |
| 804 | case 'q': |
| 805 | if v, ok := getString(field); ok { |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 806 | p.fmt.fmt_q(v) |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 807 | } else { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 808 | goto badtype |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 809 | } |
| 810 | |
| 811 | // pointer |
| 812 | case 'p': |
| 813 | if v, ok := getPtr(field); ok { |
| 814 | if v == 0 { |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 815 | p.buf.Write(nilAngleBytes) |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 816 | } else { |
Rob Pike | 353ef80 | 2009-12-06 12:58:16 -0800 | [diff] [blame] | 817 | p.fmt.fmt_s("0x"); |
| 818 | p.fmt.fmt_uX64(uint64(v)); |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 819 | } |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 820 | } else { |
Robert Griesemer | 40621d5 | 2009-11-09 12:07:39 -0800 | [diff] [blame] | 821 | goto badtype |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 822 | } |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 823 | |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 824 | // 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 Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 830 | |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 831 | // the value's type |
| 832 | case 'T': |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 833 | p.buf.WriteString(field.Type().String()) |
Rob Pike | e2621b8 | 2008-11-13 15:20:52 -0800 | [diff] [blame] | 834 | |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 835 | default: |
| 836 | badtype: |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 837 | p.buf.WriteByte('%'); |
| 838 | p.add(c); |
| 839 | p.buf.WriteByte('('); |
| 840 | p.buf.WriteString(field.Type().String()); |
| 841 | p.buf.WriteByte('='); |
Russ Cox | 8f2bf20 | 2009-09-10 14:18:53 -0700 | [diff] [blame] | 842 | p.printField(field, false, false, 0); |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 843 | p.buf.WriteByte(')'); |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 844 | } |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 845 | } |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 846 | if fieldnum < v.NumField() { |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 847 | p.buf.Write(extraBytes); |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 848 | for ; fieldnum < v.NumField(); fieldnum++ { |
Rob Pike | c6540d3 | 2009-08-28 13:02:34 -0700 | [diff] [blame] | 849 | field := getField(v, fieldnum); |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 850 | p.buf.WriteString(field.Type().String()); |
| 851 | p.buf.WriteByte('='); |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 852 | p.printField(field, false, false, 0); |
Russ Cox | ecb863a | 2009-10-06 15:38:57 -0700 | [diff] [blame] | 853 | if fieldnum+1 < v.NumField() { |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 854 | p.buf.Write(commaSpaceBytes) |
Rob Pike | f15dfa7 | 2008-11-06 10:40:57 -0800 | [diff] [blame] | 855 | } |
| 856 | } |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 857 | p.buf.WriteByte(')'); |
Rob Pike | f15dfa7 | 2008-11-06 10:40:57 -0800 | [diff] [blame] | 858 | } |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 859 | } |
| 860 | |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 861 | func (p *pp) doprint(v *reflect.StructValue, addspace, addnewline bool) { |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 862 | prev_string := false; |
Russ Cox | ecb863a | 2009-10-06 15:38:57 -0700 | [diff] [blame] | 863 | for fieldnum := 0; fieldnum < v.NumField(); fieldnum++ { |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 864 | // always add spaces if we're doing println |
Russ Cox | 387df5e | 2008-11-24 14:51:33 -0800 | [diff] [blame] | 865 | field := getField(v, fieldnum); |
Rob Pike | 2d4f7ba | 2008-11-02 12:33:02 -0800 | [diff] [blame] | 866 | if fieldnum > 0 { |
Russ Cox | 0d400a7 | 2009-07-07 11:03:31 -0700 | [diff] [blame] | 867 | _, is_string := field.(*reflect.StringValue); |
| 868 | if addspace || !is_string && !prev_string { |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 869 | p.buf.WriteByte(' ') |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 870 | } |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 871 | } |
Russ Cox | a843b45 | 2009-08-31 16:38:30 -0700 | [diff] [blame] | 872 | prev_string = p.printField(field, false, false, 0); |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 873 | } |
Rob Pike | 2d4f7ba | 2008-11-02 12:33:02 -0800 | [diff] [blame] | 874 | if addnewline { |
Rob Pike | 4c0e51c | 2009-12-06 12:03:52 -0800 | [diff] [blame] | 875 | p.buf.WriteByte('\n') |
Rob Pike | 418b97c | 2008-10-24 16:33:29 -0700 | [diff] [blame] | 876 | } |
| 877 | } |