1bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark/*
2bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark * Copyright 2017 Google Inc.
3bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark *
4bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark * Use of this source code is governed by a BSD-style license that can be
5bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark * found in the LICENSE file.
6bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark */
7bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark
8bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark#include "bookmaker.h"
9bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark
10bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark#include "SkOSFile.h"
11bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark#include "SkOSPath.h"
12bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark
13bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clarkbool Catalog::appendFile(const string& path) {
14bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    FILE* file = fopen(path.c_str(), "r");
15bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    if (!file) {
16bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        SkDebugf("could not append %s\n", path.c_str());
17bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        return false;
18bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    }
19bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    fseek(file, 0L, SEEK_END);
20bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    int sz = (int) ftell(file);
21bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    rewind(file);
22bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    char* buffer = new char[sz];
23bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    memset(buffer, ' ', sz);
24028b32c9d58ba927fc47cd80176b44c742cbb57dBrian Osman    SkAssertResult(sz == (int)fread(buffer, 1, sz, file));
25bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    fclose(file);
26bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    this->writeBlock(sz, buffer);
27bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    return true;
28bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark}
29bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark
30bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clarkbool Catalog::openCatalog(const char* inDir, const char* outDir) {
31bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    fDocsDir = inDir;
32bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    if ('/' != fDocsDir.back()) {
33bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        fDocsDir += '/';
34bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    }
35bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    string outie = outDir;
36bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    if ('/' != outie.back()) {
37bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        outie += '/';
38bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    }
39bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    fFullName = outie + "catalog.htm";
40bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    fOut = fopen(fFullName.c_str(), "wb");
41bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    if (!fOut) {
42bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        SkDebugf("could not open output file %s\n", fFullName.c_str());
43bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        return false;
44bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    }
45bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    fContinuation = false;
46bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    if (!appendFile(fDocsDir + "catalogHeader.txt")) {
47bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        return false;
48bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    }
49bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    this->lf(1);
50bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    return true;
51bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark}
52bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark
532f466242c7289b246d7ef665aa50006cfd11aa36Cary Clarkbool Catalog::openStatus(const char* statusFile, const char* outDir) {
542f466242c7289b246d7ef665aa50006cfd11aa36Cary Clark    StatusIter iter(statusFile, ".bmh", StatusFilter::kInProgress);
552f466242c7289b246d7ef665aa50006cfd11aa36Cary Clark    string unused;
562f466242c7289b246d7ef665aa50006cfd11aa36Cary Clark    // FIXME: iterate through only chosen files by setting fDocsDir to iter
572f466242c7289b246d7ef665aa50006cfd11aa36Cary Clark    // read one file to find directory
582f466242c7289b246d7ef665aa50006cfd11aa36Cary Clark    if (!iter.next(&unused)) {
592f466242c7289b246d7ef665aa50006cfd11aa36Cary Clark        return false;
602f466242c7289b246d7ef665aa50006cfd11aa36Cary Clark    }
612f466242c7289b246d7ef665aa50006cfd11aa36Cary Clark    return openCatalog(iter.baseDir().c_str(), outDir);
622f466242c7289b246d7ef665aa50006cfd11aa36Cary Clark}
632f466242c7289b246d7ef665aa50006cfd11aa36Cary Clark
64bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clarkbool Catalog::closeCatalog() {
65bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    if (fOut) {
66bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        this->lf(1);
67bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        this->writeString("}");
68bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        this->lf(1);
69bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        if (!appendFile(fDocsDir + "catalogTrailer.txt")) {
70bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark            return false;
71bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        }
72bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        this->lf(1);
73bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        this->writePending();
74bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        fclose(fOut);
75bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        SkDebugf("wrote %s\n", fFullName.c_str());
76bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        fOut = nullptr;
77bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    }
78bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    return true;
79bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark}
80bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark
81bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clarkbool Catalog::parseFromFile(const char* path) {
82bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    if (!INHERITED::parseSetup(path)) {
83bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        return false;
84bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    }
85bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    fIndent = 4;
86bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    this->writeString("var text = {");
87bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    this->lf(1);
88bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    fTextOut = true;
89bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    TextParser::Save save(this);
90bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    if (!parseFiddles()) {
91bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        return false;
92bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    }
93bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    this->lf(1);
94bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    this->writeString("}");
95bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    this->lf(2);
96bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    this->writeString("var pngs = {");
97bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    fTextOut = false;
98bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    fPngOut = true;
99bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    save.restore();
100bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    fContinuation = false;
101bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    return parseFiddles();
102bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark}
103bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark
104bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clarkbool Catalog::pngOut(Definition* example) {
105bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    string result;
106bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    if (!example->exampleToScript(&result, Definition::ExampleOptions::kPng)) {
107bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        return false;
108bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    }
109bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    if (result.length() > 0) {
110bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        if (fContinuation) {
111bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark            this->writeString(",");
112bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark            this->lf(1);
113bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        } else {
114bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark            fContinuation = true;
115bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        }
116bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        this->writeBlock(result.size(), result.c_str());
117bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    }
118bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    return true;
119bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark}
120bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark
121c896eddc1cf77ffaaa0d0cb68caac7e251cdb727Cary Clarkbool Catalog::textOut(Definition* def, const char* stdOutStart,
122bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    const char* stdOutEnd) {
123bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    string result;
124c896eddc1cf77ffaaa0d0cb68caac7e251cdb727Cary Clark    if (!def->exampleToScript(&result, Definition::ExampleOptions::kText)) {
125bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        return false;
126bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    }
127bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    if (result.length() > 0) {
128bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        if (fContinuation) {
129bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark            this->writeString(",");
130bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark            this->lf(1);
131bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        } else {
132bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark            fContinuation = true;
133bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        }
134bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        fIndent = 8;
135bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        this->writeBlock(result.size(), result.c_str());
136bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        this->lf(1);
137bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        this->writeString("\"stdout\": \"");
138bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        size_t pos = 0;
139bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        size_t len = stdOutEnd - stdOutStart;
140bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        string example;
141c896eddc1cf77ffaaa0d0cb68caac7e251cdb727Cary Clark        const Definition* stdOut = def->hasChild(MarkType::kStdOut);
142c896eddc1cf77ffaaa0d0cb68caac7e251cdb727Cary Clark        const Definition* outVolatile = stdOut ? stdOut->hasChild(MarkType::kVolatile) : nullptr;
143c896eddc1cf77ffaaa0d0cb68caac7e251cdb727Cary Clark        if (outVolatile) {
144c896eddc1cf77ffaaa0d0cb68caac7e251cdb727Cary Clark            stdOutStart = outVolatile->fContentStart;
145c896eddc1cf77ffaaa0d0cb68caac7e251cdb727Cary Clark            while ('\n' == stdOutStart[0]) {
146c896eddc1cf77ffaaa0d0cb68caac7e251cdb727Cary Clark                ++stdOutStart;
147c896eddc1cf77ffaaa0d0cb68caac7e251cdb727Cary Clark            }
148c896eddc1cf77ffaaa0d0cb68caac7e251cdb727Cary Clark            len = stdOut->fContentEnd - stdOutStart;
149c896eddc1cf77ffaaa0d0cb68caac7e251cdb727Cary Clark        }
150bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        while ((size_t) pos < len) {
151bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark            example += '"' == stdOutStart[pos] ? "\\\"" :
152bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark                '\\' == stdOutStart[pos] ? "\\\\" :
153c896eddc1cf77ffaaa0d0cb68caac7e251cdb727Cary Clark                '\n' == stdOutStart[pos] ? "\\\\n" :
154bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark                string(&stdOutStart[pos], 1);
155c896eddc1cf77ffaaa0d0cb68caac7e251cdb727Cary Clark            if (outVolatile && '\n' == stdOutStart[pos]) {
156c896eddc1cf77ffaaa0d0cb68caac7e251cdb727Cary Clark                ++pos;
157c896eddc1cf77ffaaa0d0cb68caac7e251cdb727Cary Clark                while ((size_t) pos < len && ' ' == stdOutStart[pos]) {
158c896eddc1cf77ffaaa0d0cb68caac7e251cdb727Cary Clark                    ++pos;
159c896eddc1cf77ffaaa0d0cb68caac7e251cdb727Cary Clark                }
160c896eddc1cf77ffaaa0d0cb68caac7e251cdb727Cary Clark                continue;
161c896eddc1cf77ffaaa0d0cb68caac7e251cdb727Cary Clark            }
162bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark            ++pos;
163bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        }
164c896eddc1cf77ffaaa0d0cb68caac7e251cdb727Cary Clark        if (outVolatile) {
165c896eddc1cf77ffaaa0d0cb68caac7e251cdb727Cary Clark            example += "\\\\n";
166c896eddc1cf77ffaaa0d0cb68caac7e251cdb727Cary Clark        }
167bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        this->writeBlock(example.length(), example.c_str());
168bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        this->writeString("\"");
169bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        this->lf(1);
170bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        fIndent = 4;
171bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark        this->writeString("}");
172bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    }
173bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark    return true;
174bef063af14d0608a5c40fe4473fbfaf1db591603Cary Clark}
175