The Go Programming Language

Source file src/pkg/fmt/format.go

     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	
     5	package fmt
     6	
     7	import (
     8		"bytes"
     9		"strconv"
    10		"unicode"
    11		"utf8"
    12	)
    13	
    14	const (
    15		nByte = 64
    16	
    17		ldigits = "0123456789abcdef"
    18		udigits = "0123456789ABCDEF"
    19	)
    20	
    21	const (
    22		signed   = true
    23		unsigned = false
    24	)
    25	
    26	var padZeroBytes = make([]byte, nByte)
    27	var padSpaceBytes = make([]byte, nByte)
    28	
    29	var newline = []byte{'\n'}
    30	
    31	func init() {
    32		for i := 0; i < nByte; i++ {
    33			padZeroBytes[i] = '0'
    34			padSpaceBytes[i] = ' '
    35		}
    36	}
    37	
    38	// A fmt is the raw formatter used by Printf etc.
    39	// It prints into a bytes.Buffer that must be set up externally.
    40	type fmt struct {
    41		intbuf [nByte]byte
    42		buf    *bytes.Buffer
    43		// width, precision
    44		wid  int
    45		prec int
    46		// flags
    47		widPresent  bool
    48		precPresent bool
    49		minus       bool
    50		plus        bool
    51		sharp       bool
    52		space       bool
    53		unicode     bool
    54		uniQuote    bool // Use 'x'= prefix for %U if printable.
    55		zero        bool
    56	}
    57	
    58	func (f *fmt) clearflags() {
    59		f.wid = 0
    60		f.widPresent = false
    61		f.prec = 0
    62		f.precPresent = false
    63		f.minus = false
    64		f.plus = false
    65		f.sharp = false
    66		f.space = false
    67		f.unicode = false
    68		f.uniQuote = false
    69		f.zero = false
    70	}
    71	
    72	func (f *fmt) init(buf *bytes.Buffer) {
    73		f.buf = buf
    74		f.clearflags()
    75	}
    76	
    77	// Compute left and right padding widths (only one will be non-zero).
    78	func (f *fmt) computePadding(width int) (padding []byte, leftWidth, rightWidth int) {
    79		left := !f.minus
    80		w := f.wid
    81		if w < 0 {
    82			left = false
    83			w = -w
    84		}
    85		w -= width
    86		if w > 0 {
    87			if left && f.zero {
    88				return padZeroBytes, w, 0
    89			}
    90			if left {
    91				return padSpaceBytes, w, 0
    92			} else {
    93				// can't be zero padding on the right
    94				return padSpaceBytes, 0, w
    95			}
    96		}
    97		return
    98	}
    99	
   100	// Generate n bytes of padding.
   101	func (f *fmt) writePadding(n int, padding []byte) {
   102		for n > 0 {
   103			m := n
   104			if m > nByte {
   105				m = nByte
   106			}
   107			f.buf.Write(padding[0:m])
   108			n -= m
   109		}
   110	}
   111	
   112	// Append b to f.buf, padded on left (w > 0) or right (w < 0 or f.minus)
   113	// clear flags afterwards.
   114	func (f *fmt) pad(b []byte) {
   115		var padding []byte
   116		var left, right int
   117		if f.widPresent && f.wid != 0 {
   118			padding, left, right = f.computePadding(len(b))
   119		}
   120		if left > 0 {
   121			f.writePadding(left, padding)
   122		}
   123		f.buf.Write(b)
   124		if right > 0 {
   125			f.writePadding(right, padding)
   126		}
   127	}
   128	
   129	// append s to buf, padded on left (w > 0) or right (w < 0 or f.minus).
   130	// clear flags afterwards.
   131	func (f *fmt) padString(s string) {
   132		var padding []byte
   133		var left, right int
   134		if f.widPresent && f.wid != 0 {
   135			padding, left, right = f.computePadding(utf8.RuneCountInString(s))
   136		}
   137		if left > 0 {
   138			f.writePadding(left, padding)
   139		}
   140		f.buf.WriteString(s)
   141		if right > 0 {
   142			f.writePadding(right, padding)
   143		}
   144	}
   145	
   146	func putint(buf []byte, base, val uint64, digits string) int {
   147		i := len(buf) - 1
   148		for val >= base {
   149			buf[i] = digits[val%base]
   150			i--
   151			val /= base
   152		}
   153		buf[i] = digits[val]
   154		return i - 1
   155	}
   156	
   157	// fmt_boolean formats a boolean.
   158	func (f *fmt) fmt_boolean(v bool) {
   159		if v {
   160			f.padString("true")
   161		} else {
   162			f.padString("false")
   163		}
   164	}
   165	
   166	// integer; interprets prec but not wid.  Once formatted, result is sent to pad()
   167	// and then flags are cleared.
   168	func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
   169		// precision of 0 and value of 0 means "print nothing"
   170		if f.precPresent && f.prec == 0 && a == 0 {
   171			return
   172		}
   173	
   174		var buf []byte = f.intbuf[0:]
   175		negative := signedness == signed && a < 0
   176		if negative {
   177			a = -a
   178		}
   179	
   180		// two ways to ask for extra leading zero digits: %.3d or %03d.
   181		// apparently the first cancels the second.
   182		prec := 0
   183		if f.precPresent {
   184			prec = f.prec
   185			f.zero = false
   186		} else if f.zero && f.widPresent && !f.minus && f.wid > 0 {
   187			prec = f.wid
   188			if negative || f.plus || f.space {
   189				prec-- // leave room for sign
   190			}
   191		}
   192	
   193		// format a into buf, ending at buf[i].  (printing is easier right-to-left.)
   194		// a is made into unsigned ua.  we could make things
   195		// marginally faster by splitting the 32-bit case out into a separate
   196		// block but it's not worth the duplication, so ua has 64 bits.
   197		i := len(f.intbuf)
   198		ua := uint64(a)
   199		for ua >= base {
   200			i--
   201			buf[i] = digits[ua%base]
   202			ua /= base
   203		}
   204		i--
   205		buf[i] = digits[ua]
   206		for i > 0 && prec > nByte-i {
   207			i--
   208			buf[i] = '0'
   209		}
   210	
   211		// Various prefixes: 0x, -, etc.
   212		if f.sharp {
   213			switch base {
   214			case 8:
   215				if buf[i] != '0' {
   216					i--
   217					buf[i] = '0'
   218				}
   219			case 16:
   220				i--
   221				buf[i] = 'x' + digits[10] - 'a'
   222				i--
   223				buf[i] = '0'
   224			}
   225		}
   226		if f.unicode {
   227			i--
   228			buf[i] = '+'
   229			i--
   230			buf[i] = 'U'
   231		}
   232	
   233		if negative {
   234			i--
   235			buf[i] = '-'
   236		} else if f.plus {
   237			i--
   238			buf[i] = '+'
   239		} else if f.space {
   240			i--
   241			buf[i] = ' '
   242		}
   243	
   244		// If we want a quoted char for %#U, move the data up to make room.
   245		if f.unicode && f.uniQuote && a >= 0 && a <= unicode.MaxRune && unicode.IsPrint(int(a)) {
   246			runeWidth := utf8.RuneLen(int(a))
   247			width := 1 + 1 + runeWidth + 1 // space, quote, rune, quote
   248			copy(buf[i-width:], buf[i:])   // guaranteed to have enough room.
   249			i -= width
   250			// Now put " 'x'" at the end.
   251			j := len(buf) - width
   252			buf[j] = ' '
   253			j++
   254			buf[j] = '\''
   255			j++
   256			utf8.EncodeRune(buf[j:], int(a))
   257			j += runeWidth
   258			buf[j] = '\''
   259		}
   260	
   261		f.pad(buf[i:])
   262	}
   263	
   264	// truncate truncates the string to the specified precision, if present.
   265	func (f *fmt) truncate(s string) string {
   266		if f.precPresent && f.prec < utf8.RuneCountInString(s) {
   267			n := f.prec
   268			for i := range s {
   269				if n == 0 {
   270					s = s[:i]
   271					break
   272				}
   273				n--
   274			}
   275		}
   276		return s
   277	}
   278	
   279	// fmt_s formats a string.
   280	func (f *fmt) fmt_s(s string) {
   281		s = f.truncate(s)
   282		f.padString(s)
   283	}
   284	
   285	// fmt_sx formats a string as a hexadecimal encoding of its bytes.
   286	func (f *fmt) fmt_sx(s string) {
   287		t := ""
   288		for i := 0; i < len(s); i++ {
   289			if i > 0 && f.space {
   290				t += " "
   291			}
   292			v := s[i]
   293			t += string(ldigits[v>>4])
   294			t += string(ldigits[v&0xF])
   295		}
   296		f.padString(t)
   297	}
   298	
   299	// fmt_sX formats a string as an uppercase hexadecimal encoding of its bytes.
   300	func (f *fmt) fmt_sX(s string) {
   301		t := ""
   302		for i := 0; i < len(s); i++ {
   303			if i > 0 && f.space {
   304				t += " "
   305			}
   306			v := s[i]
   307			t += string(udigits[v>>4])
   308			t += string(udigits[v&0xF])
   309		}
   310		f.padString(t)
   311	}
   312	
   313	// fmt_q formats a string as a double-quoted, escaped Go string constant.
   314	func (f *fmt) fmt_q(s string) {
   315		s = f.truncate(s)
   316		var quoted string
   317		if f.sharp && strconv.CanBackquote(s) {
   318			quoted = "`" + s + "`"
   319		} else {
   320			if f.plus {
   321				quoted = strconv.QuoteToASCII(s)
   322			} else {
   323				quoted = strconv.Quote(s)
   324			}
   325		}
   326		f.padString(quoted)
   327	}
   328	
   329	// fmt_qc formats the integer as a single-quoted, escaped Go character constant.
   330	// If the character is not valid Unicode, it will print '\ufffd'.
   331	func (f *fmt) fmt_qc(c int64) {
   332		var quoted string
   333		if f.plus {
   334			quoted = strconv.QuoteRuneToASCII(int(c))
   335		} else {
   336			quoted = strconv.QuoteRune(int(c))
   337		}
   338		f.padString(quoted)
   339	}
   340	
   341	// floating-point
   342	
   343	func doPrec(f *fmt, def int) int {
   344		if f.precPresent {
   345			return f.prec
   346		}
   347		return def
   348	}
   349	
   350	// Add a plus sign or space to the floating-point string representation if missing and required.
   351	func (f *fmt) plusSpace(s string) {
   352		if s[0] != '-' {
   353			if f.plus {
   354				s = "+" + s
   355			} else if f.space {
   356				s = " " + s
   357			}
   358		}
   359		f.padString(s)
   360	}
   361	
   362	// fmt_e64 formats a float64 in the form -1.23e+12.
   363	func (f *fmt) fmt_e64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'e', doPrec(f, 6))) }
   364	
   365	// fmt_E64 formats a float64 in the form -1.23E+12.
   366	func (f *fmt) fmt_E64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'E', doPrec(f, 6))) }
   367	
   368	// fmt_f64 formats a float64 in the form -1.23.
   369	func (f *fmt) fmt_f64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'f', doPrec(f, 6))) }
   370	
   371	// fmt_g64 formats a float64 in the 'f' or 'e' form according to size.
   372	func (f *fmt) fmt_g64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'g', doPrec(f, -1))) }
   373	
   374	// fmt_g64 formats a float64 in the 'f' or 'E' form according to size.
   375	func (f *fmt) fmt_G64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'G', doPrec(f, -1))) }
   376	
   377	// fmt_fb64 formats a float64 in the form -123p3 (exponent is power of 2).
   378	func (f *fmt) fmt_fb64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'b', 0)) }
   379	
   380	// float32
   381	// cannot defer to float64 versions
   382	// because it will get rounding wrong in corner cases.
   383	
   384	// fmt_e32 formats a float32 in the form -1.23e+12.
   385	func (f *fmt) fmt_e32(v float32) { f.plusSpace(strconv.Ftoa32(v, 'e', doPrec(f, 6))) }
   386	
   387	// fmt_E32 formats a float32 in the form -1.23E+12.
   388	func (f *fmt) fmt_E32(v float32) { f.plusSpace(strconv.Ftoa32(v, 'E', doPrec(f, 6))) }
   389	
   390	// fmt_f32 formats a float32 in the form -1.23.
   391	func (f *fmt) fmt_f32(v float32) { f.plusSpace(strconv.Ftoa32(v, 'f', doPrec(f, 6))) }
   392	
   393	// fmt_g32 formats a float32 in the 'f' or 'e' form according to size.
   394	func (f *fmt) fmt_g32(v float32) { f.plusSpace(strconv.Ftoa32(v, 'g', doPrec(f, -1))) }
   395	
   396	// fmt_G32 formats a float32 in the 'f' or 'E' form according to size.
   397	func (f *fmt) fmt_G32(v float32) { f.plusSpace(strconv.Ftoa32(v, 'G', doPrec(f, -1))) }
   398	
   399	// fmt_fb32 formats a float32 in the form -123p3 (exponent is power of 2).
   400	func (f *fmt) fmt_fb32(v float32) { f.padString(strconv.Ftoa32(v, 'b', 0)) }
   401	
   402	// fmt_c64 formats a complex64 according to the verb.
   403	func (f *fmt) fmt_c64(v complex64, verb int) {
   404		f.buf.WriteByte('(')
   405		r := real(v)
   406		for i := 0; ; i++ {
   407			switch verb {
   408			case 'e':
   409				f.fmt_e32(r)
   410			case 'E':
   411				f.fmt_E32(r)
   412			case 'f':
   413				f.fmt_f32(r)
   414			case 'g':
   415				f.fmt_g32(r)
   416			case 'G':
   417				f.fmt_G32(r)
   418			}
   419			if i != 0 {
   420				break
   421			}
   422			f.plus = true
   423			r = imag(v)
   424		}
   425		f.buf.Write(irparenBytes)
   426	}
   427	
   428	// fmt_c128 formats a complex128 according to the verb.
   429	func (f *fmt) fmt_c128(v complex128, verb int) {
   430		f.buf.WriteByte('(')
   431		r := real(v)
   432		for i := 0; ; i++ {
   433			switch verb {
   434			case 'e':
   435				f.fmt_e64(r)
   436			case 'E':
   437				f.fmt_E64(r)
   438			case 'f':
   439				f.fmt_f64(r)
   440			case 'g':
   441				f.fmt_g64(r)
   442			case 'G':
   443				f.fmt_G64(r)
   444			}
   445			if i != 0 {
   446				break
   447			}
   448			f.plus = true
   449			r = imag(v)
   450		}
   451		f.buf.Write(irparenBytes)
   452	}

release.r60.3. Except as noted, this content is licensed under a Creative Commons Attribution 3.0 License.