Change from configuring a FAX scanner function to a FAX next-line function.

In order to process some NIST FAX files, we needed to implement a custom
scanner function to skip over lines that are effectively comments, but
not marked as such.

In the near future we'll need to process KAS FAX files, for which we
need not only to skip over unmarked comment lines, but also to skip some
lines of the response which the FAX doesn't include.

For this we need a more powerful callback function, which this change
provides.

Change-Id: Ibb12b97ac65b3e85317d2e97386ef1c2ea263d4b
Reviewed-on: https://boringssl-review.googlesource.com/24664
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/fipstools/run_cavp.go b/fipstools/run_cavp.go
index e5c67c0..577334a 100644
--- a/fipstools/run_cavp.go
+++ b/fipstools/run_cavp.go
@@ -34,6 +34,10 @@
 	noFAX bool
 }
 
+// nextLineState can be used by FAX next-line function to store state.
+type nextLineState struct {
+}
+
 // testSuite describes a series of tests that are handled by a single oracle
 // binary.
 type testSuite struct {
@@ -41,10 +45,13 @@
 	directory string
 	// suite names the test suite to pass as the first command-line argument.
 	suite string
-	// faxScanFunc, if not nil, is the function to use instead of
-	// (*bufio.Scanner).Scan. This can be used to skip lines.
-	faxScanFunc func(*bufio.Scanner) bool
-	tests       []test
+	// nextLineFunc, if not nil, is the function used to read the next line
+	// from the FAX file. This can be used to skip lines and/or mutate them
+	// as needed. The second argument can be used by the scanner to store
+	// state, if needed. If isWildcard is true on return then line is not
+	// meaningful and any line from the response file should be accepted.
+	nextLineFunc func(*bufio.Scanner, *nextLineState) (line string, isWildcard, ok bool)
+	tests        []test
 }
 
 func (t *testSuite) getDirectory() string {
@@ -161,10 +168,10 @@
 var rsa2SigVerTests = testSuite{
 	"RSA2",
 	"rsa2_sigver",
-	func(s *bufio.Scanner) bool {
+	func(s *bufio.Scanner, state *nextLineState) (string, bool, bool) {
 		for {
 			if !s.Scan() {
-				return false
+				return "", false, false
 			}
 
 			line := s.Text()
@@ -173,15 +180,13 @@
 			}
 			if strings.HasPrefix(line, "q = ") {
 				// Skip the "q = " line and an additional blank line.
-				if !s.Scan() {
-					return false
-				}
-				if len(strings.TrimSpace(s.Text())) > 0 {
-					return false
+				if !s.Scan() ||
+					len(strings.TrimSpace(s.Text())) > 0 {
+					return "", false, false
 				}
 				continue
 			}
-			return true
+			return line, false, true
 		}
 	},
 	[]test{
@@ -385,9 +390,14 @@
 }
 
 func compareFAX(suite *testSuite, test test) error {
-	faxScanFunc := suite.faxScanFunc
-	if faxScanFunc == nil {
-		faxScanFunc = (*bufio.Scanner).Scan
+	nextLineFunc := suite.nextLineFunc
+	if nextLineFunc == nil {
+		nextLineFunc = func(s *bufio.Scanner, state *nextLineState) (string, bool, bool) {
+			if !s.Scan() {
+				return "", false, false
+			}
+			return s.Text(), false, true
+		}
 	}
 
 	respPath := filepath.Join(suite.getDirectory(), "resp", test.inFile+".rsp")
@@ -406,6 +416,7 @@
 
 	respScanner := bufio.NewScanner(respFile)
 	faxScanner := bufio.NewScanner(faxFile)
+	var nextLineState nextLineState
 
 	lineNo := 0
 	inHeader := true
@@ -414,6 +425,7 @@
 		lineNo++
 		respLine := respScanner.Text()
 		var faxLine string
+		var isWildcard, ok bool
 
 		if inHeader && (len(respLine) == 0 || respLine[0] == '#') {
 			continue
@@ -423,8 +435,10 @@
 			haveFaxLine := false
 
 			if inHeader {
-				for faxScanFunc(faxScanner) {
-					faxLine = faxScanner.Text()
+				for {
+					if faxLine, isWildcard, ok = nextLineFunc(faxScanner, &nextLineState); !ok {
+						break
+					}
 					if len(faxLine) != 0 && faxLine[0] != '#' {
 						haveFaxLine = true
 						break
@@ -433,10 +447,7 @@
 
 				inHeader = false
 			} else {
-				if faxScanFunc(faxScanner) {
-					faxLine = faxScanner.Text()
-					haveFaxLine = true
-				}
+				faxLine, isWildcard, haveFaxLine = nextLineFunc(faxScanner, &nextLineState)
 			}
 
 			if !haveFaxLine {
@@ -454,14 +465,14 @@
 			break
 		}
 
-		if canonicalizeLine(faxLine) == canonicalizeLine(respLine) {
+		if isWildcard || canonicalizeLine(faxLine) == canonicalizeLine(respLine) {
 			continue
 		}
 
 		return fmt.Errorf("resp and fax differ at line %d for %q %q: %q vs %q", lineNo, suite.getDirectory(), test.inFile, respLine, faxLine)
 	}
 
-	if faxScanFunc(faxScanner) {
+	if _, _, ok := nextLineFunc(faxScanner, &nextLineState); ok {
 		return fmt.Errorf("fax file is longer than resp for %q %q", suite.getDirectory(), test.inFile)
 	}