mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-11-03 19:32:26 -06:00 
			
		
		
		
	github.com/uptrace/bun v1.1.8 -> v1.1.9 github.com/uptrace/bun/pgdialect v1.1.8 -> v1.1.9 github.com/uptrace/bun/sqlitedialect v1.1.8 -> v1.1.9 modernc.org/sqlite v1.18.2 -> v1.19.5
		
			
				
	
	
		
			633 lines
		
	
	
	
		
			19 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			633 lines
		
	
	
	
		
			19 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// 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"
 | 
						||
	"runtime"
 | 
						||
	"strconv"
 | 
						||
	"strings"
 | 
						||
	"unsafe"
 | 
						||
)
 | 
						||
 | 
						||
const (
 | 
						||
	modNone = iota
 | 
						||
	modHH
 | 
						||
	modH
 | 
						||
	modL
 | 
						||
	modLL
 | 
						||
	modLD
 | 
						||
	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 {
 | 
						||
	format0 := format
 | 
						||
	args0 := args
 | 
						||
	buf := bytes.NewBuffer(nil)
 | 
						||
	for {
 | 
						||
		switch c := *(*byte)(unsafe.Pointer(format)); c {
 | 
						||
		case '%':
 | 
						||
			format = printfConversion(buf, format, &args)
 | 
						||
		case 0:
 | 
						||
			if dmesgs {
 | 
						||
				dmesg("%v: %q, %#x -> %q", origin(1), GoString(format0), args0, buf.Bytes())
 | 
						||
			}
 | 
						||
			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
 | 
						||
		if isWindows && mod == modL {
 | 
						||
			mod = modNone
 | 
						||
		}
 | 
						||
		switch mod {
 | 
						||
		case modL, modLL, mod64:
 | 
						||
			arg = VaInt64(args)
 | 
						||
		case modH:
 | 
						||
			arg = int64(int16(VaInt32(args)))
 | 
						||
		case modHH:
 | 
						||
			arg = int64(int8(VaInt32(args)))
 | 
						||
		case mod32, modNone:
 | 
						||
			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
 | 
						||
		if isWindows && mod == modL {
 | 
						||
			mod = modNone
 | 
						||
		}
 | 
						||
		switch mod {
 | 
						||
		case modNone:
 | 
						||
			arg = uint64(VaUint32(args))
 | 
						||
		case 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
 | 
						||
		if isWindows && mod == modL {
 | 
						||
			mod = modNone
 | 
						||
		}
 | 
						||
		switch mod {
 | 
						||
		case modNone:
 | 
						||
			arg = uint64(VaUint32(args))
 | 
						||
		case 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
 | 
						||
		if isWindows && mod == modL {
 | 
						||
			mod = modNone
 | 
						||
		}
 | 
						||
		switch mod {
 | 
						||
		case modNone:
 | 
						||
			arg = uint64(VaUint32(args))
 | 
						||
		case 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 = fixNanInf(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 = fixNanInf(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, GoString(arg))
 | 
						||
			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++
 | 
						||
		switch runtime.GOOS {
 | 
						||
		case "windows":
 | 
						||
			switch runtime.GOARCH {
 | 
						||
			case "386", "arm":
 | 
						||
				fmt.Fprintf(buf, "%08X", VaUintptr(args))
 | 
						||
			default:
 | 
						||
				fmt.Fprintf(buf, "%016X", VaUintptr(args))
 | 
						||
			}
 | 
						||
		default:
 | 
						||
			fmt.Fprintf(buf, "%#0x", VaUintptr(args))
 | 
						||
		}
 | 
						||
	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':
 | 
						||
		format++
 | 
						||
		n = modLD
 | 
						||
		return format, n
 | 
						||
	case 'j':
 | 
						||
		panic(todo(""))
 | 
						||
	case 'z':
 | 
						||
		panic(todo(""))
 | 
						||
	case 'Z':
 | 
						||
		panic(todo(""))
 | 
						||
	case 't':
 | 
						||
		panic(todo(""))
 | 
						||
	default:
 | 
						||
		return format, 0
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
func fixNanInf(s string) string {
 | 
						||
	switch s {
 | 
						||
	case "NaN":
 | 
						||
		return "nan"
 | 
						||
	case "+Inf", "-Inf":
 | 
						||
		return "inf"
 | 
						||
	default:
 | 
						||
		return s
 | 
						||
	}
 | 
						||
}
 |