27dddae313
This reverts commit32a4910e57
. Reason for revert: SkMatrix::toString use has been removed from flutter and has been picked up in fuchsia Additionally some bookmaker changes take into account recent additions of typedef comments and the generated header comment. Original change's description: > Revert "remove toString" > > This reverts commit5191880cbf
. > > Reason for revert: broke flutter > > Original change's description: > > remove toString > > > > toString may have been used by obsolete debugger only > > find out if that is so > > > > R=​brianosman@google.com,bsalomon@google.com > > > > Docs-Preview: https://skia.org/?cl=119894 > > Bug:830651 > > Change-Id: I737f19b7d3fbc869bea2f443fa3b5ed7c1393ffd > > Reviewed-on: https://skia-review.googlesource.com/119894 > > Commit-Queue: Cary Clark <caryclark@google.com> > > Reviewed-by: Brian Salomon <bsalomon@google.com> > > TBR=bsalomon@google.com,brianosman@google.com,caryclark@google.com,caryclark@skia.org > > Change-Id: I9f81de6c3615ee0608bcea9081b77239b4b8816c TBR=bsalomon@google.com,brianosman@google.com # Not skipping CQ checks because original CL landed > 1 day ago. Reviewed-on: https://skia-review.googlesource.com/129623 Reviewed-by: Cary Clark <caryclark@skia.org> Commit-Queue: Cary Clark <caryclark@google.com> Docs-Preview: https://skia.org/?cl=133583 Bug: 830651 Change-Id: If8499e796be63580ad419e150e94d43e8b89de1b Reviewed-on: https://skia-review.googlesource.com/133583 Commit-Queue: Cary Clark <caryclark@skia.org> Auto-Submit: Cary Clark <caryclark@skia.org>
415 lines
11 KiB
C++
415 lines
11 KiB
C++
/*
|
|
* Copyright 2017 Google Inc.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#include "bookmaker.h"
|
|
#include "SkOSFile.h"
|
|
#include "SkOSPath.h"
|
|
|
|
static void debug_out(int len, const char* data) {
|
|
// convenient place to intercept arbitrary output
|
|
SkDebugf("%.*s", len, data);
|
|
}
|
|
|
|
bool ParserCommon::parseFile(const char* fileOrPath, const char* suffix, OneFile oneFile) {
|
|
if (!sk_isdir(fileOrPath)) {
|
|
if (!this->parseFromFile(fileOrPath)) {
|
|
SkDebugf("failed to parse %s\n", fileOrPath);
|
|
return false;
|
|
}
|
|
} else if (OneFile::kNo == oneFile) {
|
|
SkOSFile::Iter it(fileOrPath, suffix);
|
|
for (SkString file; it.next(&file); ) {
|
|
// FIXME: skip difficult file for now
|
|
if (string::npos != string(file.c_str()).find("SkFontArguments")) {
|
|
continue;
|
|
}
|
|
if (string::npos != string(file.c_str()).find("SkFontStyle")) {
|
|
continue;
|
|
}
|
|
SkString p = SkOSPath::Join(fileOrPath, file.c_str());
|
|
const char* hunk = p.c_str();
|
|
if (!SkStrEndsWith(hunk, suffix)) {
|
|
continue;
|
|
}
|
|
if (!this->parseFromFile(hunk)) {
|
|
SkDebugf("failed to parse %s\n", hunk);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ParserCommon::parseStatus(const char* statusFile, const char* suffix, StatusFilter filter) {
|
|
StatusIter iter(statusFile, suffix, filter);
|
|
if (iter.empty()) {
|
|
return false;
|
|
}
|
|
for (string file; iter.next(&file); ) {
|
|
SkString p = SkOSPath::Join(iter.baseDir().c_str(), file.c_str());
|
|
const char* hunk = p.c_str();
|
|
if (!this->parseFromFile(hunk)) {
|
|
SkDebugf("failed to parse %s\n", hunk);
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ParserCommon::parseSetup(const char* path) {
|
|
sk_sp<SkData> data = SkData::MakeFromFileName(path);
|
|
if (nullptr == data.get()) {
|
|
SkDebugf("%s missing\n", path);
|
|
return false;
|
|
}
|
|
const char* rawText = (const char*) data->data();
|
|
bool hasCR = false;
|
|
size_t dataSize = data->size();
|
|
for (size_t index = 0; index < dataSize; ++index) {
|
|
if ('\r' == rawText[index]) {
|
|
hasCR = true;
|
|
break;
|
|
}
|
|
}
|
|
string name(path);
|
|
if (hasCR) {
|
|
vector<char> lfOnly;
|
|
for (size_t index = 0; index < dataSize; ++index) {
|
|
char ch = rawText[index];
|
|
if ('\r' == rawText[index]) {
|
|
ch = '\n';
|
|
if ('\n' == rawText[index + 1]) {
|
|
++index;
|
|
}
|
|
}
|
|
lfOnly.push_back(ch);
|
|
}
|
|
fLFOnly[name] = lfOnly;
|
|
dataSize = lfOnly.size();
|
|
rawText = &fLFOnly[name].front();
|
|
}
|
|
fRawData[name] = data;
|
|
fStart = rawText;
|
|
fLine = rawText;
|
|
fChar = rawText;
|
|
fEnd = rawText + dataSize;
|
|
fFileName = string(path);
|
|
fLineCount = 1;
|
|
return true;
|
|
}
|
|
|
|
bool ParserCommon::writeBlockIndent(int size, const char* data) {
|
|
bool wroteSomething = false;
|
|
while (size && ' ' >= data[size - 1]) {
|
|
--size;
|
|
}
|
|
bool newLine = false;
|
|
while (size) {
|
|
while (size && ' ' > data[0]) {
|
|
++data;
|
|
--size;
|
|
}
|
|
if (!size) {
|
|
return wroteSomething;
|
|
}
|
|
if (fReturnOnWrite) {
|
|
return true;
|
|
}
|
|
if (newLine) {
|
|
this->lf(1);
|
|
}
|
|
TextParser parser(fFileName, data, data + size, fLineCount);
|
|
const char* lineEnd = parser.strnchr('\n', data + size);
|
|
int len = lineEnd ? (int) (lineEnd - data) : size;
|
|
this->writePending();
|
|
this->indentToColumn(fIndent);
|
|
if (fDebugOut) {
|
|
debug_out(len, data);
|
|
}
|
|
fprintf(fOut, "%.*s", len, data);
|
|
size -= len;
|
|
data += len;
|
|
newLine = true;
|
|
wroteSomething = true;
|
|
}
|
|
return wroteSomething;
|
|
}
|
|
|
|
bool ParserCommon::writeBlockTrim(int size, const char* data) {
|
|
SkASSERT(size >= 0);
|
|
if (!fReturnOnWrite && fOutdentNext) {
|
|
fIndent -= 4;
|
|
fOutdentNext = false;
|
|
}
|
|
while (size && ' ' >= data[0]) {
|
|
++data;
|
|
--size;
|
|
}
|
|
while (size && ' ' >= data[size - 1]) {
|
|
--size;
|
|
}
|
|
if (size <= 0) {
|
|
if (!fReturnOnWrite) {
|
|
fLastChar = '\0';
|
|
}
|
|
return false;
|
|
}
|
|
if (fReturnOnWrite) {
|
|
return true;
|
|
}
|
|
SkASSERT(size < 16000);
|
|
if (size > 3 && !strncmp("#end", data, 4)) {
|
|
fMaxLF = 1;
|
|
}
|
|
if (this->leadingPunctuation(data, (size_t) size)) {
|
|
fPendingSpace = 0;
|
|
}
|
|
this->writePending();
|
|
if (fDebugOut) {
|
|
debug_out(size, data);
|
|
}
|
|
fprintf(fOut, "%.*s", size, data);
|
|
fWroteSomething = true;
|
|
int added = 0;
|
|
fLastChar = data[size - 1];
|
|
while (size > 0 && '\n' != data[--size]) {
|
|
++added;
|
|
}
|
|
fColumn = size ? added : fColumn + added;
|
|
fSpaces = 0;
|
|
fLinefeeds = 0;
|
|
fMaxLF = added > 2 && !strncmp("#if", &data[size + (size > 0)], 3) ? 1 : 2;
|
|
if (fOutdentNext) {
|
|
fIndent -= 4;
|
|
fOutdentNext = false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void ParserCommon::writePending() {
|
|
SkASSERT(!fReturnOnWrite);
|
|
fPendingLF = SkTMin(fPendingLF, fMaxLF);
|
|
bool wroteLF = false;
|
|
while (fLinefeeds < fPendingLF) {
|
|
if (fDebugOut) {
|
|
SkDebugf("\n");
|
|
}
|
|
fprintf(fOut, "\n");
|
|
++fLinefeeds;
|
|
wroteLF = true;
|
|
}
|
|
fPendingLF = 0;
|
|
if (wroteLF) {
|
|
SkASSERT(0 == fColumn);
|
|
SkASSERT(fIndent >= fSpaces);
|
|
if (fDebugOut) {
|
|
SkDebugf("%*s", fIndent - fSpaces, "");
|
|
}
|
|
fprintf(fOut, "%*s", fIndent - fSpaces, "");
|
|
fColumn = fIndent;
|
|
fSpaces = fIndent;
|
|
}
|
|
for (int index = 0; index < fPendingSpace; ++index) {
|
|
if (fDebugOut) {
|
|
SkDebugf(" ");
|
|
}
|
|
fprintf(fOut, " ");
|
|
++fColumn;
|
|
}
|
|
fPendingSpace = 0;
|
|
}
|
|
|
|
void ParserCommon::writeString(const char* str) {
|
|
SkASSERT(!fReturnOnWrite);
|
|
const size_t len = strlen(str);
|
|
SkASSERT(len > 0);
|
|
SkASSERT(' ' < str[0]);
|
|
fLastChar = str[len - 1];
|
|
SkASSERT(' ' < fLastChar);
|
|
SkASSERT(!strchr(str, '\n'));
|
|
if (this->leadingPunctuation(str, strlen(str))) {
|
|
fPendingSpace = 0;
|
|
}
|
|
this->writePending();
|
|
if (fDebugOut) {
|
|
debug_out((int) strlen(str), str);
|
|
}
|
|
fprintf(fOut, "%s", str);
|
|
fColumn += len;
|
|
fSpaces = 0;
|
|
fLinefeeds = 0;
|
|
fMaxLF = 2;
|
|
}
|
|
|
|
char* ParserCommon::ReadToBuffer(string filename, int* size) {
|
|
FILE* file = fopen(filename.c_str(), "rb");
|
|
if (!file) {
|
|
return nullptr;
|
|
}
|
|
fseek(file, 0L, SEEK_END);
|
|
*size = (int) ftell(file);
|
|
rewind(file);
|
|
char* buffer = new char[*size];
|
|
memset(buffer, ' ', *size);
|
|
SkAssertResult(*size == (int)fread(buffer, 1, *size, file));
|
|
fclose(file);
|
|
fflush(file);
|
|
return buffer;
|
|
}
|
|
|
|
char* ParserCommon::FindDateTime(char* buffer, int size) {
|
|
int index = -1;
|
|
int lineCount = 8;
|
|
while (++index < size && ('\n' != buffer[index] || --lineCount))
|
|
;
|
|
if (lineCount) {
|
|
return nullptr;
|
|
}
|
|
if (strncmp("\n on 20", &buffer[index], 9)) {
|
|
return nullptr;
|
|
}
|
|
return &buffer[index];
|
|
}
|
|
|
|
bool ParserCommon::writtenFileDiffers(string filename, string readname) {
|
|
int writtenSize, readSize;
|
|
char* written = ReadToBuffer(filename, &writtenSize);
|
|
if (!written) {
|
|
return true;
|
|
}
|
|
char* read = ReadToBuffer(readname, &readSize);
|
|
if (!read) {
|
|
delete[] written;
|
|
return true;
|
|
}
|
|
#if 0 // enable for debugging this
|
|
int smaller = SkTMin(writtenSize, readSize);
|
|
for (int index = 0; index < smaller; ++index) {
|
|
if (written[index] != read[index]) {
|
|
SkDebugf("%.*s\n", 40, &written[index]);
|
|
SkDebugf("%.*s\n", 40, &read[index]);
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
if (readSize != writtenSize) {
|
|
return true;
|
|
}
|
|
// force the date/time to be the same, if present in both
|
|
const char* newDateTime = FindDateTime(written, writtenSize);
|
|
char* oldDateTime = FindDateTime(read, readSize);
|
|
if (newDateTime && oldDateTime) {
|
|
memcpy(oldDateTime, newDateTime, 26);
|
|
}
|
|
bool result = !!memcmp(written, read, writtenSize);
|
|
delete[] written;
|
|
delete[] read;
|
|
return result;
|
|
}
|
|
|
|
StatusIter::StatusIter(const char* statusFile, const char* suffix, StatusFilter filter)
|
|
: fSuffix(suffix)
|
|
, fFilter(filter) {
|
|
if (!this->parseFromFile(statusFile)) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
static const char* block_names[] = {
|
|
"Completed",
|
|
"InProgress",
|
|
};
|
|
|
|
string StatusIter::baseDir() {
|
|
SkASSERT(fStack.back().fObject.isArray());
|
|
SkASSERT(fStack.size() > 2);
|
|
string dir;
|
|
for (unsigned index = 2; index < fStack.size(); ++index) {
|
|
dir += fStack[index].fName;
|
|
if (index < fStack.size() - 1) {
|
|
dir += SkOSPath::SEPARATOR;
|
|
}
|
|
}
|
|
return dir;
|
|
}
|
|
|
|
// FIXME: need to compare fBlockName against fFilter
|
|
// need to compare fSuffix against next value returned
|
|
bool StatusIter::next(string* str) {
|
|
JsonStatus* status;
|
|
do {
|
|
do {
|
|
if (fStack.empty()) {
|
|
return false;
|
|
}
|
|
status = &fStack.back();
|
|
if (status->fIter != status->fObject.end()) {
|
|
break;
|
|
}
|
|
fStack.pop_back();
|
|
} while (true);
|
|
if (1 == fStack.size()) {
|
|
do {
|
|
StatusFilter blockType = StatusFilter::kUnknown;
|
|
for (unsigned index = 0; index < SK_ARRAY_COUNT(block_names); ++index) {
|
|
if (status->fIter.key().asString() == block_names[index]) {
|
|
blockType = (StatusFilter) index;
|
|
break;
|
|
}
|
|
}
|
|
if (blockType <= fFilter) {
|
|
break;
|
|
}
|
|
status->fIter++;
|
|
} while (status->fIter != status->fObject.end());
|
|
if (status->fIter == status->fObject.end()) {
|
|
continue;
|
|
}
|
|
}
|
|
if (!status->fObject.isArray()) {
|
|
SkASSERT(status->fIter != status->fObject.end());
|
|
JsonStatus block = {
|
|
*status->fIter,
|
|
status->fIter->begin(),
|
|
status->fIter.key().asString()
|
|
};
|
|
fStack.emplace_back(block);
|
|
status = &(&fStack.back())[-1];
|
|
status->fIter++;
|
|
status = &fStack.back();
|
|
continue;
|
|
}
|
|
*str = status->fIter->asString();
|
|
status->fIter++;
|
|
if (str->length() - strlen(fSuffix) == str->find(fSuffix)) {
|
|
return true;
|
|
}
|
|
} while (true);
|
|
return true;
|
|
}
|
|
|
|
bool StatusIter::parseFromFile(const char* path) {
|
|
sk_sp<SkData> json(SkData::MakeFromFileName(path));
|
|
if (!json) {
|
|
SkDebugf("file %s:\n", path);
|
|
return this->reportError<bool>("file not readable");
|
|
}
|
|
Json::Reader reader;
|
|
const char* data = (const char*)json->data();
|
|
if (!reader.parse(data, data+json->size(), fRoot)) {
|
|
SkDebugf("file %s:\n", path);
|
|
return this->reportError<bool>("file not parsable");
|
|
}
|
|
JsonStatus block = { fRoot, fRoot.begin(), "" };
|
|
fStack.emplace_back(block);
|
|
return true;
|
|
}
|
|
|
|
void StatusIter::reset() {
|
|
fStack.clear();
|
|
}
|