1/*
2 * Copyright 2017 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "bookmaker.h"
9
10bool FiddleBase::parseFiddles() {
11    if (!this->skipExact("{\n")) {
12        return false;
13    }
14    while (!this->eof()) {
15        if (!this->skipExact("  \"")) {
16            return false;
17        }
18        const char* nameLoc = fChar;
19        if (!this->skipToEndBracket("\"")) {
20            return false;
21        }
22        string name(nameLoc, fChar - nameLoc);
23        if (!this->skipExact("\": {\n")) {
24            return false;
25        }
26        if (!this->skipExact("    \"compile_errors\": [")) {
27            return false;
28        }
29        if (']' != this->peek()) {
30            // report compiler errors
31            int brackets = 1;
32            do {
33                if ('[' == this->peek()) {
34                    ++brackets;
35                } else if (']' == this->peek()) {
36                    --brackets;
37                }
38            } while (!this->eof() && this->next() && brackets > 0);
39            this->reportError("fiddle compile error");
40        }
41        if (!this->skipExact("],\n")) {
42            return false;
43        }
44        if (!this->skipExact("    \"runtime_error\": \"")) {
45            return false;
46        }
47        if ('"' != this->peek()) {
48            if (!this->skipToEndBracket('"')) {
49                return false;
50            }
51            this->reportError("fiddle runtime error");
52        }
53        if (!this->skipExact("\",\n")) {
54            return false;
55        }
56        if (!this->skipExact("    \"fiddleHash\": \"")) {
57            return false;
58        }
59        const char* hashStart = fChar;
60        if (!this->skipToEndBracket('"')) {
61            return false;
62        }
63        Definition* example = this->findExample(name);
64        if (!example) {
65            this->reportError("missing example");
66        }
67        string hash(hashStart, fChar - hashStart);
68        if (example) {
69            example->fHash = hash;
70        }
71        if (!this->skipExact("\",\n")) {
72            return false;
73        }
74        if (!this->skipExact("    \"text\": \"")) {
75            return false;
76        }
77        if ('"' != this->peek()) {
78            const char* stdOutStart = fChar;
79            do {
80                if ('\\' == this->peek()) {
81                    this->next();
82                } else if ('"' == this->peek()) {
83                    break;
84                }
85            } while (!this->eof() && this->next());
86            const char* stdOutEnd = fChar;
87            if (example && fTextOut) {
88                if (!this->textOut(example, stdOutStart, stdOutEnd)) {
89                    return false;
90                }
91            }
92        } else {
93            if (example && fPngOut) {
94                if (!this->pngOut(example)) {
95                    return false;
96                }
97            }
98        }
99        if (!this->skipExact("\"\n")) {
100            return false;
101        }
102        if (!this->skipExact("  }")) {
103            return false;
104        }
105        if ('\n' == this->peek()) {
106            break;
107        }
108        if (!this->skipExact(",\n")) {
109            return false;
110        }
111    }
112    return true;
113}
114
115bool FiddleParser::textOut(Definition* example, const char* stdOutStart,
116        const char* stdOutEnd) {
117    bool foundStdOut = false;
118    for (auto& textOut : example->fChildren) {
119        if (MarkType::kStdOut != textOut->fMarkType) {
120            continue;
121        }
122        foundStdOut = true;
123        bool foundVolatile = false;
124        for (auto& stdOutChild : textOut->fChildren) {
125                if (MarkType::kVolatile == stdOutChild->fMarkType) {
126                    foundVolatile = true;
127                    break;
128                }
129        }
130        TextParser bmh(textOut);
131        EscapeParser fiddle(stdOutStart, stdOutEnd);
132        do {
133            bmh.skipWhiteSpace();
134            fiddle.skipWhiteSpace();
135            const char* bmhEnd = bmh.trimmedLineEnd();
136            const char* fiddleEnd = fiddle.trimmedLineEnd();
137            ptrdiff_t bmhLen = bmhEnd - bmh.fChar;
138            SkASSERT(bmhLen > 0);
139            ptrdiff_t fiddleLen = fiddleEnd - fiddle.fChar;
140            SkASSERT(fiddleLen > 0);
141            if (bmhLen != fiddleLen) {
142                if (!foundVolatile) {
143                    bmh.reportError("mismatched stdout len\n");
144                }
145            } else  if (strncmp(bmh.fChar, fiddle.fChar, fiddleLen)) {
146                if (!foundVolatile) {
147                    bmh.reportError("mismatched stdout text\n");
148                }
149            }
150            bmh.skipToLineStart();
151            fiddle.skipToLineStart();
152        } while (!bmh.eof() && !fiddle.eof());
153        if (!foundStdOut) {
154            bmh.reportError("bmh %s missing stdout\n");
155        } else if (!bmh.eof() || !fiddle.eof()) {
156            if (!foundVolatile) {
157                bmh.reportError("%s mismatched stdout eof\n");
158            }
159        }
160    }
161    return true;
162}
163