| 
									
										
										
										
											2021-08-29 15:41:41 +01:00
										 |  |  |  | // Copyright 2020 The Libc Authors. All rights reserved. | 
					
						
							|  |  |  |  | // Use of this source code is governed by a BSD-style | 
					
						
							|  |  |  |  | // license that can be found in the LICENSE file. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | package libc // import "modernc.org/libc" | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | import ( | 
					
						
							|  |  |  |  | 	"bytes" | 
					
						
							|  |  |  |  | 	"fmt" | 
					
						
							|  |  |  |  | 	"strconv" | 
					
						
							|  |  |  |  | 	"strings" | 
					
						
							|  |  |  |  | 	"unsafe" | 
					
						
							|  |  |  |  | ) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | const ( | 
					
						
							|  |  |  |  | 	modNone = iota | 
					
						
							|  |  |  |  | 	modHH | 
					
						
							|  |  |  |  | 	modH | 
					
						
							|  |  |  |  | 	modL | 
					
						
							|  |  |  |  | 	modLL | 
					
						
							|  |  |  |  | 	modQ | 
					
						
							|  |  |  |  | 	modCapitalL | 
					
						
							|  |  |  |  | 	modJ | 
					
						
							|  |  |  |  | 	modZ | 
					
						
							|  |  |  |  | 	modCapitalZ | 
					
						
							|  |  |  |  | 	modT | 
					
						
							|  |  |  |  | 	mod32 | 
					
						
							|  |  |  |  | 	mod64 | 
					
						
							|  |  |  |  | ) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // Format of the format string | 
					
						
							|  |  |  |  | // | 
					
						
							|  |  |  |  | // The format string is a character string, beginning and ending in its initial | 
					
						
							|  |  |  |  | // shift state, if any.  The format string is composed of zero or more | 
					
						
							|  |  |  |  | // directives: ordinary  characters  (not  %), which  are  copied unchanged to | 
					
						
							|  |  |  |  | // the output stream; and conversion specifications, each of which results in | 
					
						
							|  |  |  |  | // fetching zero or more subsequent arguments. | 
					
						
							|  |  |  |  | func printf(format, args uintptr) []byte { | 
					
						
							|  |  |  |  | 	buf := bytes.NewBuffer(nil) | 
					
						
							|  |  |  |  | 	for { | 
					
						
							|  |  |  |  | 		switch c := *(*byte)(unsafe.Pointer(format)); c { | 
					
						
							|  |  |  |  | 		case '%': | 
					
						
							|  |  |  |  | 			format = printfConversion(buf, format, &args) | 
					
						
							|  |  |  |  | 		case 0: | 
					
						
							| 
									
										
										
										
											2021-09-08 21:12:23 +01:00
										 |  |  |  | 			if dmesgs { | 
					
						
							|  |  |  |  | 				dmesg("%v: %q", origin(1), buf.Bytes()) | 
					
						
							|  |  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2021-08-29 15:41:41 +01:00
										 |  |  |  | 			return buf.Bytes() | 
					
						
							|  |  |  |  | 		default: | 
					
						
							|  |  |  |  | 			format++ | 
					
						
							|  |  |  |  | 			buf.WriteByte(c) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // Each conversion specification is introduced by the character %, and ends | 
					
						
							|  |  |  |  | // with a conversion specifier.  In between there may be (in this order) zero | 
					
						
							|  |  |  |  | // or more flags, an optional minimum field width, an optional  precision  and | 
					
						
							|  |  |  |  | // an optional length modifier. | 
					
						
							|  |  |  |  | func printfConversion(buf *bytes.Buffer, format uintptr, args *uintptr) uintptr { | 
					
						
							|  |  |  |  | 	format++ // '%' | 
					
						
							|  |  |  |  | 	spec := "%" | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// Flags characters | 
					
						
							|  |  |  |  | 	// | 
					
						
							|  |  |  |  | 	// The character % is followed by zero or more of the following flags: | 
					
						
							|  |  |  |  | flags: | 
					
						
							|  |  |  |  | 	for { | 
					
						
							|  |  |  |  | 		switch c := *(*byte)(unsafe.Pointer(format)); c { | 
					
						
							|  |  |  |  | 		case '#': | 
					
						
							|  |  |  |  | 			// The value should be converted to an "alternate form".  For o conversions, | 
					
						
							|  |  |  |  | 			// the first character of the output string is made zero (by prefixing a 0 if | 
					
						
							|  |  |  |  | 			// it was not zero already).  For x and  X  conversions,  a nonzero result has | 
					
						
							|  |  |  |  | 			// the string "0x" (or "0X" for X conversions) prepended to it.  For a, A, e, | 
					
						
							|  |  |  |  | 			// E, f, F, g, and G conversions, the result will always contain a decimal | 
					
						
							|  |  |  |  | 			// point, even if no digits follow it (normally, a decimal point appears in the | 
					
						
							|  |  |  |  | 			// results of those conversions only if a digit follows).  For g and G | 
					
						
							|  |  |  |  | 			// conversions, trailing  zeros are not removed from the result as they would | 
					
						
							|  |  |  |  | 			// otherwise be.  For other conversions, the result is undefined. | 
					
						
							|  |  |  |  | 			format++ | 
					
						
							|  |  |  |  | 			spec += "#" | 
					
						
							|  |  |  |  | 		case '0': | 
					
						
							|  |  |  |  | 			// The  value  should  be zero padded.  For d, i, o, u, x, X, a, A, e, E, f, F, | 
					
						
							|  |  |  |  | 			// g, and G conversions, the converted value is padded on the left with zeros | 
					
						
							|  |  |  |  | 			// rather than blanks.  If the 0 and - flags both appear, the 0 flag is | 
					
						
							|  |  |  |  | 			// ignored.  If a precision is given with a numeric conversion (d, i, o, u, x, | 
					
						
							|  |  |  |  | 			// and X), the 0 flag is ignored.  For other conversions, the  behav‐ ior is | 
					
						
							|  |  |  |  | 			// undefined. | 
					
						
							|  |  |  |  | 			format++ | 
					
						
							|  |  |  |  | 			spec += "0" | 
					
						
							|  |  |  |  | 		case '-': | 
					
						
							|  |  |  |  | 			// The  converted value is to be left adjusted on the field boundary.  (The | 
					
						
							|  |  |  |  | 			// default is right justification.)  The converted value is padded on the right | 
					
						
							|  |  |  |  | 			// with blanks, rather than on the left with blanks or zeros.  A - overrides a | 
					
						
							|  |  |  |  | 			// 0 if both are given. | 
					
						
							|  |  |  |  | 			format++ | 
					
						
							|  |  |  |  | 			spec += "-" | 
					
						
							|  |  |  |  | 		case ' ': | 
					
						
							|  |  |  |  | 			// A blank should be left before a positive number (or empty string) produced | 
					
						
							|  |  |  |  | 			// by a signed conversion. | 
					
						
							|  |  |  |  | 			format++ | 
					
						
							|  |  |  |  | 			spec += " " | 
					
						
							|  |  |  |  | 		case '+': | 
					
						
							|  |  |  |  | 			// A sign (+ or -) should always be placed before a number produced by a signed | 
					
						
							|  |  |  |  | 			// conversion.  By default, a sign is used only for negative numbers.  A + | 
					
						
							|  |  |  |  | 			// overrides a space  if  both  are used. | 
					
						
							|  |  |  |  | 			format++ | 
					
						
							|  |  |  |  | 			spec += "+" | 
					
						
							|  |  |  |  | 		default: | 
					
						
							|  |  |  |  | 			break flags | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	format, width, hasWidth := parseFieldWidth(format) | 
					
						
							|  |  |  |  | 	if hasWidth { | 
					
						
							|  |  |  |  | 		spec += strconv.Itoa(width) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	format, prec, hasPrecision := parsePrecision(format, args) | 
					
						
							|  |  |  |  | 	format, mod := parseLengthModifier(format) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	var str string | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | more: | 
					
						
							|  |  |  |  | 	// Conversion specifiers | 
					
						
							|  |  |  |  | 	// | 
					
						
							|  |  |  |  | 	// A character that specifies the type of conversion to be applied.  The | 
					
						
							|  |  |  |  | 	// conversion specifiers and their meanings are: | 
					
						
							|  |  |  |  | 	switch c := *(*byte)(unsafe.Pointer(format)); c { | 
					
						
							|  |  |  |  | 	case 'd', 'i': | 
					
						
							|  |  |  |  | 		// The  int argument is converted to signed decimal notation.  The precision, | 
					
						
							|  |  |  |  | 		// if any, gives the minimum number of digits that must appear; if the | 
					
						
							|  |  |  |  | 		// converted value requires fewer digits, it is padded on the left with zeros. | 
					
						
							|  |  |  |  | 		// The default precision is 1.  When 0 is printed with an explicit precision 0, | 
					
						
							|  |  |  |  | 		// the output is empty. | 
					
						
							|  |  |  |  | 		format++ | 
					
						
							|  |  |  |  | 		var arg int64 | 
					
						
							|  |  |  |  | 		switch mod { | 
					
						
							|  |  |  |  | 		case modNone, modL, modLL, mod64: | 
					
						
							|  |  |  |  | 			arg = VaInt64(args) | 
					
						
							|  |  |  |  | 		case modH: | 
					
						
							|  |  |  |  | 			arg = int64(int16(VaInt32(args))) | 
					
						
							|  |  |  |  | 		case modHH: | 
					
						
							|  |  |  |  | 			arg = int64(int8(VaInt32(args))) | 
					
						
							|  |  |  |  | 		case mod32: | 
					
						
							|  |  |  |  | 			arg = int64(VaInt32(args)) | 
					
						
							|  |  |  |  | 		default: | 
					
						
							|  |  |  |  | 			panic(todo("", mod)) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		if arg == 0 && hasPrecision && prec == 0 { | 
					
						
							|  |  |  |  | 			break | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		if hasPrecision { | 
					
						
							|  |  |  |  | 			panic(todo("", prec)) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		f := spec + "d" | 
					
						
							|  |  |  |  | 		str = fmt.Sprintf(f, arg) | 
					
						
							|  |  |  |  | 	case 'u': | 
					
						
							|  |  |  |  | 		// The unsigned int argument is converted to unsigned decimal notation. The | 
					
						
							|  |  |  |  | 		// precision, if any, gives the minimum number of digits that must appear; if | 
					
						
							|  |  |  |  | 		// the converted value requires fewer digits, it is padded on the left with | 
					
						
							|  |  |  |  | 		// zeros.  The default precision is 1.  When 0 is printed with an explicit | 
					
						
							|  |  |  |  | 		// precision 0, the output is empty. | 
					
						
							|  |  |  |  | 		format++ | 
					
						
							|  |  |  |  | 		var arg uint64 | 
					
						
							|  |  |  |  | 		switch mod { | 
					
						
							|  |  |  |  | 		case modNone, modL, modLL, mod64: | 
					
						
							|  |  |  |  | 			arg = VaUint64(args) | 
					
						
							|  |  |  |  | 		case modH: | 
					
						
							|  |  |  |  | 			arg = uint64(uint16(VaInt32(args))) | 
					
						
							|  |  |  |  | 		case modHH: | 
					
						
							|  |  |  |  | 			arg = uint64(uint8(VaInt32(args))) | 
					
						
							|  |  |  |  | 		case mod32: | 
					
						
							|  |  |  |  | 			arg = uint64(VaInt32(args)) | 
					
						
							|  |  |  |  | 		default: | 
					
						
							|  |  |  |  | 			panic(todo("", mod)) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		if arg == 0 && hasPrecision && prec == 0 { | 
					
						
							|  |  |  |  | 			break | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		if hasPrecision { | 
					
						
							|  |  |  |  | 			panic(todo("", prec)) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		f := spec + "d" | 
					
						
							|  |  |  |  | 		str = fmt.Sprintf(f, arg) | 
					
						
							|  |  |  |  | 	case 'o': | 
					
						
							|  |  |  |  | 		// The unsigned int argument is converted to unsigned octal notation. The | 
					
						
							|  |  |  |  | 		// precision, if any, gives the minimum number of digits that must appear; if | 
					
						
							|  |  |  |  | 		// the converted value requires fewer digits, it is padded on the left with | 
					
						
							|  |  |  |  | 		// zeros.  The default precision is 1.  When 0 is printed with an explicit | 
					
						
							|  |  |  |  | 		// precision 0, the output is empty. | 
					
						
							|  |  |  |  | 		format++ | 
					
						
							|  |  |  |  | 		var arg uint64 | 
					
						
							|  |  |  |  | 		switch mod { | 
					
						
							|  |  |  |  | 		case modNone, modL, modLL, mod64: | 
					
						
							|  |  |  |  | 			arg = VaUint64(args) | 
					
						
							|  |  |  |  | 		case modH: | 
					
						
							|  |  |  |  | 			arg = uint64(uint16(VaInt32(args))) | 
					
						
							|  |  |  |  | 		case modHH: | 
					
						
							|  |  |  |  | 			arg = uint64(uint8(VaInt32(args))) | 
					
						
							|  |  |  |  | 		case mod32: | 
					
						
							|  |  |  |  | 			arg = uint64(VaInt32(args)) | 
					
						
							|  |  |  |  | 		default: | 
					
						
							|  |  |  |  | 			panic(todo("", mod)) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		if arg == 0 && hasPrecision && prec == 0 { | 
					
						
							|  |  |  |  | 			break | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		if hasPrecision { | 
					
						
							|  |  |  |  | 			panic(todo("", prec)) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		f := spec + "o" | 
					
						
							|  |  |  |  | 		str = fmt.Sprintf(f, arg) | 
					
						
							|  |  |  |  | 	case 'I': | 
					
						
							|  |  |  |  | 		if !isWindows { | 
					
						
							|  |  |  |  | 			panic(todo("%#U", c)) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		format++ | 
					
						
							|  |  |  |  | 		switch c = *(*byte)(unsafe.Pointer(format)); c { | 
					
						
							|  |  |  |  | 		case 'x', 'X': | 
					
						
							|  |  |  |  | 			// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-wsprintfa | 
					
						
							|  |  |  |  | 			// | 
					
						
							|  |  |  |  | 			// Ix, IX | 
					
						
							|  |  |  |  | 			// | 
					
						
							|  |  |  |  | 			// 64-bit unsigned hexadecimal integer in lowercase or uppercase on 64-bit | 
					
						
							|  |  |  |  | 			// platforms, 32-bit unsigned hexadecimal integer in lowercase or uppercase on | 
					
						
							|  |  |  |  | 			// 32-bit platforms. | 
					
						
							|  |  |  |  | 			if unsafe.Sizeof(int(0)) == 4 { | 
					
						
							|  |  |  |  | 				mod = mod32 | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 		case '3': | 
					
						
							|  |  |  |  | 			// https://en.wikipedia.org/wiki/Printf_format_string#Length_field | 
					
						
							|  |  |  |  | 			// | 
					
						
							|  |  |  |  | 			// I32	For integer types, causes printf to expect a 32-bit (double word) integer argument. | 
					
						
							|  |  |  |  | 			format++ | 
					
						
							|  |  |  |  | 			switch c = *(*byte)(unsafe.Pointer(format)); c { | 
					
						
							|  |  |  |  | 			case '2': | 
					
						
							|  |  |  |  | 				format++ | 
					
						
							|  |  |  |  | 				mod = mod32 | 
					
						
							|  |  |  |  | 				goto more | 
					
						
							|  |  |  |  | 			default: | 
					
						
							|  |  |  |  | 				panic(todo("%#U", c)) | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 		case '6': | 
					
						
							|  |  |  |  | 			// https://en.wikipedia.org/wiki/Printf_format_string#Length_field | 
					
						
							|  |  |  |  | 			// | 
					
						
							|  |  |  |  | 			// I64	For integer types, causes printf to expect a 64-bit (quad word) integer argument. | 
					
						
							|  |  |  |  | 			format++ | 
					
						
							|  |  |  |  | 			switch c = *(*byte)(unsafe.Pointer(format)); c { | 
					
						
							|  |  |  |  | 			case '4': | 
					
						
							|  |  |  |  | 				format++ | 
					
						
							|  |  |  |  | 				mod = mod64 | 
					
						
							|  |  |  |  | 				goto more | 
					
						
							|  |  |  |  | 			default: | 
					
						
							|  |  |  |  | 				panic(todo("%#U", c)) | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 		default: | 
					
						
							|  |  |  |  | 			panic(todo("%#U", c)) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		fallthrough | 
					
						
							|  |  |  |  | 	case 'X': | 
					
						
							|  |  |  |  | 		fallthrough | 
					
						
							|  |  |  |  | 	case 'x': | 
					
						
							|  |  |  |  | 		// The unsigned int argument is converted to unsigned hexadecimal notation. | 
					
						
							|  |  |  |  | 		// The letters abcdef are used for x  conversions;  the letters ABCDEF are used | 
					
						
							|  |  |  |  | 		// for X conversions.  The precision, if any, gives the minimum number of | 
					
						
							|  |  |  |  | 		// digits that must appear; if the converted value requires fewer digits, it is | 
					
						
							|  |  |  |  | 		// padded on the left with zeros.  The default precision is 1.  When 0 is | 
					
						
							|  |  |  |  | 		// printed with an explicit precision 0, the output is empty. | 
					
						
							|  |  |  |  | 		format++ | 
					
						
							|  |  |  |  | 		var arg uint64 | 
					
						
							|  |  |  |  | 		switch mod { | 
					
						
							|  |  |  |  | 		case modNone, modL, modLL, mod64: | 
					
						
							|  |  |  |  | 			arg = VaUint64(args) | 
					
						
							|  |  |  |  | 		case modH: | 
					
						
							|  |  |  |  | 			arg = uint64(uint16(VaInt32(args))) | 
					
						
							|  |  |  |  | 		case modHH: | 
					
						
							|  |  |  |  | 			arg = uint64(uint8(VaInt32(args))) | 
					
						
							|  |  |  |  | 		case mod32: | 
					
						
							|  |  |  |  | 			arg = uint64(VaInt32(args)) | 
					
						
							|  |  |  |  | 		default: | 
					
						
							|  |  |  |  | 			panic(todo("", mod)) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		if arg == 0 && hasPrecision && prec == 0 { | 
					
						
							|  |  |  |  | 			break | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		if strings.Contains(spec, "#") && arg == 0 { | 
					
						
							|  |  |  |  | 			spec = strings.ReplaceAll(spec, "#", "") | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		var f string | 
					
						
							|  |  |  |  | 		switch { | 
					
						
							|  |  |  |  | 		case hasPrecision: | 
					
						
							|  |  |  |  | 			f = fmt.Sprintf("%s.%d%c", spec, prec, c) | 
					
						
							|  |  |  |  | 		default: | 
					
						
							|  |  |  |  | 			f = spec + string(c) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		str = fmt.Sprintf(f, arg) | 
					
						
							|  |  |  |  | 	case 'e', 'E': | 
					
						
							|  |  |  |  | 		// The double argument is rounded and converted in the style [-]d.ddde±dd where | 
					
						
							|  |  |  |  | 		// there is one digit before the decimal-point character and the number of | 
					
						
							|  |  |  |  | 		// digits after it is equal to  the precision;  if the precision is missing, it | 
					
						
							|  |  |  |  | 		// is taken as 6; if the precision is zero, no decimal-point character appears. | 
					
						
							|  |  |  |  | 		// An E conversion uses the letter E (rather than e) to intro‐ duce the | 
					
						
							|  |  |  |  | 		// exponent.  The exponent always contains at least two digits; if the value is | 
					
						
							|  |  |  |  | 		// zero, the exponent is 00. | 
					
						
							|  |  |  |  | 		format++ | 
					
						
							|  |  |  |  | 		arg := VaFloat64(args) | 
					
						
							|  |  |  |  | 		if !hasPrecision { | 
					
						
							|  |  |  |  | 			prec = 6 | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		f := fmt.Sprintf("%s.%d%c", spec, prec, c) | 
					
						
							|  |  |  |  | 		str = fmt.Sprintf(f, arg) | 
					
						
							|  |  |  |  | 	case 'f', 'F': | 
					
						
							|  |  |  |  | 		// The double argument is rounded and converted to decimal notation in the | 
					
						
							|  |  |  |  | 		// style [-]ddd.ddd, where the number of digits after the decimal-point | 
					
						
							|  |  |  |  | 		// character  is  equal  to  the  precision specification.   If  the  precision | 
					
						
							|  |  |  |  | 		// is missing, it is taken as 6; if the precision is explicitly zero, no | 
					
						
							|  |  |  |  | 		// decimal-point character appears.  If a decimal point appears, at least one | 
					
						
							|  |  |  |  | 		// digit appears before it. | 
					
						
							|  |  |  |  | 		format++ | 
					
						
							|  |  |  |  | 		arg := VaFloat64(args) | 
					
						
							|  |  |  |  | 		if !hasPrecision { | 
					
						
							|  |  |  |  | 			prec = 6 | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		f := fmt.Sprintf("%s.%d%c", spec, prec, c) | 
					
						
							|  |  |  |  | 		str = fmt.Sprintf(f, arg) | 
					
						
							|  |  |  |  | 	case 'G': | 
					
						
							|  |  |  |  | 		fallthrough | 
					
						
							|  |  |  |  | 	case 'g': | 
					
						
							|  |  |  |  | 		// The double argument is converted in style f or e (or F or E for G | 
					
						
							|  |  |  |  | 		// conversions).  The precision specifies the number of significant digits.  If | 
					
						
							|  |  |  |  | 		// the precision is missing, 6 digits are given;  if the precision is zero, it | 
					
						
							|  |  |  |  | 		// is treated as 1.  Style e is used if the exponent from its conversion is | 
					
						
							|  |  |  |  | 		// less than -4 or greater than or equal to the precision.  Trailing zeros are | 
					
						
							|  |  |  |  | 		// removed from the fractional part of the result; a decimal point appears only | 
					
						
							|  |  |  |  | 		// if it is followed by at least one digit. | 
					
						
							|  |  |  |  | 		format++ | 
					
						
							|  |  |  |  | 		arg := VaFloat64(args) | 
					
						
							|  |  |  |  | 		if !hasPrecision { | 
					
						
							|  |  |  |  | 			prec = 6 | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		if prec == 0 { | 
					
						
							|  |  |  |  | 			prec = 1 | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		f := fmt.Sprintf("%s.%d%c", spec, prec, c) | 
					
						
							|  |  |  |  | 		str = fmt.Sprintf(f, arg) | 
					
						
							|  |  |  |  | 	case 's': | 
					
						
							|  |  |  |  | 		// If  no l modifier is present: the const char * argument is expected to be a | 
					
						
							|  |  |  |  | 		// pointer to an array of character type (pointer to a string).  Characters | 
					
						
							|  |  |  |  | 		// from the array are written up to (but not including) a terminating null byte | 
					
						
							|  |  |  |  | 		// ('\0'); if a precision is specified, no more than the number specified are | 
					
						
							|  |  |  |  | 		// written.  If a precision  is  given,  no  null  byte  need  be present; if | 
					
						
							|  |  |  |  | 		// the precision is not specified, or is greater than the size of the array, | 
					
						
							|  |  |  |  | 		// the array must contain a terminating null byte. | 
					
						
							|  |  |  |  | 		// | 
					
						
							|  |  |  |  | 		// If  an  l  modifier  is  present: the const wchar_t * argument is expected | 
					
						
							|  |  |  |  | 		// to be a pointer to an array of wide characters.  Wide characters from the | 
					
						
							|  |  |  |  | 		// array are converted to multibyte characters (each by a call to the | 
					
						
							|  |  |  |  | 		// wcrtomb(3) function, with a conversion state starting in the initial state | 
					
						
							|  |  |  |  | 		// before the first wide character), up to and including a terminating null | 
					
						
							|  |  |  |  | 		// wide  character.   The  resulting  multibyte  characters are written up to | 
					
						
							|  |  |  |  | 		// (but not including) the terminating null byte.  If a precision is specified, | 
					
						
							|  |  |  |  | 		// no more bytes than the number specified are written, but no partial | 
					
						
							|  |  |  |  | 		// multibyte characters are written.  Note that the precision determines the | 
					
						
							|  |  |  |  | 		// number of bytes written, not the number of wide characters or  screen | 
					
						
							|  |  |  |  | 		// positions.   The  array  must contain a terminating null wide character, | 
					
						
							|  |  |  |  | 		// unless a precision is given and it is so small that the number of bytes | 
					
						
							|  |  |  |  | 		// written exceeds it before the end of the array is reached. | 
					
						
							|  |  |  |  | 		format++ | 
					
						
							|  |  |  |  | 		arg := VaUintptr(args) | 
					
						
							|  |  |  |  | 		switch mod { | 
					
						
							|  |  |  |  | 		case modNone: | 
					
						
							|  |  |  |  | 			var f string | 
					
						
							|  |  |  |  | 			switch { | 
					
						
							|  |  |  |  | 			case hasPrecision: | 
					
						
							|  |  |  |  | 				f = fmt.Sprintf("%s.%ds", spec, prec) | 
					
						
							|  |  |  |  | 				str = fmt.Sprintf(f, GoBytes(arg, prec)) | 
					
						
							|  |  |  |  | 			default: | 
					
						
							|  |  |  |  | 				f = spec + "s" | 
					
						
							|  |  |  |  | 				str = fmt.Sprintf(f, GoString(arg)) | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 		default: | 
					
						
							|  |  |  |  | 			panic(todo("")) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	case 'p': | 
					
						
							|  |  |  |  | 		// The void * pointer argument is printed in hexadecimal (as if by %#x or | 
					
						
							|  |  |  |  | 		// %#lx). | 
					
						
							|  |  |  |  | 		format++ | 
					
						
							|  |  |  |  | 		arg := VaUintptr(args) | 
					
						
							|  |  |  |  | 		buf.WriteString("0x") | 
					
						
							|  |  |  |  | 		buf.WriteString(strconv.FormatInt(int64(arg), 16)) | 
					
						
							|  |  |  |  | 	case 'c': | 
					
						
							|  |  |  |  | 		// If no l modifier is present, the int argument is converted to an unsigned | 
					
						
							|  |  |  |  | 		// char, and the resulting character is written.  If an l modifier is present, | 
					
						
							|  |  |  |  | 		// the wint_t (wide character) ar‐ gument is converted to a multibyte sequence | 
					
						
							|  |  |  |  | 		// by a call to the wcrtomb(3) function, with a conversion state starting in | 
					
						
							|  |  |  |  | 		// the initial state, and the resulting multibyte string is  writ‐ ten. | 
					
						
							|  |  |  |  | 		format++ | 
					
						
							|  |  |  |  | 		switch mod { | 
					
						
							|  |  |  |  | 		case modNone: | 
					
						
							|  |  |  |  | 			arg := VaInt32(args) | 
					
						
							|  |  |  |  | 			buf.WriteByte(byte(arg)) | 
					
						
							|  |  |  |  | 		default: | 
					
						
							|  |  |  |  | 			panic(todo("")) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	case '%': | 
					
						
							|  |  |  |  | 		// A '%' is written.  No argument is converted.  The complete conversion | 
					
						
							|  |  |  |  | 		// specification is '%%'. | 
					
						
							|  |  |  |  | 		format++ | 
					
						
							|  |  |  |  | 		buf.WriteByte('%') | 
					
						
							|  |  |  |  | 	default: | 
					
						
							|  |  |  |  | 		panic(todo("%#U", c)) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	buf.WriteString(str) | 
					
						
							|  |  |  |  | 	return format | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // Field width | 
					
						
							|  |  |  |  | // | 
					
						
							|  |  |  |  | // An optional decimal digit string (with nonzero first digit) specifying a | 
					
						
							|  |  |  |  | // minimum field width.  If the converted value has fewer characters than the | 
					
						
							|  |  |  |  | // field width, it will be padded with spa‐ ces on the left (or right, if the | 
					
						
							|  |  |  |  | // left-adjustment flag has been given).  Instead of a decimal digit string one | 
					
						
							|  |  |  |  | // may write "*" or "*m$" (for some decimal integer m) to specify that the | 
					
						
							|  |  |  |  | // field width  is  given  in the next argument, or in the m-th argument, | 
					
						
							|  |  |  |  | // respectively, which must be of type int.  A negative field width is taken as | 
					
						
							|  |  |  |  | // a '-' flag followed by a positive field width.  In no case does a | 
					
						
							|  |  |  |  | // nonexistent or small field width cause truncation of a field; if the result | 
					
						
							|  |  |  |  | // of a conversion is wider than the field width, the field is expanded to | 
					
						
							|  |  |  |  | // contain the conversion result. | 
					
						
							|  |  |  |  | func parseFieldWidth(format uintptr) (_ uintptr, n int, ok bool) { | 
					
						
							|  |  |  |  | 	first := true | 
					
						
							|  |  |  |  | 	for { | 
					
						
							|  |  |  |  | 		var digit int | 
					
						
							|  |  |  |  | 		switch c := *(*byte)(unsafe.Pointer(format)); { | 
					
						
							|  |  |  |  | 		case first && c == '0': | 
					
						
							|  |  |  |  | 			return format, n, ok | 
					
						
							|  |  |  |  | 		case first && c == '*': | 
					
						
							|  |  |  |  | 			panic(todo("")) | 
					
						
							|  |  |  |  | 		case c >= '0' && c <= '9': | 
					
						
							|  |  |  |  | 			format++ | 
					
						
							|  |  |  |  | 			ok = true | 
					
						
							|  |  |  |  | 			first = false | 
					
						
							|  |  |  |  | 			digit = int(c) - '0' | 
					
						
							|  |  |  |  | 		default: | 
					
						
							|  |  |  |  | 			return format, n, ok | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		n0 := n | 
					
						
							|  |  |  |  | 		n = 10*n + digit | 
					
						
							|  |  |  |  | 		if n < n0 { | 
					
						
							|  |  |  |  | 			panic(todo("")) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // Precision | 
					
						
							|  |  |  |  | // | 
					
						
							|  |  |  |  | // An  optional precision, in the form of a period ('.')  followed by an | 
					
						
							|  |  |  |  | // optional decimal digit string.  Instead of a decimal digit string one may | 
					
						
							|  |  |  |  | // write "*" or "*m$" (for some decimal integer m) to specify that the | 
					
						
							|  |  |  |  | // precision is given in the next argument, or in the m-th argument, | 
					
						
							|  |  |  |  | // respectively, which must be of type int.  If the precision is given as just | 
					
						
							|  |  |  |  | // '.', the  precision  is taken  to  be  zero.  A negative precision is taken | 
					
						
							|  |  |  |  | // as if the precision were omitted.  This gives the minimum number of digits | 
					
						
							|  |  |  |  | // to appear for d, i, o, u, x, and X conversions, the number of digits to | 
					
						
							|  |  |  |  | // appear after the radix character for a, A, e, E, f, and F conversions, the | 
					
						
							|  |  |  |  | // maximum number of significant digits for g and G conversions, or the maximum | 
					
						
							|  |  |  |  | // number of characters to be printed from a string for s and S conversions. | 
					
						
							|  |  |  |  | func parsePrecision(format uintptr, args *uintptr) (_ uintptr, n int, ok bool) { | 
					
						
							|  |  |  |  | 	for { | 
					
						
							|  |  |  |  | 		switch c := *(*byte)(unsafe.Pointer(format)); c { | 
					
						
							|  |  |  |  | 		case '.': | 
					
						
							|  |  |  |  | 			format++ | 
					
						
							|  |  |  |  | 			first := true | 
					
						
							|  |  |  |  | 			for { | 
					
						
							|  |  |  |  | 				switch c := *(*byte)(unsafe.Pointer(format)); { | 
					
						
							|  |  |  |  | 				case first && c == '*': | 
					
						
							|  |  |  |  | 					format++ | 
					
						
							|  |  |  |  | 					n = int(VaInt32(args)) | 
					
						
							|  |  |  |  | 					return format, n, true | 
					
						
							|  |  |  |  | 				case c >= '0' && c <= '9': | 
					
						
							|  |  |  |  | 					format++ | 
					
						
							|  |  |  |  | 					first = false | 
					
						
							|  |  |  |  | 					n0 := n | 
					
						
							|  |  |  |  | 					n = 10*n + (int(c) - '0') | 
					
						
							|  |  |  |  | 					if n < n0 { | 
					
						
							|  |  |  |  | 						panic(todo("")) | 
					
						
							|  |  |  |  | 					} | 
					
						
							|  |  |  |  | 				default: | 
					
						
							|  |  |  |  | 					return format, n, true | 
					
						
							|  |  |  |  | 				} | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 		default: | 
					
						
							|  |  |  |  | 			return format, 0, false | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // Length modifier | 
					
						
							|  |  |  |  | // | 
					
						
							|  |  |  |  | // Here, "integer conversion" stands for d, i, o, u, x, or X conversion. | 
					
						
							|  |  |  |  | // | 
					
						
							|  |  |  |  | // hh     A following integer conversion corresponds to a signed char or | 
					
						
							|  |  |  |  | // unsigned char argument, or a following n conversion corresponds to a pointer | 
					
						
							|  |  |  |  | // to a signed char argument. | 
					
						
							|  |  |  |  | // | 
					
						
							|  |  |  |  | // h      A following integer conversion corresponds to a short int or unsigned | 
					
						
							|  |  |  |  | // short int argument, or a following n conversion corresponds to a pointer to | 
					
						
							|  |  |  |  | // a short int argument. | 
					
						
							|  |  |  |  | // | 
					
						
							|  |  |  |  | // l      (ell)  A following integer conversion corresponds to a long int or | 
					
						
							|  |  |  |  | // unsigned long int argument, or a following n conversion corresponds to a | 
					
						
							|  |  |  |  | // pointer to a long int argument, or a fol‐ lowing c conversion corresponds to | 
					
						
							|  |  |  |  | // a wint_t argument, or a following s conversion corresponds to a pointer to | 
					
						
							|  |  |  |  | // wchar_t argument. | 
					
						
							|  |  |  |  | // | 
					
						
							|  |  |  |  | // ll     (ell-ell).  A following integer conversion corresponds to a long long | 
					
						
							|  |  |  |  | // int or unsigned long long int argument, or a following n conversion | 
					
						
							|  |  |  |  | // corresponds to a pointer to a long long int argument. | 
					
						
							|  |  |  |  | // | 
					
						
							|  |  |  |  | // q      A synonym for ll.  This is a nonstandard extension, derived from BSD; | 
					
						
							|  |  |  |  | // avoid its use in new code. | 
					
						
							|  |  |  |  | // | 
					
						
							|  |  |  |  | // L      A following a, A, e, E, f, F, g, or G conversion corresponds to a | 
					
						
							|  |  |  |  | // long double argument.  (C99 allows %LF, but SUSv2 does not.) | 
					
						
							|  |  |  |  | // | 
					
						
							|  |  |  |  | // j      A following integer conversion corresponds to an intmax_t or | 
					
						
							|  |  |  |  | // uintmax_t argument, or a following n conversion corresponds to a pointer to | 
					
						
							|  |  |  |  | // an intmax_t argument. | 
					
						
							|  |  |  |  | // | 
					
						
							|  |  |  |  | // z      A following integer conversion corresponds to a size_t or ssize_t | 
					
						
							|  |  |  |  | // argument, or a following n conversion corresponds to a pointer to a size_t | 
					
						
							|  |  |  |  | // argument. | 
					
						
							|  |  |  |  | // | 
					
						
							|  |  |  |  | // Z      A nonstandard synonym for z that predates the appearance of z.  Do | 
					
						
							|  |  |  |  | // not use in new code. | 
					
						
							|  |  |  |  | // | 
					
						
							|  |  |  |  | // t      A following integer conversion corresponds to a ptrdiff_t argument, | 
					
						
							|  |  |  |  | // or a following n conversion corresponds to a pointer to a ptrdiff_t | 
					
						
							|  |  |  |  | // argument. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func parseLengthModifier(format uintptr) (_ uintptr, n int) { | 
					
						
							|  |  |  |  | 	switch c := *(*byte)(unsafe.Pointer(format)); c { | 
					
						
							|  |  |  |  | 	case 'h': | 
					
						
							|  |  |  |  | 		format++ | 
					
						
							|  |  |  |  | 		n = modH | 
					
						
							|  |  |  |  | 		switch c := *(*byte)(unsafe.Pointer(format)); c { | 
					
						
							|  |  |  |  | 		case 'h': | 
					
						
							|  |  |  |  | 			format++ | 
					
						
							|  |  |  |  | 			n = modHH | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		return format, n | 
					
						
							|  |  |  |  | 	case 'l': | 
					
						
							|  |  |  |  | 		format++ | 
					
						
							|  |  |  |  | 		n = modL | 
					
						
							|  |  |  |  | 		switch c := *(*byte)(unsafe.Pointer(format)); c { | 
					
						
							|  |  |  |  | 		case 'l': | 
					
						
							|  |  |  |  | 			format++ | 
					
						
							|  |  |  |  | 			n = modLL | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		return format, n | 
					
						
							|  |  |  |  | 	case 'q': | 
					
						
							|  |  |  |  | 		panic(todo("")) | 
					
						
							|  |  |  |  | 	case 'L': | 
					
						
							|  |  |  |  | 		panic(todo("")) | 
					
						
							|  |  |  |  | 	case 'j': | 
					
						
							|  |  |  |  | 		panic(todo("")) | 
					
						
							|  |  |  |  | 	case 'z': | 
					
						
							|  |  |  |  | 		panic(todo("")) | 
					
						
							|  |  |  |  | 	case 'Z': | 
					
						
							|  |  |  |  | 		panic(todo("")) | 
					
						
							|  |  |  |  | 	case 't': | 
					
						
							|  |  |  |  | 		panic(todo("")) | 
					
						
							|  |  |  |  | 	default: | 
					
						
							|  |  |  |  | 		return format, 0 | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } |