mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 14:12:26 -05:00 
			
		
		
		
	* upstep bun and sqlite versions * allow specific columns to be updated in the db * only update necessary columns for user * bit tidier * only update necessary fields of media_attachment * only update relevant instance fields * update tests * update only specific account columns * use bool pointers on gtsmodels includes attachment, status, account, user * update columns more selectively * test all default fields on new account insert * updating remaining bools on gtsmodels * initialize pointer fields when extracting AP emoji * copy bools properly * add copyBoolPtr convenience function + test it * initialize false bool ptrs a bit more neatly
		
			
				
	
	
		
			443 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			443 lines
		
	
	
	
		
			11 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 (
 | ||
| 	"strings"
 | ||
| 	"unsafe"
 | ||
| )
 | ||
| 
 | ||
| // The format string consists of a sequence of directives which describe how to
 | ||
| // process the sequence of input characters.  If processing of a directive
 | ||
| // fails, no further input  is  read,  and scanf()  returns.   A "failure" can
 | ||
| // be either of the following: input failure, meaning that input characters
 | ||
| // were unavailable, or matching failure, meaning that the input was
 | ||
| // inappropriate.
 | ||
| func scanf(r *strings.Reader, format, args uintptr) (nvalues int32) {
 | ||
| 	// var src []byte //TODO-
 | ||
| 	var ok bool
 | ||
| out:
 | ||
| 	for {
 | ||
| 		c := *(*byte)(unsafe.Pointer(format))
 | ||
| 		// src = append(src, c) //TODO-
 | ||
| 		switch c {
 | ||
| 		case '%':
 | ||
| 			var n int
 | ||
| 			var match bool
 | ||
| 			format, n, match = scanfConversion(r, format, &args)
 | ||
| 			if !match {
 | ||
| 				break out
 | ||
| 			}
 | ||
| 
 | ||
| 			nvalues += int32(n)
 | ||
| 			ok = true
 | ||
| 		case 0:
 | ||
| 			break out
 | ||
| 		case ' ', '\t', '\n', '\r', '\v', '\f':
 | ||
| 			format = skipWhiteSpace(format)
 | ||
| 			ok = true
 | ||
| 		next:
 | ||
| 			for {
 | ||
| 				c, err := r.ReadByte()
 | ||
| 				if err != nil {
 | ||
| 					break out
 | ||
| 				}
 | ||
| 
 | ||
| 				switch c {
 | ||
| 				case ' ', '\t', '\n', '\r', '\v', '\f':
 | ||
| 					// nop
 | ||
| 				default:
 | ||
| 					r.UnreadByte()
 | ||
| 					break next
 | ||
| 				}
 | ||
| 			}
 | ||
| 		default:
 | ||
| 			c2, err := r.ReadByte()
 | ||
| 			if err != nil {
 | ||
| 				break out
 | ||
| 			}
 | ||
| 
 | ||
| 			if c2 != c {
 | ||
| 				r.UnreadByte()
 | ||
| 				break out
 | ||
| 			}
 | ||
| 
 | ||
| 			format++
 | ||
| 			ok = true
 | ||
| 		}
 | ||
| 	}
 | ||
| 	if ok {
 | ||
| 		return nvalues
 | ||
| 	}
 | ||
| 
 | ||
| 	return -1 // stdio.EOF but not defined for windows
 | ||
| }
 | ||
| 
 | ||
| func scanfConversion(r *strings.Reader, format uintptr, args *uintptr) (_ uintptr, nvalues int, match bool) {
 | ||
| 	format++ // '%'
 | ||
| 
 | ||
| 	// Each conversion specification in format begins with either the character '%'
 | ||
| 	// or the character sequence "%n$" (see below for the distinction) followed by:
 | ||
| 
 | ||
| 	mod := 0
 | ||
| 	width := -1
 | ||
| flags:
 | ||
| 	for {
 | ||
| 		switch c := *(*byte)(unsafe.Pointer(format)); c {
 | ||
| 		case '*':
 | ||
| 			// An  optional '*' assignment-suppression character: scanf() reads input as
 | ||
| 			// directed by the conversion specification, but discards the input.  No
 | ||
| 			// corresponding pointer argument is re‐ quired, and this specification is not
 | ||
| 			// included in the count of successful assignments returned by scanf().
 | ||
| 			format++
 | ||
| 			panic(todo(""))
 | ||
| 		case '\'':
 | ||
| 			// For decimal conversions, an optional quote character (').  This specifies
 | ||
| 			// that the input number may include thousands' separators as defined by the
 | ||
| 			// LC_NUMERIC category of  the  current locale.  (See setlocale(3).)  The quote
 | ||
| 			// character may precede or follow the '*' assignment-suppression character.
 | ||
| 			format++
 | ||
| 			panic(todo(""))
 | ||
| 		case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
 | ||
| 			// An  optional  decimal  integer  which  specifies  the maximum field width.
 | ||
| 			// Reading of characters stops either when this maximum is reached or when a
 | ||
| 			// nonmatching character is found, whichever happens first.  Most conversions
 | ||
| 			// discard initial white space characters (the exceptions are noted below), and
 | ||
| 			// these discarded characters don't  count  toward  the  maximum field width.
 | ||
| 			// String input conversions store a terminating null byte ('\0') to mark the
 | ||
| 			// end of the input; the maximum field width does not include this terminator.
 | ||
| 			width = 0
 | ||
| 		num:
 | ||
| 			for {
 | ||
| 				var digit int
 | ||
| 				switch c := *(*byte)(unsafe.Pointer(format)); {
 | ||
| 				default:
 | ||
| 					break num
 | ||
| 				case c >= '0' && c <= '9':
 | ||
| 					format++
 | ||
| 					digit = int(c) - '0'
 | ||
| 				}
 | ||
| 				width0 := width
 | ||
| 				width = 10*width + digit
 | ||
| 				if width < width0 {
 | ||
| 					panic(todo(""))
 | ||
| 				}
 | ||
| 			}
 | ||
| 		case 'h', 'j', 'l', 'L', 'q', 't', 'z':
 | ||
| 			format, mod = parseLengthModifier(format)
 | ||
| 		default:
 | ||
| 			break flags
 | ||
| 		}
 | ||
| 	}
 | ||
| 
 | ||
| 	// A conversion specifier that specifies the type of input conversion to be
 | ||
| 	// performed.
 | ||
| 	switch c := *(*byte)(unsafe.Pointer(format)); c {
 | ||
| 	case '%':
 | ||
| 		// Matches a literal '%'.  That is, %% in the format string matches a single
 | ||
| 		// input '%' character.  No conversion is done (but initial white space
 | ||
| 		// characters are discarded), and assign‐ ment does not occur.
 | ||
| 		format++
 | ||
| 		panic(todo(""))
 | ||
| 	case 'd':
 | ||
| 		// Matches an optionally signed decimal integer; the next pointer must be a
 | ||
| 		// pointer to int.
 | ||
| 		format++
 | ||
| 		skipReaderWhiteSpace(r)
 | ||
| 		var digit, n uint64
 | ||
| 		allowSign := true
 | ||
| 		neg := false
 | ||
| 	dec:
 | ||
| 		for ; width != 0; width-- {
 | ||
| 			c, err := r.ReadByte()
 | ||
| 			if err != nil {
 | ||
| 				if match {
 | ||
| 					break dec
 | ||
| 				}
 | ||
| 
 | ||
| 				panic(todo("", err))
 | ||
| 			}
 | ||
| 
 | ||
| 			if allowSign {
 | ||
| 				switch c {
 | ||
| 				case '-':
 | ||
| 					allowSign = false
 | ||
| 					neg = true
 | ||
| 					continue
 | ||
| 				case '+':
 | ||
| 					allowSign = false
 | ||
| 					continue
 | ||
| 				}
 | ||
| 			}
 | ||
| 
 | ||
| 			switch {
 | ||
| 			case c >= '0' && c <= '9':
 | ||
| 				digit = uint64(c) - '0'
 | ||
| 			default:
 | ||
| 				r.UnreadByte()
 | ||
| 				break dec
 | ||
| 			}
 | ||
| 			match = true
 | ||
| 			n0 := n
 | ||
| 			n = n*10 + digit
 | ||
| 			if n < n0 {
 | ||
| 				panic(todo(""))
 | ||
| 			}
 | ||
| 		}
 | ||
| 		if !match {
 | ||
| 			break
 | ||
| 		}
 | ||
| 
 | ||
| 		arg := VaUintptr(args)
 | ||
| 		v := int64(n)
 | ||
| 		if neg {
 | ||
| 			v = -v
 | ||
| 		}
 | ||
| 		switch mod {
 | ||
| 		case modNone:
 | ||
| 			*(*int32)(unsafe.Pointer(arg)) = int32(v)
 | ||
| 		case modH:
 | ||
| 			*(*int16)(unsafe.Pointer(arg)) = int16(v)
 | ||
| 		case modHH:
 | ||
| 			*(*int8)(unsafe.Pointer(arg)) = int8(v)
 | ||
| 		case modL:
 | ||
| 			*(*long)(unsafe.Pointer(arg)) = long(n)
 | ||
| 		default:
 | ||
| 			panic(todo(""))
 | ||
| 		}
 | ||
| 		nvalues = 1
 | ||
| 	case 'D':
 | ||
| 		// Equivalent  to  ld;  this  exists  only for backward compatibility.  (Note:
 | ||
| 		// thus only in libc4.  In libc5 and glibc the %D is silently ignored, causing
 | ||
| 		// old programs to fail mysteriously.)
 | ||
| 		format++
 | ||
| 		panic(todo(""))
 | ||
| 	case 'i':
 | ||
| 		// Matches an optionally signed integer; the next pointer must be a pointer to
 | ||
| 		// int.  The integer is read in base 16 if it begins with 0x or 0X, in base 8
 | ||
| 		// if it begins with  0,  and  in base 10 otherwise.  Only characters that
 | ||
| 		// correspond to the base are used.
 | ||
| 		format++
 | ||
| 		panic(todo(""))
 | ||
| 	case 'o':
 | ||
| 		// Matches an unsigned octal integer; the next pointer must be a pointer to
 | ||
| 		// unsigned int.
 | ||
| 		format++
 | ||
| 		panic(todo(""))
 | ||
| 	case 'u':
 | ||
| 		// Matches an unsigned decimal integer; the next pointer must be a pointer to
 | ||
| 		// unsigned int.
 | ||
| 		format++
 | ||
| 		panic(todo(""))
 | ||
| 	case 'x', 'X':
 | ||
| 		// Matches an unsigned hexadecimal integer; the next pointer must be a pointer
 | ||
| 		// to unsigned int.
 | ||
| 		format++
 | ||
| 		skipReaderWhiteSpace(r)
 | ||
| 		var digit, n uint64
 | ||
| 		allowPrefix := true
 | ||
| 		var b []byte
 | ||
| 	hex:
 | ||
| 		for ; width != 0; width-- {
 | ||
| 			c, err := r.ReadByte()
 | ||
| 			if err != nil {
 | ||
| 				if match {
 | ||
| 					break hex
 | ||
| 				}
 | ||
| 
 | ||
| 				panic(todo("", err))
 | ||
| 			}
 | ||
| 
 | ||
| 			if allowPrefix {
 | ||
| 				if len(b) == 1 && b[0] == '0' && (c == 'x' || c == 'X') {
 | ||
| 					allowPrefix = false
 | ||
| 					match = false
 | ||
| 					b = nil
 | ||
| 					continue
 | ||
| 				}
 | ||
| 
 | ||
| 				b = append(b, c)
 | ||
| 			}
 | ||
| 
 | ||
| 			switch {
 | ||
| 			case c >= '0' && c <= '9':
 | ||
| 				digit = uint64(c) - '0'
 | ||
| 			case c >= 'a' && c <= 'f':
 | ||
| 				digit = uint64(c) - 'a' + 10
 | ||
| 			case c >= 'A' && c <= 'F':
 | ||
| 				digit = uint64(c) - 'A' + 10
 | ||
| 			default:
 | ||
| 				r.UnreadByte()
 | ||
| 				break hex
 | ||
| 			}
 | ||
| 			match = true
 | ||
| 			n0 := n
 | ||
| 			n = n<<4 + digit
 | ||
| 			if n < n0 {
 | ||
| 				panic(todo(""))
 | ||
| 			}
 | ||
| 		}
 | ||
| 		if !match {
 | ||
| 			break
 | ||
| 		}
 | ||
| 
 | ||
| 		arg := VaUintptr(args)
 | ||
| 		switch mod {
 | ||
| 		case modNone:
 | ||
| 			*(*uint32)(unsafe.Pointer(arg)) = uint32(n)
 | ||
| 		case modH:
 | ||
| 			*(*uint16)(unsafe.Pointer(arg)) = uint16(n)
 | ||
| 		case modHH:
 | ||
| 			*(*byte)(unsafe.Pointer(arg)) = byte(n)
 | ||
| 		case modL:
 | ||
| 			*(*ulong)(unsafe.Pointer(arg)) = ulong(n)
 | ||
| 		default:
 | ||
| 			panic(todo(""))
 | ||
| 		}
 | ||
| 		nvalues = 1
 | ||
| 	case 'f', 'e', 'g', 'E', 'a':
 | ||
| 		// Matches an optionally signed floating-point number; the next pointer must be
 | ||
| 		// a pointer to float.
 | ||
| 		format++
 | ||
| 		panic(todo(""))
 | ||
| 	case 's':
 | ||
| 		// Matches  a  sequence of non-white-space characters; the next pointer must be
 | ||
| 		// a pointer to the initial element of a character array that is long enough to
 | ||
| 		// hold the input sequence and the terminating null byte ('\0'), which is added
 | ||
| 		// automatically.  The input string stops at white space or at the maximum
 | ||
| 		// field width, whichever occurs first.
 | ||
| 		format++
 | ||
| 		panic(todo(""))
 | ||
| 	case 'c':
 | ||
| 		// Matches a sequence of characters whose length is specified by the maximum
 | ||
| 		// field width (default 1); the next pointer must be a pointer to char, and
 | ||
| 		// there must be enough room for  all the characters (no terminating null byte
 | ||
| 		// is added).  The usual skip of leading white space is suppressed.  To skip
 | ||
| 		// white space first, use an explicit space in the format.
 | ||
| 		format++
 | ||
| 		panic(todo(""))
 | ||
| 	case '[':
 | ||
| 		// Matches  a nonempty sequence of characters from the specified set of
 | ||
| 		// accepted characters; the next pointer must be a pointer to char, and there
 | ||
| 		// must be enough room for all the char‐ acters in the string, plus a
 | ||
| 		// terminating null byte.  The usual skip of leading white space is suppressed.
 | ||
| 		// The string is to be made up of characters in (or not in) a particular set;
 | ||
| 		// the  set  is defined by the characters between the open bracket [ character
 | ||
| 		// and a close bracket ] character.  The set excludes those characters if the
 | ||
| 		// first character after the open bracket is a circumflex (^).  To include a
 | ||
| 		// close bracket in the set, make it the first character after the open bracket
 | ||
| 		// or the circumflex; any other position will end the set.   The hyphen
 | ||
| 		// character - is also special; when placed between two other characters, it
 | ||
| 		// adds all intervening characters to the set.  To include a hyphen, make it
 | ||
| 		// the last character before the final close bracket.  For instance, [^]0-9-]
 | ||
| 		// means the set "everything except close bracket, zero through nine, and
 | ||
| 		// hyphen".  The string ends with the appearance of a  character not in the
 | ||
| 		// (or, with a circumflex, in) set or when the field width runs out.
 | ||
| 		format++
 | ||
| 		panic(todo(""))
 | ||
| 	case 'p':
 | ||
| 		// Matches a pointer value (as printed by %p in printf(3); the next pointer
 | ||
| 		// must be a pointer to a pointer to void.
 | ||
| 		format++
 | ||
| 		skipReaderWhiteSpace(r)
 | ||
| 		c, err := r.ReadByte()
 | ||
| 		if err != nil {
 | ||
| 			panic(todo(""))
 | ||
| 		}
 | ||
| 
 | ||
| 		if c != '0' {
 | ||
| 			r.UnreadByte()
 | ||
| 			panic(todo(""))
 | ||
| 		}
 | ||
| 
 | ||
| 		if c, err = r.ReadByte(); err != nil {
 | ||
| 			panic(todo(""))
 | ||
| 		}
 | ||
| 
 | ||
| 		if c != 'x' && c != 'X' {
 | ||
| 			r.UnreadByte()
 | ||
| 			panic(todo(""))
 | ||
| 		}
 | ||
| 
 | ||
| 		var digit, n uint64
 | ||
| 	ptr:
 | ||
| 		for ; width != 0; width-- {
 | ||
| 			c, err := r.ReadByte()
 | ||
| 			if err != nil {
 | ||
| 				if match {
 | ||
| 					break ptr
 | ||
| 				}
 | ||
| 
 | ||
| 				panic(todo(""))
 | ||
| 			}
 | ||
| 
 | ||
| 			switch {
 | ||
| 			case c >= '0' && c <= '9':
 | ||
| 				digit = uint64(c) - '0'
 | ||
| 			case c >= 'a' && c <= 'f':
 | ||
| 				digit = uint64(c) - 'a' + 10
 | ||
| 			case c >= 'A' && c <= 'F':
 | ||
| 				digit = uint64(c) - 'A' + 10
 | ||
| 			default:
 | ||
| 				r.UnreadByte()
 | ||
| 				break ptr
 | ||
| 			}
 | ||
| 			match = true
 | ||
| 			n0 := n
 | ||
| 			n = n<<4 + digit
 | ||
| 			if n < n0 {
 | ||
| 				panic(todo(""))
 | ||
| 			}
 | ||
| 		}
 | ||
| 		if !match {
 | ||
| 			break
 | ||
| 		}
 | ||
| 
 | ||
| 		arg := VaUintptr(args)
 | ||
| 		*(*uintptr)(unsafe.Pointer(arg)) = uintptr(n)
 | ||
| 		nvalues = 1
 | ||
| 	case 'n':
 | ||
| 		// Nothing is expected; instead, the number of characters consumed thus far
 | ||
| 		// from the input is stored through the next pointer, which must be a pointer
 | ||
| 		// to int.  This is not a conversion and does not increase the count returned
 | ||
| 		// by the function.  The assignment can be suppressed with the *
 | ||
| 		// assignment-suppression character, but the effect on the return value is
 | ||
| 		// undefined.  Therefore %*n conversions should not be used.
 | ||
| 		format++
 | ||
| 		panic(todo(""))
 | ||
| 	default:
 | ||
| 		panic(todo("%#U", c))
 | ||
| 	}
 | ||
| 
 | ||
| 	return format, nvalues, match
 | ||
| }
 | ||
| 
 | ||
| func skipReaderWhiteSpace(r *strings.Reader) error {
 | ||
| 	for {
 | ||
| 		c, err := r.ReadByte()
 | ||
| 		if err != nil {
 | ||
| 			return err
 | ||
| 		}
 | ||
| 
 | ||
| 		switch c {
 | ||
| 		case ' ', '\t', '\n', '\r', '\v', '\f':
 | ||
| 			// ok
 | ||
| 		default:
 | ||
| 			r.UnreadByte()
 | ||
| 			return nil
 | ||
| 		}
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| func skipWhiteSpace(s uintptr) uintptr {
 | ||
| 	for {
 | ||
| 		switch c := *(*byte)(unsafe.Pointer(s)); c {
 | ||
| 		case ' ', '\t', '\n', '\r', '\v', '\f':
 | ||
| 			s++
 | ||
| 		default:
 | ||
| 			return s
 | ||
| 		}
 | ||
| 	}
 | ||
| }
 |