Began implementing the VCommunication namespace.
[aesalon.git] / monitor / src / config / Parser.cpp
blobe8d22e6ab59691a88a5ff3f6ddeafbd39eaea279
1 /**
2 Aesalon, a tool to visualize a program's behaviour at run-time.
3 Copyright (C) 2010, Aesalon Development Team.
5 Aesalon is distributed under the terms of the GNU GPLv3. For more
6 licensing information, see the file LICENSE included with the distribution.
8 @file monitor/src/config/Parser.cpp
12 #include <iostream> // for debugging
13 #include <sstream>
14 #include <fstream>
15 #include <string>
16 #include <cctype>
17 #include <sys/types.h>
18 #include <dirent.h>
19 #include <stdlib.h>
20 #include <cstring>
21 #include <libgen.h>
23 #include "config/Parser.h"
24 #include "common/ParsingException.h"
25 #include "common/StreamAsString.h"
26 #include "common/PathSanitizer.h"
27 #include "config/ConcreteVault.h"
28 #include "common/Config.h"
30 namespace Monitor {
31 namespace Config {
33 void Parser::parse(ConcreteVault *vault, const std::string &configFile) {
34 std::string currentModule;
36 openFile(configFile);
38 if(!m_stream->is_open()) return;
40 for(;;) {
41 TokenType tokenType;
42 std::string token = nextToken(tokenType);
43 if(tokenType == END_OF_FILE) break;
45 //std::cout << '"' << token << '"' << " of type " << nameOf(tokenType) << std::endl;
47 if(tokenType == WORD && token == "include") {
48 Parser().parse(vault, expectNextToken(QUOTED_WORD));
49 expectNextSymbol(";");
51 else if(tokenType == WORD && token == "module") {
52 currentModule = expectNextToken(WORD);
53 expectNextSymbol("{");
55 else if(tokenType == WORD && token == "search") {
56 char *dirpath = strdup(configFile.c_str());
57 dirpath = dirname(dirpath);
59 std::string dirname = expectNextToken(QUOTED_WORD);
61 if(dirname[0] != '/' && dirname[0] != '~') {
62 dirname = Common::StreamAsString() << dirpath << "/" << dirname;
65 Parser().parseDirectory(vault, dirname);
67 expectNextSymbol(";");
68 free(dirpath);
70 else if(tokenType == SYMBOL && token == "}") {
71 if(currentModule != "") {
72 currentModule = "";
74 else throw Common::ParsingException("Extra \"}\"");
76 else if(tokenType == WORD && token == "use") {
77 /*std::cout << "Parser: Using module \"" << expectNextToken(WORD) << "\"\n";*/
78 std::string moduleName = expectNextToken(WORD);
80 vault->set("::modules", moduleName);
82 expectNextSymbol(";");
84 else if(tokenType == WORD) {
85 std::string op = expectNextToken(SYMBOL);
87 if(op == "=") vault->clear(token);
89 do {
90 TokenType nextType;
91 std::string next = nextToken(nextType);
93 //if(nextType == SYMBOL && next == ";") break;
95 if(nextType == WORD || nextType == QUOTED_WORD) {
96 if(currentModule != "") vault->set(
97 Common::StreamAsString() << currentModule << ":" << token, next);
99 else vault->set(token, next);
101 /*std::cout << "Set \"" << currentModule << "::" << token << "\" to \""
102 << next << "\" with operator " << op << std::endl;*/
104 else throw Common::ParsingException("Invalid RHS");
106 std::string sym = expectNextToken(SYMBOL);
107 if(sym == ";") break;
108 else if(sym == ",") {}
109 else {
110 throw Common::ParsingException(Common::StreamAsString()
111 << "Expected \",\" or \";\", got \"" << sym << "\"");
113 } while(true);
115 else {
116 throw Common::ParsingException(Common::StreamAsString()
117 << "Syntax error at token \"" << token << "\"");
119 //std::cout << "\"" << token << "\"\n";
122 closeFile();
125 void Parser::parseDirectory(ConcreteVault *vault, const std::string &directory) {
126 DIR *dir = opendir(directory.c_str());
127 if(dir == NULL) return;
129 vault->clear("::directory");
130 vault->set("::directory", directory);
132 struct dirent *dent;
134 while((dent = readdir(dir)) != NULL) {
135 if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) continue;
136 std::string possible = directory + "/";
137 possible += dent->d_name;
139 struct stat s;
140 if(stat(possible.c_str(), &s) != 0) {
141 /* Cannot stat file, probably don't have access permissions. */
142 continue;
145 possible += "/";
147 if(S_ISDIR(s.st_mode)) {
148 parse(vault, possible + AesalonModuleConfigFileName);
149 std::string path = dent->d_name;
150 path += ":root";
151 vault->clear(path);
152 vault->set(path, possible);
156 closedir(dir);
159 void Parser::openFile(const std::string &configFile) {
160 m_stream = new std::ifstream(configFile.c_str());
163 std::string Parser::nextToken(TokenType &type) {
164 std::ifstream &stream = *m_stream;
166 skipWhitespace();
168 if(stream.eof()) {
169 type = END_OF_FILE;
170 return "";
173 if(stream.peek() == '#') {
174 std::string line;
175 std::getline(stream, line);
176 return nextToken(type);
178 else if(stream.peek() == '"') {
179 stream.get(); // skip "
181 std::string word;
182 while(stream.peek() != '"') {
183 word += stream.get();
186 stream.get(); // skip "
188 type = QUOTED_WORD;
189 return word;
191 else if(std::isalnum(stream.peek())) {
192 std::string word;
193 while(std::isalnum(stream.peek())) {
194 word += stream.get();
197 type = WORD;
198 return word;
200 else if(stream.peek() == '+') {
201 stream.get(); // skip '+'
202 if(stream.peek() == '=') {
203 stream.get(); // skip '='
204 type = SYMBOL;
205 return "+=";
208 std::string rest;
209 stream >> rest;
211 throw Common::ParsingException(Common::StreamAsString()
212 << "Unrecognized token: \"+" << rest << "\"");
214 else {
215 std::string token;
216 token += stream.get();
218 type = SYMBOL;
219 return token;
223 std::string Parser::expectNextToken(TokenType expected) {
224 TokenType actual;
225 std::string token = nextToken(actual);
227 if(actual != expected) {
228 throw Common::ParsingException(Common::StreamAsString()
229 << "Expected " << nameOf(expected) << " token, found " << nameOf(actual)
230 << " token: \"" << token << "\"");
233 return token;
236 void Parser::expectNextSymbol(const std::string &symbol) {
237 std::string s = expectNextToken(SYMBOL);
238 if(symbol != s) {
239 throw Common::ParsingException(Common::StreamAsString()
240 << "Expected token \"" << symbol << "\", got \"" << s << "\"");
244 void Parser::skipWhitespace() {
245 std::ifstream &stream = *m_stream;
247 while(!stream.fail() && std::isspace(stream.peek())) {
248 stream.get();
252 void Parser::closeFile() {
253 delete m_stream;
254 m_stream = NULL;
257 const char *Parser::nameOf(TokenType type) const {
258 static const char *name[] = {
259 "WORD",
260 "QUOTED_WORD",
261 "SYMBOL",
262 "END_OF_FILE"
265 return name[type];
268 } // namespace Config
269 } // namespace Monitor