summaryrefslogtreecommitdiff
path: root/libgo/go/fmt/scan.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/fmt/scan.go')
-rw-r--r--libgo/go/fmt/scan.go103
1 files changed, 62 insertions, 41 deletions
diff --git a/libgo/go/fmt/scan.go b/libgo/go/fmt/scan.go
index d7befeae43e..5b9b516353b 100644
--- a/libgo/go/fmt/scan.go
+++ b/libgo/go/fmt/scan.go
@@ -34,16 +34,16 @@ type ScanState interface {
ReadRune() (r rune, size int, err error)
// UnreadRune causes the next call to ReadRune to return the same rune.
UnreadRune() error
- // SkipSpace skips space in the input. Newlines are treated as space
- // unless the scan operation is Scanln, Fscanln or Sscanln, in which case
- // a newline is treated as EOF.
+ // SkipSpace skips space in the input. Newlines are treated appropriately
+ // for the operation being performed; see the package documentation
+ // for more information.
SkipSpace()
// Token skips space in the input if skipSpace is true, then returns the
// run of Unicode code points c satisfying f(c). If f is nil,
// !unicode.IsSpace(c) is used; that is, the token will hold non-space
- // characters. Newlines are treated as space unless the scan operation
- // is Scanln, Fscanln or Sscanln, in which case a newline is treated as
- // EOF. The returned slice points to shared data that may be overwritten
+ // characters. Newlines are treated appropriately for the operation being
+ // performed; see the package documentation for more information.
+ // The returned slice points to shared data that may be overwritten
// by the next call to Token, a call to a Scan function using the ScanState
// as input, or when the calling Scan method returns.
Token(skipSpace bool, f func(rune) bool) (token []byte, err error)
@@ -81,6 +81,8 @@ func Scanln(a ...interface{}) (n int, err error) {
// Scanf scans text read from standard input, storing successive
// space-separated values into successive arguments as determined by
// the format. It returns the number of items successfully scanned.
+// If that is less than the number of arguments, err will report why.
+// Newlines in the input must match newlines in the format.
func Scanf(format string, a ...interface{}) (n int, err error) {
return Fscanf(os.Stdin, format, a...)
}
@@ -113,6 +115,7 @@ func Sscanln(str string, a ...interface{}) (n int, err error) {
// Sscanf scans the argument string, storing successive space-separated
// values into successive arguments as determined by the format. It
// returns the number of items successfully parsed.
+// Newlines in the input must match newlines in the format.
func Sscanf(str string, format string, a ...interface{}) (n int, err error) {
return Fscanf((*stringReader)(&str), format, a...)
}
@@ -140,6 +143,7 @@ func Fscanln(r io.Reader, a ...interface{}) (n int, err error) {
// Fscanf scans text read from r, storing successive space-separated
// values into successive arguments as determined by the format. It
// returns the number of items successfully parsed.
+// Newlines in the input must match newlines in the format.
func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err error) {
s, old := newScanState(r, false, false)
n, err = s.doScanf(format, a)
@@ -387,17 +391,6 @@ var ssFree = sync.Pool{
// newScanState allocates a new ss struct or grab a cached one.
func newScanState(r io.Reader, nlIsSpace, nlIsEnd bool) (s *ss, old ssave) {
- // If the reader is a *ss, then we've got a recursive
- // call to Scan, so re-use the scan state.
- s, ok := r.(*ss)
- if ok {
- old = s.ssave
- s.limit = s.argLimit
- s.nlIsEnd = nlIsEnd || s.nlIsEnd
- s.nlIsSpace = nlIsSpace
- return
- }
-
s = ssFree.Get().(*ss)
if rr, ok := r.(io.RuneReader); ok {
s.rr = rr
@@ -875,34 +868,39 @@ func (s *ss) quotedString() string {
return ""
}
-// hexDigit returns the value of the hexadecimal digit
-func (s *ss) hexDigit(d rune) int {
+// hexDigit returns the value of the hexadecimal digit.
+func hexDigit(d rune) (int, bool) {
digit := int(d)
switch digit {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
- return digit - '0'
+ return digit - '0', true
case 'a', 'b', 'c', 'd', 'e', 'f':
- return 10 + digit - 'a'
+ return 10 + digit - 'a', true
case 'A', 'B', 'C', 'D', 'E', 'F':
- return 10 + digit - 'A'
+ return 10 + digit - 'A', true
}
- s.errorString("illegal hex digit")
- return 0
+ return -1, false
}
// hexByte returns the next hex-encoded (two-character) byte from the input.
-// There must be either two hexadecimal digits or a space character in the input.
+// It returns ok==false if the next bytes in the input do not encode a hex byte.
+// If the first byte is hex and the second is not, processing stops.
func (s *ss) hexByte() (b byte, ok bool) {
rune1 := s.getRune()
if rune1 == eof {
return
}
- if isSpace(rune1) {
+ value1, ok := hexDigit(rune1)
+ if !ok {
s.UnreadRune()
return
}
- rune2 := s.mustReadRune()
- return byte(s.hexDigit(rune1)<<4 | s.hexDigit(rune2)), true
+ value2, ok := hexDigit(s.mustReadRune())
+ if !ok {
+ s.errorString("illegal hex digit")
+ return
+ }
+ return byte(value1<<4 | value2), true
}
// hexString returns the space-delimited hexpair-encoded string.
@@ -1050,8 +1048,8 @@ func (s *ss) doScan(a []interface{}) (numProcessed int, err error) {
s.scanOne('v', arg)
numProcessed++
}
- // Check for newline if required.
- if !s.nlIsSpace {
+ // Check for newline (or EOF) if required (Scanln etc.).
+ if s.nlIsEnd {
for {
r := s.getRune()
if r == '\n' || r == eof {
@@ -1067,12 +1065,13 @@ func (s *ss) doScan(a []interface{}) (numProcessed int, err error) {
}
// advance determines whether the next characters in the input match
-// those of the format. It returns the number of bytes (sic) consumed
-// in the format. Newlines included, all runs of space characters in
-// either input or format behave as a single space. This routine also
-// handles the %% case. If the return value is zero, either format
-// starts with a % (with no following %) or the input is empty.
-// If it is negative, the input did not match the string.
+// those of the format. It returns the number of bytes (sic) consumed
+// in the format. All runs of space characters in either input or
+// format behave as a single space. Newlines are special, though:
+// newlines in the format must match those in the input and vice versa.
+// This routine also handles the %% case. If the return value is zero,
+// either format starts with a % (with no following %) or the input
+// is empty. If it is negative, the input did not match the string.
func (s *ss) advance(format string) (i int) {
for i < len(format) {
fmtc, w := utf8.DecodeRuneInString(format[i:])
@@ -1085,24 +1084,45 @@ func (s *ss) advance(format string) (i int) {
i += w // skip the first %
}
sawSpace := false
+ wasNewline := false
+ // Skip spaces in format but absorb at most one newline.
for isSpace(fmtc) && i < len(format) {
+ if fmtc == '\n' {
+ if wasNewline { // Already saw one; stop here.
+ break
+ }
+ wasNewline = true
+ }
sawSpace = true
i += w
fmtc, w = utf8.DecodeRuneInString(format[i:])
}
if sawSpace {
- // There was space in the format, so there should be space (EOF)
+ // There was space in the format, so there should be space
// in the input.
inputc := s.getRune()
- if inputc == eof || inputc == '\n' {
- // If we've reached a newline, stop now; don't read ahead.
+ if inputc == eof {
return
}
if !isSpace(inputc) {
- // Space in format but not in input: error
+ // Space in format but not in input.
s.errorString("expected space in input to match format")
}
- s.skipSpace(true)
+ // Skip spaces but stop at newline.
+ for inputc != '\n' && isSpace(inputc) {
+ inputc = s.getRune()
+ }
+ if inputc == '\n' {
+ if !wasNewline {
+ s.errorString("newline in input does not match format")
+ }
+ // We've reached a newline, stop now; don't read further.
+ return
+ }
+ s.UnreadRune()
+ if wasNewline {
+ s.errorString("newline in format does not match input")
+ }
continue
}
inputc := s.mustReadRune()
@@ -1144,6 +1164,7 @@ func (s *ss) doScanf(format string, a []interface{}) (numProcessed int, err erro
if !widPresent {
s.maxWid = hugeWid
}
+ s.SkipSpace()
s.argLimit = s.limit
if f := s.count + s.maxWid; f < s.argLimit {
s.argLimit = f