summaryrefslogtreecommitdiffstats
path: root/vendor/modernc.org/libc/scanf.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/modernc.org/libc/scanf.go')
-rw-r--r--vendor/modernc.org/libc/scanf.go443
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 00000000..955db04e
--- /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
+ }
+ }
+}