Skip to content

Commit e65c9ff

Browse files
committed
Improve config parsing
1 parent 4b9a5ea commit e65c9ff

File tree

2 files changed

+74
-84
lines changed

2 files changed

+74
-84
lines changed

include/config/Config.hpp

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,13 @@ std::string isCgi(std::string const &value, size_t index);
4444
* minOccurence, maxOccurence, minArgs, maxArgs, validationFunction}
4545
*/
4646
const token_t tokens_g[] = {
47+
// Wildcard context
48+
{"include", "*", false, 0, static_cast<size_t>(-1), 1, 1, NULL},
49+
50+
// Root context
4751
{"http", "_", true, 1, 1, 0, 0, NULL},
52+
53+
// Http context
4854
{"log_to_terminal", "http", false, 0, 1, 1, 1, isBoolean},
4955
{"log_level", "http", false, 0, 1, 1, 1, isLogLevel},
5056
{"access_log", "http", false, 0, 1, 1, 1, NULL},
@@ -109,20 +115,6 @@ class Config {
109115
bool validate = true);
110116

111117
private:
112-
// Processes a context
113-
// @param context The context to add data to
114-
// @param data The data to process
115-
// @param token The token name of the context to process
116-
// @param line The line in the config file where the context starts
117-
// @exception std::runtime_error If the context is invalid
118-
void processContext(Context &context, std::string &data, std::string token,
119-
size_t &line);
120-
121-
// Processes an include directive
122-
// @param context The context to add the included context to
123-
// @param path The path to the included config file
124-
void processInclude(Context &context, std::string path);
125-
126118
// Checks if the token is a valid context in the given context
127119
// @param context The context to check in
128120
// @param token The token to check
@@ -159,7 +151,7 @@ class Config {
159151
// @param recursive If true, the function will validate all child contexts
160152
// @return An empty string if the context is valid, an error message otherwise
161153
// @exception No custom exceptions
162-
std::string validate(Context &context, bool recursive);
154+
std::string validateContext(Context &context, bool recursive);
163155

164156
// Returns the number of lines until the given position
165157
// @param data The string to search in

src/config/Config.cpp

Lines changed: 67 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,10 @@ void Config::removeComments() {
153153

154154
Context &Config::parseContext(Context &context, std::string data, size_t line,
155155
bool validateResult) {
156-
accessLog_g.write(_path + ":" + toString(line) + " Context: '" + context.getName() + "' -> Parsing", DEBUG);
156+
accessLog_g.write(_path + ":" + toString(line) + " Context: '" +
157+
context.getName() + "' -> Parsing",
158+
DEBUG);
159+
157160
size_t startLine = line;
158161
while (true) {
159162
// Trim leading whitespace
@@ -169,19 +172,38 @@ Context &Config::parseContext(Context &context, std::string data, size_t line,
169172

170173
// Process token
171174
std::string token = trim(cut(data, 0, nextEnd));
172-
if (token == "include" || isValidDirective(context, token)) {
175+
if (isValidDirective(context, token)) {
176+
accessLog_g.write(_path + ":" + toString(line) + " Directive: '" + token +
177+
"' -> Parsing",
178+
DEBUG);
179+
173180
// Find end of token value
174181
nextEnd = data.find_first_of(";\n");
175182
if (nextEnd == std::string::npos || data[nextEnd] != ';')
176183
throwExeption(line, "Expected token ';' not found");
177184

178185
// Process token value
179-
if (token == "include") try {
180-
processInclude(context, trim(cut(data, 0, nextEnd)));
181-
} catch (const std::exception &e) {
182-
throwExeption(line, e.what());
186+
if (token == "include") {
187+
const std::string path = trim(cut(data, 0, nextEnd));
188+
189+
// Prepare wildcard path
190+
std::string wildcardPath =
191+
startsWith(path, "/") ? path : _includePath + path;
192+
193+
// Get file list
194+
std::set<std::string> files = processWildcardPath(wildcardPath);
195+
std::set<std::string>::iterator itr = files.begin();
196+
for (; itr != files.end(); itr++) {
197+
accessLog_g.write(_path + " Context: '" + context.getName() +
198+
"' -> Include '" + *itr + "'",
199+
DEBUG);
200+
201+
// Recursively parse included config files
202+
Config config(*itr, _includePath);
203+
config.removeComments();
204+
config.parseContext(context, config.getConfig(), 1, false);
183205
}
184-
else {
206+
} else {
185207
checkError(line, validToAdd(context, token));
186208
std::vector<std::string> args = split<std::vector<std::string> >(
187209
cut(data, 0, nextEnd), " \f\n\r\t\v");
@@ -190,68 +212,41 @@ Context &Config::parseContext(Context &context, std::string data, size_t line,
190212
}
191213
data.erase(0, 1);
192214
} else if (isValidContext(context, token)) {
193-
processContext(context, data, token, line);
215+
Context child(token, &context);
216+
// Find context start bracket
217+
size_t argsEnd = data.find_first_of("{\n");
218+
if (argsEnd == std::string::npos || data[argsEnd] != '{')
219+
throwExeption(line, "Expected token '{' not found");
220+
221+
// Parse, validate and add
222+
std::vector<std::string> args = split<std::vector<std::string> >(
223+
trim(cut(data, 0, argsEnd)), " \f\n\r\t\v");
224+
checkError(line, validArguments(context, token, args));
225+
child.setArgs(args);
226+
227+
line += linesUntilPos(data, data.find_first_not_of(" \f\t\v"));
228+
trimStart(data, " \f\t\v");
229+
230+
// Find context end bracket
231+
size_t nextEnd = findContextEnd(data);
232+
if (nextEnd == std::string::npos)
233+
throwExeption(line, "No context end found for '" + token + "'");
234+
std::string contextData = cut(data, 1, nextEnd);
235+
236+
// Parse context
237+
parseContext(child, contextData, line);
238+
checkError(line, validToAdd(context, token));
239+
context.addContext(child);
240+
line += linesUntilPos(contextData, contextData.length() + 2);
241+
data.erase(0, 2);
194242
} else
195243
throwExeption(line, "Invalid token '" + token + "'");
196244
}
197245
// Validate parsed context
198-
if (validateResult) checkError(startLine, validate(context, false));
246+
if (validateResult) checkError(startLine, validateContext(context, false));
199247
return context;
200248
}
201249

202-
void Config::processContext(Context &context, std::string &data,
203-
std::string token, size_t &line) {
204-
Context child(token, &context);
205-
// Find context start bracket
206-
size_t argsEnd = data.find_first_of("{\n");
207-
if (argsEnd == std::string::npos || data[argsEnd] != '{')
208-
throwExeption(line, "Expected token '{' not found");
209-
210-
// Parse, validate and add
211-
std::vector<std::string> args = split<std::vector<std::string> >(
212-
trim(cut(data, 0, argsEnd)), " \f\n\r\t\v");
213-
checkError(line, validArguments(context, token, args));
214-
child.setArgs(args);
215-
216-
line += linesUntilPos(data, data.find_first_not_of(" \f\t\v"));
217-
trimStart(data, " \f\t\v");
218-
219-
// Find context end bracket
220-
size_t nextEnd = findContextEnd(data);
221-
if (nextEnd == std::string::npos)
222-
throwExeption(line, "No context end found for '" + token + "'");
223-
std::string contextData = cut(data, 1, nextEnd);
224-
225-
// Parse context
226-
parseContext(child, contextData, line);
227-
checkError(line, validToAdd(context, token));
228-
context.addContext(child);
229-
line += linesUntilPos(contextData, contextData.length() + 2);
230-
data.erase(0, 2);
231-
}
232-
233-
void Config::processInclude(Context &context, std::string path) {
234-
// Prepare wildcard path
235-
std::string includePath;
236-
if (startsWith(path, "/"))
237-
includePath = path;
238-
else
239-
includePath = _includePath + path;
240-
241-
// Get file list
242-
std::set<std::string> files = processWildcardPath(includePath);
243-
std::set<std::string>::iterator itr = files.begin();
244-
for (; itr != files.end(); itr++) {
245-
accessLog_g.write( _path +
246-
" Context: '" + context.getName() + "' -> Include '" + *itr + "'",
247-
DEBUG);
248-
// Recursively parse included config files
249-
Config config(*itr, _includePath);
250-
config.removeComments();
251-
config.parseContext(context, config.getConfig(), 1, false);
252-
}
253-
}
254-
255250
bool Config::isValidContext(Context &context, std::string token) const {
256251
for (size_t i = 0; i < sizeof(tokens_g) / sizeof(token_t); i++)
257252
if (tokens_g[i].name == token && tokens_g[i].parent == context.getName() &&
@@ -262,8 +257,10 @@ bool Config::isValidContext(Context &context, std::string token) const {
262257

263258
bool Config::isValidDirective(Context &context, std::string token) const {
264259
for (size_t i = 0; i < sizeof(tokens_g) / sizeof(token_t); i++)
265-
if (tokens_g[i].name == token && tokens_g[i].parent == context.getName() &&
266-
!tokens_g[i].isContext)
260+
if (tokens_g[i].name == token &&
261+
(tokens_g[i].parent == "*" ||
262+
tokens_g[i].parent == context.getName()) &&
263+
tokens_g[i].isContext == false)
267264
return true;
268265
return false;
269266
}
@@ -273,7 +270,7 @@ std::string Config::validToAdd(Context &context, std::string token) {
273270
if (tokens_g[i].name == token && tokens_g[i].parent == context.getName())
274271
return context.getTokenOccurence(token) < tokens_g[i].maxOccurence
275272
? ""
276-
: "Token '" + token + "'has too many occurences";
273+
: "Token '" + token + "' has too many occurences";
277274
return "Token '" + token + "' not found";
278275
}
279276

@@ -298,9 +295,9 @@ std::string Config::validArguments(Context &context, std::string token,
298295
return "Token '" + token + "' not found";
299296
}
300297

301-
std::string Config::validate(Context &context, bool recursive) {
302-
accessLog_g.write(_path + " Context: '" + context.getName() + "' -> Validating",
303-
DEBUG);
298+
std::string Config::validateContext(Context &context, bool recursive) {
299+
accessLog_g.write(
300+
_path + " Context: '" + context.getName() + "' -> Validating", DEBUG);
304301
for (size_t i = 0; i < sizeof(tokens_g) / sizeof(token_t); i++) {
305302
if (tokens_g[i].parent == context.getName() &&
306303
context.getTokenOccurence(tokens_g[i].name) <
@@ -314,7 +311,8 @@ std::string Config::validate(Context &context, bool recursive) {
314311
std::map<std::string, std::vector<Context> >::iterator it;
315312
for (it = context.getContexts().begin(); it != context.getContexts().end();
316313
it++)
317-
for (size_t i = 0; i < it->second.size(); i++) validate(context, true);
314+
for (size_t i = 0; i < it->second.size(); i++)
315+
validateContext(context, true);
318316
}
319317
return "";
320318
}

0 commit comments

Comments
 (0)