diff options
Diffstat (limited to 'vendor/modernc.org/libc/scanf.go')
| -rw-r--r-- | vendor/modernc.org/libc/scanf.go | 443 | 
1 files changed, 443 insertions, 0 deletions
| diff --git a/vendor/modernc.org/libc/scanf.go b/vendor/modernc.org/libc/scanf.go new file mode 100644 index 000000000..955db04ed --- /dev/null +++ b/vendor/modernc.org/libc/scanf.go @@ -0,0 +1,443 @@ +// 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 +		} +	} +} | 
