1// Copyright 2017 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
5package message
6
7import (
8	"bytes"
9	"strconv"
10	"unicode/utf8"
11
12	"golang.org/x/text/internal/format"
13)
14
15const (
16	ldigits = "0123456789abcdefx"
17	udigits = "0123456789ABCDEFX"
18)
19
20const (
21	signed   = true
22	unsigned = false
23)
24
25// A formatInfo is the raw formatter used by Printf etc.
26// It prints into a buffer that must be set up separately.
27type formatInfo struct {
28	buf *bytes.Buffer
29
30	format.Parser
31
32	// intbuf is large enough to store %b of an int64 with a sign and
33	// avoids padding at the end of the struct on 32 bit architectures.
34	intbuf [68]byte
35}
36
37func (f *formatInfo) init(buf *bytes.Buffer) {
38	f.ClearFlags()
39	f.buf = buf
40}
41
42// writePadding generates n bytes of padding.
43func (f *formatInfo) writePadding(n int) {
44	if n <= 0 { // No padding bytes needed.
45		return
46	}
47	f.buf.Grow(n)
48	// Decide which byte the padding should be filled with.
49	padByte := byte(' ')
50	if f.Zero {
51		padByte = byte('0')
52	}
53	// Fill padding with padByte.
54	for i := 0; i < n; i++ {
55		f.buf.WriteByte(padByte) // TODO: make more efficient.
56	}
57}
58
59// pad appends b to f.buf, padded on left (!f.minus) or right (f.minus).
60func (f *formatInfo) pad(b []byte) {
61	if !f.WidthPresent || f.Width == 0 {
62		f.buf.Write(b)
63		return
64	}
65	width := f.Width - utf8.RuneCount(b)
66	if !f.Minus {
67		// left padding
68		f.writePadding(width)
69		f.buf.Write(b)
70	} else {
71		// right padding
72		f.buf.Write(b)
73		f.writePadding(width)
74	}
75}
76
77// padString appends s to f.buf, padded on left (!f.minus) or right (f.minus).
78func (f *formatInfo) padString(s string) {
79	if !f.WidthPresent || f.Width == 0 {
80		f.buf.WriteString(s)
81		return
82	}
83	width := f.Width - utf8.RuneCountInString(s)
84	if !f.Minus {
85		// left padding
86		f.writePadding(width)
87		f.buf.WriteString(s)
88	} else {
89		// right padding
90		f.buf.WriteString(s)
91		f.writePadding(width)
92	}
93}
94
95// fmt_boolean formats a boolean.
96func (f *formatInfo) fmt_boolean(v bool) {
97	if v {
98		f.padString("true")
99	} else {
100		f.padString("false")
101	}
102}
103
104// fmt_unicode formats a uint64 as "U+0078" or with f.sharp set as "U+0078 'x'".
105func (f *formatInfo) fmt_unicode(u uint64) {
106	buf := f.intbuf[0:]
107
108	// With default precision set the maximum needed buf length is 18
109	// for formatting -1 with %#U ("U+FFFFFFFFFFFFFFFF") which fits
110	// into the already allocated intbuf with a capacity of 68 bytes.
111	prec := 4
112	if f.PrecPresent && f.Prec > 4 {
113		prec = f.Prec
114		// Compute space needed for "U+" , number, " '", character, "'".
115		width := 2 + prec + 2 + utf8.UTFMax + 1
116		if width > len(buf) {
117			buf = make([]byte, width)
118		}
119	}
120
121	// Format into buf, ending at buf[i]. Formatting numbers is easier right-to-left.
122	i := len(buf)
123
124	// For %#U we want to add a space and a quoted character at the end of the buffer.
125	if f.Sharp && u <= utf8.MaxRune && strconv.IsPrint(rune(u)) {
126		i--
127		buf[i] = '\''
128		i -= utf8.RuneLen(rune(u))
129		utf8.EncodeRune(buf[i:], rune(u))
130		i--
131		buf[i] = '\''
132		i--
133		buf[i] = ' '
134	}
135	// Format the Unicode code point u as a hexadecimal number.
136	for u >= 16 {
137		i--
138		buf[i] = udigits[u&0xF]
139		prec--
140		u >>= 4
141	}
142	i--
143	buf[i] = udigits[u]
144	prec--
145	// Add zeros in front of the number until requested precision is reached.
146	for prec > 0 {
147		i--
148		buf[i] = '0'
149		prec--
150	}
151	// Add a leading "U+".
152	i--
153	buf[i] = '+'
154	i--
155	buf[i] = 'U'
156
157	oldZero := f.Zero
158	f.Zero = false
159	f.pad(buf[i:])
160	f.Zero = oldZero
161}
162
163// fmt_integer formats signed and unsigned integers.
164func (f *formatInfo) fmt_integer(u uint64, base int, isSigned bool, digits string) {
165	negative := isSigned && int64(u) < 0
166	if negative {
167		u = -u
168	}
169
170	buf := f.intbuf[0:]
171	// The already allocated f.intbuf with a capacity of 68 bytes
172	// is large enough for integer formatting when no precision or width is set.
173	if f.WidthPresent || f.PrecPresent {
174		// Account 3 extra bytes for possible addition of a sign and "0x".
175		width := 3 + f.Width + f.Prec // wid and prec are always positive.
176		if width > len(buf) {
177			// We're going to need a bigger boat.
178			buf = make([]byte, width)
179		}
180	}
181
182	// Two ways to ask for extra leading zero digits: %.3d or %03d.
183	// If both are specified the f.zero flag is ignored and
184	// padding with spaces is used instead.
185	prec := 0
186	if f.PrecPresent {
187		prec = f.Prec
188		// Precision of 0 and value of 0 means "print nothing" but padding.
189		if prec == 0 && u == 0 {
190			oldZero := f.Zero
191			f.Zero = false
192			f.writePadding(f.Width)
193			f.Zero = oldZero
194			return
195		}
196	} else if f.Zero && f.WidthPresent {
197		prec = f.Width
198		if negative || f.Plus || f.Space {
199			prec-- // leave room for sign
200		}
201	}
202
203	// Because printing is easier right-to-left: format u into buf, ending at buf[i].
204	// We could make things marginally faster by splitting the 32-bit case out
205	// into a separate block but it's not worth the duplication, so u has 64 bits.
206	i := len(buf)
207	// Use constants for the division and modulo for more efficient code.
208	// Switch cases ordered by popularity.
209	switch base {
210	case 10:
211		for u >= 10 {
212			i--
213			next := u / 10
214			buf[i] = byte('0' + u - next*10)
215			u = next
216		}
217	case 16:
218		for u >= 16 {
219			i--
220			buf[i] = digits[u&0xF]
221			u >>= 4
222		}
223	case 8:
224		for u >= 8 {
225			i--
226			buf[i] = byte('0' + u&7)
227			u >>= 3
228		}
229	case 2:
230		for u >= 2 {
231			i--
232			buf[i] = byte('0' + u&1)
233			u >>= 1
234		}
235	default:
236		panic("fmt: unknown base; can't happen")
237	}
238	i--
239	buf[i] = digits[u]
240	for i > 0 && prec > len(buf)-i {
241		i--
242		buf[i] = '0'
243	}
244
245	// Various prefixes: 0x, -, etc.
246	if f.Sharp {
247		switch base {
248		case 8:
249			if buf[i] != '0' {
250				i--
251				buf[i] = '0'
252			}
253		case 16:
254			// Add a leading 0x or 0X.
255			i--
256			buf[i] = digits[16]
257			i--
258			buf[i] = '0'
259		}
260	}
261
262	if negative {
263		i--
264		buf[i] = '-'
265	} else if f.Plus {
266		i--
267		buf[i] = '+'
268	} else if f.Space {
269		i--
270		buf[i] = ' '
271	}
272
273	// Left padding with zeros has already been handled like precision earlier
274	// or the f.zero flag is ignored due to an explicitly set precision.
275	oldZero := f.Zero
276	f.Zero = false
277	f.pad(buf[i:])
278	f.Zero = oldZero
279}
280
281// truncate truncates the string to the specified precision, if present.
282func (f *formatInfo) truncate(s string) string {
283	if f.PrecPresent {
284		n := f.Prec
285		for i := range s {
286			n--
287			if n < 0 {
288				return s[:i]
289			}
290		}
291	}
292	return s
293}
294
295// fmt_s formats a string.
296func (f *formatInfo) fmt_s(s string) {
297	s = f.truncate(s)
298	f.padString(s)
299}
300
301// fmt_sbx formats a string or byte slice as a hexadecimal encoding of its bytes.
302func (f *formatInfo) fmt_sbx(s string, b []byte, digits string) {
303	length := len(b)
304	if b == nil {
305		// No byte slice present. Assume string s should be encoded.
306		length = len(s)
307	}
308	// Set length to not process more bytes than the precision demands.
309	if f.PrecPresent && f.Prec < length {
310		length = f.Prec
311	}
312	// Compute width of the encoding taking into account the f.sharp and f.space flag.
313	width := 2 * length
314	if width > 0 {
315		if f.Space {
316			// Each element encoded by two hexadecimals will get a leading 0x or 0X.
317			if f.Sharp {
318				width *= 2
319			}
320			// Elements will be separated by a space.
321			width += length - 1
322		} else if f.Sharp {
323			// Only a leading 0x or 0X will be added for the whole string.
324			width += 2
325		}
326	} else { // The byte slice or string that should be encoded is empty.
327		if f.WidthPresent {
328			f.writePadding(f.Width)
329		}
330		return
331	}
332	// Handle padding to the left.
333	if f.WidthPresent && f.Width > width && !f.Minus {
334		f.writePadding(f.Width - width)
335	}
336	// Write the encoding directly into the output buffer.
337	buf := f.buf
338	if f.Sharp {
339		// Add leading 0x or 0X.
340		buf.WriteByte('0')
341		buf.WriteByte(digits[16])
342	}
343	var c byte
344	for i := 0; i < length; i++ {
345		if f.Space && i > 0 {
346			// Separate elements with a space.
347			buf.WriteByte(' ')
348			if f.Sharp {
349				// Add leading 0x or 0X for each element.
350				buf.WriteByte('0')
351				buf.WriteByte(digits[16])
352			}
353		}
354		if b != nil {
355			c = b[i] // Take a byte from the input byte slice.
356		} else {
357			c = s[i] // Take a byte from the input string.
358		}
359		// Encode each byte as two hexadecimal digits.
360		buf.WriteByte(digits[c>>4])
361		buf.WriteByte(digits[c&0xF])
362	}
363	// Handle padding to the right.
364	if f.WidthPresent && f.Width > width && f.Minus {
365		f.writePadding(f.Width - width)
366	}
367}
368
369// fmt_sx formats a string as a hexadecimal encoding of its bytes.
370func (f *formatInfo) fmt_sx(s, digits string) {
371	f.fmt_sbx(s, nil, digits)
372}
373
374// fmt_bx formats a byte slice as a hexadecimal encoding of its bytes.
375func (f *formatInfo) fmt_bx(b []byte, digits string) {
376	f.fmt_sbx("", b, digits)
377}
378
379// fmt_q formats a string as a double-quoted, escaped Go string constant.
380// If f.sharp is set a raw (backquoted) string may be returned instead
381// if the string does not contain any control characters other than tab.
382func (f *formatInfo) fmt_q(s string) {
383	s = f.truncate(s)
384	if f.Sharp && strconv.CanBackquote(s) {
385		f.padString("`" + s + "`")
386		return
387	}
388	buf := f.intbuf[:0]
389	if f.Plus {
390		f.pad(strconv.AppendQuoteToASCII(buf, s))
391	} else {
392		f.pad(strconv.AppendQuote(buf, s))
393	}
394}
395
396// fmt_c formats an integer as a Unicode character.
397// If the character is not valid Unicode, it will print '\ufffd'.
398func (f *formatInfo) fmt_c(c uint64) {
399	r := rune(c)
400	if c > utf8.MaxRune {
401		r = utf8.RuneError
402	}
403	buf := f.intbuf[:0]
404	w := utf8.EncodeRune(buf[:utf8.UTFMax], r)
405	f.pad(buf[:w])
406}
407
408// fmt_qc formats an integer as a single-quoted, escaped Go character constant.
409// If the character is not valid Unicode, it will print '\ufffd'.
410func (f *formatInfo) fmt_qc(c uint64) {
411	r := rune(c)
412	if c > utf8.MaxRune {
413		r = utf8.RuneError
414	}
415	buf := f.intbuf[:0]
416	if f.Plus {
417		f.pad(strconv.AppendQuoteRuneToASCII(buf, r))
418	} else {
419		f.pad(strconv.AppendQuoteRune(buf, r))
420	}
421}
422
423// fmt_float formats a float64. It assumes that verb is a valid format specifier
424// for strconv.AppendFloat and therefore fits into a byte.
425func (f *formatInfo) fmt_float(v float64, size int, verb rune, prec int) {
426	// Explicit precision in format specifier overrules default precision.
427	if f.PrecPresent {
428		prec = f.Prec
429	}
430	// Format number, reserving space for leading + sign if needed.
431	num := strconv.AppendFloat(f.intbuf[:1], v, byte(verb), prec, size)
432	if num[1] == '-' || num[1] == '+' {
433		num = num[1:]
434	} else {
435		num[0] = '+'
436	}
437	// f.space means to add a leading space instead of a "+" sign unless
438	// the sign is explicitly asked for by f.plus.
439	if f.Space && num[0] == '+' && !f.Plus {
440		num[0] = ' '
441	}
442	// Special handling for infinities and NaN,
443	// which don't look like a number so shouldn't be padded with zeros.
444	if num[1] == 'I' || num[1] == 'N' {
445		oldZero := f.Zero
446		f.Zero = false
447		// Remove sign before NaN if not asked for.
448		if num[1] == 'N' && !f.Space && !f.Plus {
449			num = num[1:]
450		}
451		f.pad(num)
452		f.Zero = oldZero
453		return
454	}
455	// The sharp flag forces printing a decimal point for non-binary formats
456	// and retains trailing zeros, which we may need to restore.
457	if f.Sharp && verb != 'b' {
458		digits := 0
459		switch verb {
460		case 'v', 'g', 'G':
461			digits = prec
462			// If no precision is set explicitly use a precision of 6.
463			if digits == -1 {
464				digits = 6
465			}
466		}
467
468		// Buffer pre-allocated with enough room for
469		// exponent notations of the form "e+123".
470		var tailBuf [5]byte
471		tail := tailBuf[:0]
472
473		hasDecimalPoint := false
474		// Starting from i = 1 to skip sign at num[0].
475		for i := 1; i < len(num); i++ {
476			switch num[i] {
477			case '.':
478				hasDecimalPoint = true
479			case 'e', 'E':
480				tail = append(tail, num[i:]...)
481				num = num[:i]
482			default:
483				digits--
484			}
485		}
486		if !hasDecimalPoint {
487			num = append(num, '.')
488		}
489		for digits > 0 {
490			num = append(num, '0')
491			digits--
492		}
493		num = append(num, tail...)
494	}
495	// We want a sign if asked for and if the sign is not positive.
496	if f.Plus || num[0] != '+' {
497		// If we're zero padding to the left we want the sign before the leading zeros.
498		// Achieve this by writing the sign out and then padding the unsigned number.
499		if f.Zero && f.WidthPresent && f.Width > len(num) {
500			f.buf.WriteByte(num[0])
501			f.writePadding(f.Width - len(num))
502			f.buf.Write(num[1:])
503			return
504		}
505		f.pad(num)
506		return
507	}
508	// No sign to show and the number is positive; just print the unsigned number.
509	f.pad(num[1:])
510}
511