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 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 23 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 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 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