refactor bookmaker

mostly create include files with minimum
content

TBR=caryclark@google.com

Bug: skia:
Change-Id: I3db0f913cc108bd5ef8ec6c3b229eaccc3f25198
Reviewed-on: https://skia-review.googlesource.com/c/167302
Commit-Queue: Cary Clark <caryclark@skia.org>
Auto-Submit: Cary Clark <caryclark@skia.org>
Reviewed-by: Cary Clark <caryclark@skia.org>
diff --git a/tools/bookmaker/textParser.cpp b/tools/bookmaker/textParser.cpp
new file mode 100644
index 0000000..6ea4a24
--- /dev/null
+++ b/tools/bookmaker/textParser.cpp
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "definition.h"
+
+#ifdef SK_BUILD_FOR_WIN
+#include <Windows.h>
+#endif
+
+TextParser::TextParser(const Definition* definition) :
+    TextParser(definition->fFileName, definition->fContentStart, definition->fContentEnd,
+        definition->fLineCount) {
+}
+
+string TextParser::ReportFilename(string file) {
+	string fullName;
+#ifdef SK_BUILD_FOR_WIN
+	TCHAR pathChars[MAX_PATH];
+	DWORD pathLen = GetCurrentDirectory(MAX_PATH, pathChars);
+	for (DWORD index = 0; index < pathLen; ++index) {
+		fullName += pathChars[index] == (char)pathChars[index] ? (char)pathChars[index] : '?';
+	}
+	fullName += '\\';
+#endif
+	fullName += file;
+    return fullName;
+}
+
+void TextParser::reportError(const char* errorStr) const {
+    this->reportWarning(errorStr);
+    SkDebugf("");  // convenient place to set a breakpoint
+}
+
+void TextParser::reportWarning(const char* errorStr) const {
+    const char* lineStart = fLine;
+    if (lineStart >= fEnd) {
+        lineStart = fChar;
+    }
+    SkASSERT(lineStart < fEnd);
+    TextParser err(fFileName, lineStart, fEnd, fLineCount);
+    size_t lineLen = this->lineLength();
+    ptrdiff_t spaces = fChar - lineStart;
+    while (spaces > 0 && (size_t) spaces > lineLen) {
+        ++err.fLineCount;
+        err.fLine += lineLen;
+        spaces -= lineLen;
+        lineLen = err.lineLength();
+    }
+	string fullName = this->ReportFilename(fFileName);
+    SkDebugf("\n%s(%zd): error: %s\n", fullName.c_str(), err.fLineCount, errorStr);
+    if (0 == lineLen) {
+        SkDebugf("[blank line]\n");
+    } else {
+        while (lineLen > 0 && '\n' == err.fLine[lineLen - 1]) {
+            --lineLen;
+        }
+        SkDebugf("%.*s\n", (int) lineLen, err.fLine);
+        SkDebugf("%*s^\n", (int) spaces, "");
+    }
+}
+
+void TextParser::setForErrorReporting(const Definition* definition, const char* str) {
+    fFileName = definition->fFileName;
+    fStart = definition->fContentStart;
+    fLine = str;
+    while (fLine > fStart && fLine[-1] != '\n') {
+        --fLine;
+    }
+    fChar = str;
+    fEnd = definition->fContentEnd;
+    fLineCount = definition->fLineCount;
+    const char* lineInc = fStart;
+    while (lineInc < str) {
+        fLineCount += '\n' == *lineInc++;
+    }
+}
+
+string TextParser::typedefName() {
+    // look for typedef as one of three forms:
+    // typedef return-type (*NAME)(params);
+    // typedef alias NAME;
+    // typedef std::function<alias> NAME;
+    string builder;
+    const char* end = this->doubleLF();
+    if (!end) {
+       end = fEnd;
+    }
+    const char* altEnd = this->strnstr("#Typedef ##", end);
+    if (altEnd) {
+        end = this->strnchr('\n', end);
+    }
+    if (!end) {
+        return this->reportError<string>("missing typedef std::function end bracket >");
+    }
+    bool stdFunction = this->startsWith("std::function");
+    if (stdFunction) {
+        if (!this->skipToEndBracket('>')) {
+            return this->reportError<string>("missing typedef std::function end bracket >");
+        }
+        this->next();
+        this->skipWhiteSpace();
+        builder += string(fChar, end - fChar);
+    } else {
+        const char* paren = this->strnchr('(', end);
+        if (!paren) {
+            const char* lastWord = nullptr;
+            do {
+                this->skipToWhiteSpace();
+                if (fChar < end && isspace(fChar[0])) {
+                    const char* whiteStart = fChar;
+                    this->skipWhiteSpace();
+                    // FIXME: test should be for fMC
+                    if ('#' == fChar[0]) {
+                        end = whiteStart;
+                        break;
+                    }
+                    lastWord = fChar;
+                } else {
+                    break;
+                }
+            } while (true);
+            if (!lastWord) {
+                return this->reportError<string>("missing typedef name");
+            }
+            builder += string(lastWord, end - lastWord);
+        } else {
+            this->skipTo(paren);
+            this->next();
+            if ('*' != this->next()) {
+                return this->reportError<string>("missing typedef function asterisk");
+            }
+            const char* nameStart = fChar;
+            if (!this->skipToEndBracket(')')) {
+                return this->reportError<string>("missing typedef function )");
+            }
+            builder += string(nameStart, fChar - nameStart);
+            if (!this->skipToEndBracket('(')) {
+                return this->reportError<string>("missing typedef params (");
+            }
+            if (! this->skipToEndBracket(')')) {
+                return this->reportError<string>("missing typedef params )");
+            }
+            this->skipTo(end);
+        }
+    }
+    return builder;
+}
+
+void MethodParser::skipToMethodEnd(Resolvable resolvable) {
+    if (this->eof()) {
+        return;
+    }
+    string name = fLocalName.length() ? fLocalName : fClassName;
+    if ('~' == this->peek()) {
+        this->next();
+        if (!this->startsWith(name.c_str())) {
+            --fChar;
+            return;
+        }
+    }
+    if (Resolvable::kSimple != resolvable
+            && Resolvable::kInclude != resolvable
+            && (this->startsWith(name.c_str()) || this->startsWith("operator"))) {
+        const char* ptr = this->anyOf("\n (");
+        if (ptr && '(' ==  *ptr && strncmp(ptr, "(...", 4)) {
+            this->skipToEndBracket(')');
+            SkAssertResult(')' == this->next());
+            this->skipExact("_const") || (Resolvable::kCode == resolvable
+                    && this->skipExact(" const"));
+            return;
+        }
+    }
+    if (this->startsWith("Sk") && this->wordEndsWith(".h")) {  // allow include refs
+        this->skipToNonName();
+    } else {
+        this->skipFullName();
+        if (this->endsWith("operator")) {
+            const char* ptr = this->anyOf("\n (");
+            if (ptr && '(' ==  *ptr) {
+                this->skipToEndBracket(')');
+                SkAssertResult(')' == this->next());
+                this->skipExact("_const");
+            }
+        }
+    }
+}