diff options
| author | 2021-08-29 15:41:41 +0100 | |
|---|---|---|
| committer | 2021-08-29 16:41:41 +0200 | |
| commit | ed462245730bd7832019bd43e0bc1c9d1c055e8e (patch) | |
| tree | 1caad78ea6aabf5ea93c93a8ade97176b4889500 /vendor/modernc.org/libc/printf.go | |
| parent | Mention fixup (#167) (diff) | |
| download | gotosocial-ed462245730bd7832019bd43e0bc1c9d1c055e8e.tar.xz | |
Add SQLite support, fix un-thread-safe DB caches, small performance f… (#172)
* Add SQLite support, fix un-thread-safe DB caches, small performance fixes
Signed-off-by: kim (grufwub) <grufwub@gmail.com>
* add SQLite licenses to README
Signed-off-by: kim (grufwub) <grufwub@gmail.com>
* appease the linter, and fix my dumbass-ery
Signed-off-by: kim (grufwub) <grufwub@gmail.com>
* make requested changes
Signed-off-by: kim (grufwub) <grufwub@gmail.com>
* add back comment
Signed-off-by: kim (grufwub) <grufwub@gmail.com>
Diffstat (limited to 'vendor/modernc.org/libc/printf.go')
| -rw-r--r-- | vendor/modernc.org/libc/printf.go | 590 | 
1 files changed, 590 insertions, 0 deletions
| diff --git a/vendor/modernc.org/libc/printf.go b/vendor/modernc.org/libc/printf.go new file mode 100644 index 000000000..c755a5375 --- /dev/null +++ b/vendor/modernc.org/libc/printf.go @@ -0,0 +1,590 @@ +// 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: +			// if dmesgs { +			// 	dmesg("%v: %q", origin(1), 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 +		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 +	} +} | 
