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