Began implementing cpuTime module again.
[aesalon.git] / src / config / Parser.cpp
blob4d497a8527ffc0eeb239d29e5bde9dbc2845c617
1 /** Aesalon, a tool to visualize program behaviour in real time.
2 Copyright (C) 2009-2011, Aesalon development team.
4 Aesalon is distributed under the terms of the GNU GPLv3. See
5 the included file LICENSE for more information.
7 @file src/config/Parser.cpp
8 */
10 #include <cstring>
11 #include <cstdlib>
12 #include <libgen.h>
13 #include <dirent.h>
14 #include <sys/stat.h>
16 #include "config/Parser.h"
17 #include "util/StreamAsString.h"
18 #include "util/MessageSystem.h"
19 #include "Config.h"
21 namespace Config {
23 void Parser::parse(Vault *vault, const std::string &configFile) {
24 std::string currentModule;
26 openFile(configFile);
28 if(!m_stream->is_open()) return;
30 for(;;) {
31 TokenType tokenType;
32 std::string token = nextToken(tokenType);
33 if(tokenType == END_OF_FILE) break;
35 //std::cout << '"' << token << '"' << " of type " << nameOf(tokenType) << std::endl;
37 if(tokenType == WORD && token == "include") {
38 Parser().parse(vault, expectNextToken(QUOTED_WORD));
39 expectNextSymbol(";");
41 else if(tokenType == WORD && token == "module") {
42 currentModule = expectNextToken(WORD);
43 expectNextSymbol("{");
45 else if(tokenType == WORD && token == "search") {
46 char *dirpath = strdup(configFile.c_str());
47 dirpath = dirname(dirpath);
49 std::string dirname = expectNextToken(QUOTED_WORD);
51 if(dirname[0] != '/' && dirname[0] != '~') {
52 dirname = Util::StreamAsString() << dirpath << "/" << dirname;
55 Parser().parseDirectory(vault, dirname);
57 expectNextSymbol(";");
58 std::free(dirpath);
60 else if(tokenType == SYMBOL && token == "}") {
61 if(currentModule != "") {
62 currentModule = "";
64 else Message(Fatal, "Extra \"}\" in config file.");
66 else if(tokenType == WORD && token == "use") {
67 /*std::cout << "Parser: Using module \"" << expectNextToken(WORD) << "\"\n";*/
68 std::string moduleName = expectNextToken(WORD);
70 vault->set("::modules", moduleName);
72 expectNextSymbol(";");
74 else if(tokenType == WORD && token == "output") {
75 std::string spec = expectNextToken(QUOTED_WORD);
77 vault->set("::output", spec);
79 expectNextSymbol(";");
81 else if(tokenType == WORD) {
82 std::string op = expectNextToken(SYMBOL);
84 if(op == "=") vault->clear(token);
86 do {
87 TokenType nextType;
88 std::string next = nextToken(nextType);
90 //if(nextType == SYMBOL && next == ";") break;
92 if(nextType == WORD || nextType == QUOTED_WORD) {
93 if(currentModule != "") vault->set(
94 Util::StreamAsString() << currentModule << ":" << token, next);
96 else vault->set(token, next);
98 /*std::cout << "Set \"" << currentModule << "::" << token << "\" to \""
99 << next << "\" with operator " << op << std::endl;*/
101 else Message(Fatal, "Invalid RHS");
103 std::string sym = expectNextToken(SYMBOL);
104 if(sym == ";") break;
105 else if(sym == ",") {}
106 else {
107 Message(Fatal, "Expected \",\" or \";\", got \"" << sym << "\"");
109 } while(true);
111 else {
112 Message(Fatal, "Syntax error at token \"" << token << "\"");
114 //std::cout << "\"" << token << "\"\n";
117 closeFile();
120 void Parser::parseDirectory(Vault *vault, const std::string &directory) {
121 DIR *dir = opendir(directory.c_str());
122 if(dir == NULL) return;
124 vault->clear("::directory");
125 vault->set("::directory", directory);
127 struct dirent *dent;
129 while((dent = readdir(dir)) != NULL) {
130 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) continue;
131 std::string possible = directory + "/";
132 possible += dent->d_name;
134 struct stat s;
135 if(stat(possible.c_str(), &s) != 0) {
136 /* Cannot stat file, probably don't have access permissions. */
137 continue;
140 possible += "/";
142 if(S_ISDIR(s.st_mode)) {
143 parse(vault, possible + AesalonModuleConfigFileName);
144 std::string path = dent->d_name;
145 path += ":root";
146 vault->clear(path);
147 vault->set(path, possible);
151 closedir(dir);
154 void Parser::openFile(const std::string &configFile) {
155 m_stream = new std::ifstream(configFile.c_str());
158 std::string Parser::nextToken(TokenType &type) {
159 std::ifstream &stream = *m_stream;
161 skipWhitespace();
163 if(stream.eof()) {
164 type = END_OF_FILE;
165 return "";
168 if(stream.peek() == '#') {
169 std::string line;
170 std::getline(stream, line);
171 return nextToken(type);
173 else if(stream.peek() == '"') {
174 stream.get(); // skip "
176 std::string word;
177 while(stream.peek() != '"') {
178 word += stream.get();
181 stream.get(); // skip "
183 type = QUOTED_WORD;
184 return word;
186 else if(std::isalnum(stream.peek())) {
187 std::string word;
188 while(std::isalnum(stream.peek())) {
189 word += stream.get();
192 type = WORD;
193 return word;
195 else if(stream.peek() == '+') {
196 stream.get(); // skip '+'
197 if(stream.peek() == '=') {
198 stream.get(); // skip '='
199 type = SYMBOL;
200 return "+=";
203 std::string rest;
204 stream >> rest;
206 Message(Fatal, "Unrecognized token: \"+" << rest << "\"");
207 return ""; // Never reached.
209 else {
210 std::string token;
211 token += stream.get();
213 type = SYMBOL;
214 return token;
218 std::string Parser::expectNextToken(TokenType expected) {
219 TokenType actual;
220 std::string token = nextToken(actual);
222 if(actual != expected) {
223 Message(Fatal,
224 "Expected " << nameOf(expected) << " token, found " << nameOf(actual)
225 << " token: \"" << token << "\"");
228 return token;
231 void Parser::expectNextSymbol(const std::string &symbol) {
232 std::string s = expectNextToken(SYMBOL);
233 if(symbol != s) {
234 Message(Fatal, "Expected token \"" << symbol << "\", got \"" << s << "\"");
238 void Parser::skipWhitespace() {
239 std::ifstream &stream = *m_stream;
241 while(!stream.fail() && std::isspace(stream.peek())) {
242 stream.get();
246 void Parser::closeFile() {
247 delete m_stream;
248 m_stream = NULL;
251 const char *Parser::nameOf(TokenType type) const {
252 static const char *name[] = {
253 "WORD",
254 "QUOTED_WORD",
255 "SYMBOL",
256 "END_OF_FILE"
259 return name[type];
262 } // namespace Config