File: Write.cpp

package info (click to toggle)
storm-lang 0.7.4-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 52,004 kB
  • sloc: ansic: 261,462; cpp: 140,405; sh: 14,891; perl: 9,846; python: 2,525; lisp: 2,504; asm: 860; makefile: 678; pascal: 70; java: 52; xml: 37; awk: 12
file content (144 lines) | stat: -rw-r--r-- 3,224 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#include "stdafx.h"
#include "Write.h"
#include "Exception.h"
#include "World.h"
#include "Utils/FileStream.h"
#include "Utils/MemoryStream.h"
#include "Utils/TextReader.h"

static String lineEnds(TextReader *src) {
	String result = L"\n";
	nat pos = src->position();

	wchar prev = 0;
	while (src->more()) {
		wchar c = src->get();
		if (prev == '\r' && c == '\n') {
			result = L"\r\n";
			break;
		} else if (c == '\n') {
			result = L"\n";
			break;
		}
		prev = c;
	}

	src->seek(pos);
	return result;
}

static void generatePart(TextWriter *to, const String &indent, const String &endl, GenerateFn fn, World &world) {
	std::wostringstream tmp;
	(*fn)(tmp, world);

	String cont = tmp.str();
	bool indented = false;
	for (nat i = 0; i < cont.size(); i++) {
		if (cont[i] == '\n') {
			to->put(endl);
			indented = false;
		} else {
			if (!indented) {
				// Do not indent preprocessor directives!
				if (cont[i] != '#')
					to->put(indent);
				indented = true;
			}
			to->put(cont[i]);
		}
	}
}

static String findIndentation(const String &line) {
	for (nat i = 0; i < line.size(); i++) {
		switch (line[i]) {
		case ' ':
		case '\t':
			break;
		default:
			return line.substr(0, i);
		}
	}
	return L"";
}

void generateFile(const Path &src, const Path &dest, const GenerateMap &actions, World &world) {
	{
		Path folder = dest.parent();
		if (!folder.exists())
			folder.createDir();
	}

	FileStream *rStream = new FileStream(src, Stream::mRead);
	if (!rStream->valid()) {
		delete rStream;
		throw Error(L"Failed to open the template file: " + toS(src), SrcPos());
	}
	TextReader *read = TextReader::create(rStream);
	TextWriter *write = TextWriter::create(new FileStream(dest, Stream::mWrite), true, read->format());
	String endl = lineEnds(read);

	try {
		while (read->more()) {
			String line = read->getLine();

			write->put(line);
			write->put(endl);

			size_t pos = line.find(L"// ");
			if (pos != String::npos) {
				String part = line.substr(pos + 3);
				String indent = findIndentation(line);

				GenerateMap::const_iterator i = actions.find(part);
				if (i != actions.end()) {
					generatePart(write, indent, endl, i->second, world);
				}
			}
		}

		delete read;
		delete write;
	} catch (...) {
		delete read;
		delete write;

		// Make sure we re-run later!
		dest.deleteFile();

		throw;
	}
}

void generateDoc(const Path &out, World &world) {
	{
		Path folder = out.parent();
		if (!folder.exists())
			folder.createDir();
	}


	// Index part of the file. Contains character offsets for all entries. For entry 'n', the index
	// 'n - 1' and 'n' tells the beginning and end of the actual data.
	const vector<Auto<Doc>> src = world.documentation;
	vector<nat> index(src.size() + 1, 0);

	// Write all data to memory first.
	MemoryStream data;
	{
		textfile::Utf8Writer w(&data, false, false);
		for (nat i = 0; i < src.size(); i++) {
			w.put(src[i]->v);
			index[i + 1] = nat(data.pos());
		}
	}

	// Offset the indexes to make room for the table itself.
	for (nat i = 0; i < index.size(); i++)
		index[i] += nat(sizeof(nat)*index.size());

	// Write everything to file.
	FileStream file(out, Stream::mWrite);
	file.write(nat(sizeof(nat)*index.size()), &index[0]);
	file.write(&data);
}