fmt: check newline in the end of input

Sscanf doc says:
Newlines in the input must match newlines in the format.

However Sscanf didn't check newline in the end of input (EOF).
A test for the case is broken.

* check newline in EOF
* fix the test
* slightly simplify ss.doScanf

Fixes #12788

Change-Id: Iaf6b7d81324a72e557543ac22ecea5cecb72e0d6
Reviewed-on: https://go-review.googlesource.com/16165
Run-TryBot: Rob Pike <r@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
diff --git a/src/fmt/scan.go b/src/fmt/scan.go
index 4618ed4..553deb4 100644
--- a/src/fmt/scan.go
+++ b/src/fmt/scan.go
@@ -1108,6 +1108,10 @@
 			// in the input.
 			inputc := s.getRune()
 			if inputc == eof {
+				if wasNewline {
+					// Newlines are mandatory.
+					return -1
+				}
 				return
 			}
 			if !isSpace(inputc) {
@@ -1148,17 +1152,18 @@
 	end := len(format) - 1
 	// We process one item per non-trivial format
 	for i := 0; i <= end; {
-		w := s.advance(format[i:])
-		if w > 0 {
+		switch w := s.advance(format[i:]); {
+		case w > 0:
 			i += w
 			continue
+		case w < 0:
+			// Can't advance format. Why not?
+			s.errorString("input does not match format")
 		}
-		// Either we failed to advance, we have a percent character, or we ran out of input.
+
+		// Either we have a percent character, or we ran out of input.
+
 		if format[i] != '%' {
-			// Can't advance format.  Why not?
-			if w < 0 {
-				s.errorString("input does not match format")
-			}
 			// Otherwise at EOF; "too many operands" error handled below
 			break
 		}
diff --git a/src/fmt/scan_test.go b/src/fmt/scan_test.go
index 7ac74dc..bcc2844 100644
--- a/src/fmt/scan_test.go
+++ b/src/fmt/scan_test.go
@@ -1114,14 +1114,22 @@
 		count  int
 		ok     bool
 	}{
-		{"newline in both", "1\n2", "%d\n%d\n", 2, true},
+		{"newline in both", "1\n2", "%d\n%d", 2, true},
 		{"newline in input", "1\n2", "%d %d", 1, false},
+		{"extra newline in format", "1\n2", "%d\n%d\n", 2, false},
+		{"newline-newline in both", "1\n\n2", "%d\n\n%d", 2, true},
+		{"newline-newline in format", "1\n2", "%d\n\n%d", 1, false},
+		{"newline-newline in input", "1\n\n2", "%d\n%d", 1, false},
 		{"space-newline in input", "1 \n2", "%d %d", 1, false},
 		{"newline in format", "1 2", "%d\n%d", 1, false},
 		{"space-newline in format", "1 2", "%d \n%d", 1, false},
 		{"space-newline in both", "1 \n2", "%d \n%d", 2, true},
 		{"extra space in format", "1\n2", "%d\n %d", 2, true},
 		{"two extra spaces in format", "1\n2", "%d \n %d", 2, true},
+		{"newline start in both", "\n1 2", "\n%d %d", 2, true},
+		{"newline start in format", "1 2", "\n%d %d", 0, false},
+		{"newline start in input", "\n1 2", "%d %d", 0, false},
+		{"space-newline start in input", " \n1 2", "\n%d %d", 2, true},
 	}
 	for _, test := range tests {
 		n, err := Sscanf(test.text, test.format, &a, &b)