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
find_fiddle(Definition * def,const string & name)10 static Definition* find_fiddle(Definition* def, const string& name) {
11 if (MarkType::kExample == def->fMarkType && name == def->fFiddle) {
12 return def;
13 }
14 for (auto& child : def->fChildren) {
15 Definition* result = find_fiddle(child, name);
16 if (result) {
17 return result;
18 }
19 }
20 return nullptr;
21 }
22
findExample(const string & name) const23 Definition* FiddleBase::findExample(const string& name) const {
24 for (const auto& topic : fBmhParser->fTopicMap) {
25 if (topic.second->fParent) {
26 continue;
27 }
28 Definition* def = find_fiddle(topic.second, name);
29 if (def) {
30 return def;
31 }
32 }
33 return nullptr;
34 }
35
parseFiddles()36 bool FiddleBase::parseFiddles() {
37 if (!this->skipExact("{\n")) {
38 return false;
39 }
40 while (!this->eof()) {
41 if (!this->skipExact(" \"")) {
42 return false;
43 }
44 const char* nameLoc = fChar;
45 if (!this->skipToEndBracket("\"")) {
46 return false;
47 }
48 string name(nameLoc, fChar - nameLoc);
49 if (!this->skipExact("\": {\n")) {
50 return false;
51 }
52 if (!this->skipExact(" \"compile_errors\": [")) {
53 return false;
54 }
55 if (']' != this->peek()) {
56 // report compiler errors
57 int brackets = 1;
58 do {
59 if ('[' == this->peek()) {
60 ++brackets;
61 } else if (']' == this->peek()) {
62 --brackets;
63 }
64 } while (!this->eof() && this->next() && brackets > 0);
65 this->reportError("fiddle compile error");
66 }
67 if (!this->skipExact("],\n")) {
68 return false;
69 }
70 if (!this->skipExact(" \"runtime_error\": \"")) {
71 return false;
72 }
73 if ('"' != this->peek()) {
74 if (!this->skipToEndBracket('"')) {
75 return false;
76 }
77 this->reportError("fiddle runtime error");
78 }
79 if (!this->skipExact("\",\n")) {
80 return false;
81 }
82 if (!this->skipExact(" \"fiddleHash\": \"")) {
83 return false;
84 }
85 const char* hashStart = fChar;
86 if (!this->skipToEndBracket('"')) {
87 return false;
88 }
89 Definition* example = this->findExample(name);
90 if (!example) {
91 this->reportError("missing example");
92 }
93 string hash(hashStart, fChar - hashStart);
94 if (example) {
95 example->fHash = hash;
96 }
97 if (!this->skipExact("\",\n")) {
98 return false;
99 }
100 if (!this->skipExact(" \"text\": \"")) {
101 return false;
102 }
103 if ('"' != this->peek()) {
104 const char* stdOutStart = fChar;
105 do {
106 if ('\\' == this->peek()) {
107 this->next();
108 } else if ('"' == this->peek()) {
109 break;
110 }
111 } while (!this->eof() && this->next());
112 const char* stdOutEnd = fChar;
113 if (example && fTextOut) {
114 if (!this->textOut(example, stdOutStart, stdOutEnd)) {
115 return false;
116 }
117 }
118 } else {
119 if (example && fPngOut) {
120 if (!this->pngOut(example)) {
121 return false;
122 }
123 }
124 }
125 if (!this->skipExact("\"\n")) {
126 return false;
127 }
128 if (!this->skipExact(" }")) {
129 return false;
130 }
131 if ('\n' == this->peek()) {
132 break;
133 }
134 if (!this->skipExact(",\n")) {
135 return false;
136 }
137 }
138 return true;
139 }
140
textOut(Definition * example,const char * stdOutStart,const char * stdOutEnd)141 bool FiddleParser::textOut(Definition* example, const char* stdOutStart,
142 const char* stdOutEnd) {
143 bool foundStdOut = false;
144 for (auto& textOut : example->fChildren) {
145 if (MarkType::kStdOut != textOut->fMarkType) {
146 continue;
147 }
148 foundStdOut = true;
149 bool foundVolatile = false;
150 for (auto& stdOutChild : textOut->fChildren) {
151 if (MarkType::kVolatile == stdOutChild->fMarkType) {
152 foundVolatile = true;
153 break;
154 }
155 }
156 TextParser bmh(textOut);
157 EscapeParser fiddle(stdOutStart, stdOutEnd);
158 do {
159 bmh.skipWhiteSpace();
160 fiddle.skipWhiteSpace();
161 const char* bmhEnd = bmh.trimmedLineEnd();
162 const char* fiddleEnd = fiddle.trimmedLineEnd();
163 ptrdiff_t bmhLen = bmhEnd - bmh.fChar;
164 SkASSERT(bmhLen > 0);
165 ptrdiff_t fiddleLen = fiddleEnd - fiddle.fChar;
166 SkASSERT(fiddleLen > 0);
167 if (bmhLen != fiddleLen) {
168 if (!foundVolatile) {
169 bmh.reportError("mismatched stdout len\n");
170 }
171 } else if (strncmp(bmh.fChar, fiddle.fChar, fiddleLen)) {
172 if (!foundVolatile) {
173 bmh.reportError("mismatched stdout text\n");
174 }
175 }
176 bmh.skipToLineStart();
177 fiddle.skipToLineStart();
178 } while (!bmh.eof() && !fiddle.eof());
179 if (!foundStdOut) {
180 bmh.reportError("bmh %s missing stdout\n");
181 } else if (!bmh.eof() || !fiddle.eof()) {
182 if (!foundVolatile) {
183 bmh.reportError("%s mismatched stdout eof\n");
184 }
185 }
186 }
187 return true;
188 }
189