blob: 79503a66b3136a40e45588deb4733546ec120d75 [file] [log] [blame]
/*
* 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) {
// this->reset();
if (!sk_isdir(fileOrPath)) {
if (!this->parseFromFile(fileOrPath)) {
SkDebugf("failed to parse %s\n", fileOrPath);
return false;
}
} else {
SkOSFile::Iter it(fileOrPath, suffix);
for (SkString file; it.next(&file); ) {
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::parseSetup(const char* path) {
// this->reset();
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;
}
void ParserCommon::writeBlockIndent(int size, const char* data) {
while (size && ' ' >= data[size - 1]) {
--size;
}
bool newLine = false;
while (size) {
while (size && ' ' > data[0]) {
++data;
--size;
}
if (!size) {
return;
}
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;
}
}
bool ParserCommon::writeBlockTrim(int size, const char* data) {
if (fOutdentNext) {
fIndent -= 4;
fOutdentNext = false;
}
while (size && ' ' >= data[0]) {
++data;
--size;
}
while (size && ' ' >= data[size - 1]) {
--size;
}
if (size <= 0) {
fLastChar = '\0';
return false;
}
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);
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() {
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) {
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;
}