Implemented messaging system.
[aesalon.git] / src / config / Parser.cpp
blob9014c9bb3c23e2093713a69b9ed801e24435ddbe
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) {
75 std::string op = expectNextToken(SYMBOL);
77 if(op == "=") vault->clear(token);
79 do {
80 TokenType nextType;
81 std::string next = nextToken(nextType);
83 //if(nextType == SYMBOL && next == ";") break;
85 if(nextType == WORD || nextType == QUOTED_WORD) {
86 if(currentModule != "") vault->set(
87 Util::StreamAsString() << currentModule << ":" << token, next);
89 else vault->set(token, next);
91 /*std::cout << "Set \"" << currentModule << "::" << token << "\" to \""
92 << next << "\" with operator " << op << std::endl;*/
94 else Message(Fatal, "Invalid RHS");
96 std::string sym = expectNextToken(SYMBOL);
97 if(sym == ";") break;
98 else if(sym == ",") {}
99 else {
100 Message(Fatal, "Expected \",\" or \";\", got \"" << sym << "\"");
102 } while(true);
104 else {
105 Message(Fatal, "Syntax error at token \"" << token << "\"");
107 //std::cout << "\"" << token << "\"\n";
110 closeFile();
113 void Parser::parseDirectory(Vault *vault, const std::string &directory) {
114 DIR *dir = opendir(directory.c_str());
115 if(dir == NULL) return;
117 vault->clear("::directory");
118 vault->set("::directory", directory);
120 struct dirent *dent;
122 while((dent = readdir(dir)) != NULL) {
123 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) continue;
124 std::string possible = directory + "/";
125 possible += dent->d_name;
127 struct stat s;
128 if(stat(possible.c_str(), &s) != 0) {
129 /* Cannot stat file, probably don't have access permissions. */
130 continue;
133 possible += "/";
135 if(S_ISDIR(s.st_mode)) {
136 parse(vault, possible + AesalonModuleConfigFileName);
137 std::string path = dent->d_name;
138 path += ":root";
139 vault->clear(path);
140 vault->set(path, possible);
144 closedir(dir);
147 void Parser::openFile(const std::string &configFile) {
148 m_stream = new std::ifstream(configFile.c_str());
151 std::string Parser::nextToken(TokenType &type) {
152 std::ifstream &stream = *m_stream;
154 skipWhitespace();
156 if(stream.eof()) {
157 type = END_OF_FILE;
158 return "";
161 if(stream.peek() == '#') {
162 std::string line;
163 std::getline(stream, line);
164 return nextToken(type);
166 else if(stream.peek() == '"') {
167 stream.get(); // skip "
169 std::string word;
170 while(stream.peek() != '"') {
171 word += stream.get();
174 stream.get(); // skip "
176 type = QUOTED_WORD;
177 return word;
179 else if(std::isalnum(stream.peek())) {
180 std::string word;
181 while(std::isalnum(stream.peek())) {
182 word += stream.get();
185 type = WORD;
186 return word;
188 else if(stream.peek() == '+') {
189 stream.get(); // skip '+'
190 if(stream.peek() == '=') {
191 stream.get(); // skip '='
192 type = SYMBOL;
193 return "+=";
196 std::string rest;
197 stream >> rest;
199 Message(Fatal, "Unrecognized token: \"+" << rest << "\"");
201 else {
202 std::string token;
203 token += stream.get();
205 type = SYMBOL;
206 return token;
210 std::string Parser::expectNextToken(TokenType expected) {
211 TokenType actual;
212 std::string token = nextToken(actual);
214 if(actual != expected) {
215 Message(Fatal,
216 "Expected " << nameOf(expected) << " token, found " << nameOf(actual)
217 << " token: \"" << token << "\"");
220 return token;
223 void Parser::expectNextSymbol(const std::string &symbol) {
224 std::string s = expectNextToken(SYMBOL);
225 if(symbol != s) {
226 Message(Fatal, "Expected token \"" << symbol << "\", got \"" << s << "\"");
230 void Parser::skipWhitespace() {
231 std::ifstream &stream = *m_stream;
233 while(!stream.fail() && std::isspace(stream.peek())) {
234 stream.get();
238 void Parser::closeFile() {
239 delete m_stream;
240 m_stream = NULL;
243 const char *Parser::nameOf(TokenType type) const {
244 static const char *name[] = {
245 "WORD",
246 "QUOTED_WORD",
247 "SYMBOL",
248 "END_OF_FILE"
251 return name[type];
254 } // namespace Config