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