You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
100 lines
3.9 KiB
100 lines
3.9 KiB
// ©2008-2017 despair <despair@netrunner.cc> |
|
#include "CFGFileParser.h" |
|
#include <climits> |
|
#include "slre.h" |
|
|
|
CFGFileParser::CFGFileParser(const char* filename){ |
|
// Open the config file, get its size, |
|
// allocate the buffer, read it into |
|
// the buffer, close the file |
|
cfg_file = fopen(filename, "rb"); // On NT, opening in text mode translates \n into \r\n |
|
stat(filename, cfg_fileinfo); |
|
buffer = static_cast<char*>(tlsf_malloc(cfg_fileinfo->st_size & INT_MAX, sizeof(char) & INT_MAX)); |
|
cfg = new BrowserConfiguration(); |
|
bytesRead = fread(buffer, sizeof(char) & INT_MAX, cfg_fileinfo->st_size & INT_MAX, cfg_file); |
|
if (!bytesRead) { |
|
std::cout << "no config" << std::endl; |
|
} |
|
fclose(cfg_file); |
|
} |
|
|
|
CFGFileParser::~CFGFileParser(){ |
|
// clean up! |
|
// This buffer has been written to and co-opted by |
|
// libc itself, but it stands that we initially allocated |
|
// it. So we'll free it ourselves. |
|
tlsf_free(buffer); |
|
// We've already copied the collected config directives |
|
// into a global class, we can safely delete the scratch |
|
// object, and its file info block. |
|
tlsf_free(cfg_fileinfo); |
|
delete cfg; |
|
} |
|
|
|
bool CFGFileParser::ParseText() { |
|
// Initial buffer for pass 1. tmp holds the config file (fmr. buffer) |
|
// token holds the actual token. pass1_length to keep track of memory, |
|
// reallocate as needed. |
|
char *tmp, *token; |
|
size_t pass1_length = 0; |
|
struct slre regex; // final validation before adding to second-pass buffer |
|
// Second pass. All comments and .tags stripped out. Starts off at 512 bytes, increases if necessary. |
|
char* directives = static_cast<char*>(tlsf_malloc(512, sizeof(char))); |
|
char* tmp2; |
|
token = strtok_r(buffer, "\n", &tmp); |
|
while (tmp != nullptr) { |
|
if (token[0] == '#' || token[0] == '.' || token[0] == '\n'){ // Comment, Perl directive, or single <LF> found, skip over |
|
token = strtok_r(nullptr, "\n", &tmp); |
|
} |
|
else if (!isalpha(token[0])){ // The leading character is NOT a #, ., <LF>, or a letter. NB: Leading numbers are also invalid. |
|
printf("ERROR: Config file is invalid\n"); |
|
printf("%s\n",token); |
|
return false; |
|
} |
|
else { |
|
if (!slre_compile(®ex, "([A-Z0-9_]*)(:)(\\[.*\\])")){ |
|
printf("Internal error.\n"); |
|
return false; |
|
} |
|
if (!slre_match(®ex, token, strlen(token), nullptr)){ |
|
printf("Invalid directive: %s\n", token); // regex matches DIREC[_]T[I1]VE:[token] but NOT directive:[token] - the directive MUST be all caps |
|
return false; |
|
} |
|
// Config directive found, add to second-pass buffer |
|
// once we reach the 0.5KB mark, realloc exactly enough to keep going |
|
if (pass1_length >= 512){ |
|
tlsf_realloc(directives, pass1_length+strlen(token)+2); |
|
} |
|
strcat(directives, token); |
|
strcat(directives, "\t"); |
|
pass1_length = strlen(directives); |
|
token = strtok_r(nullptr, "\n", &tmp); // continue |
|
} |
|
} |
|
// First pass complete, second pass: break up into single directives and <key, value> pairs |
|
token = strtok_r(directives, "\t", &tmp); |
|
ntr::fast_string key, value; |
|
while (tmp != nullptr){ |
|
key=strtok_r(token, ":", &tmp2); |
|
value=strtok_r(nullptr, "[]", &tmp2); |
|
// strip ending bracket |
|
cfg->Settings.insert({key,value}); |
|
token = strtok_r(nullptr, "\t", &tmp); |
|
} |
|
#ifdef DEBUG |
|
std::cout << "Settings stringmap contains, in no particular order:\n"; |
|
for ( auto it = cfg->Settings.begin(); it != cfg->Settings.end(); ++it ){ |
|
std::cout << it->first << ":" << it->second << std::endl; |
|
} |
|
std::cout << std::endl; |
|
#endif |
|
// clean up, we're done parsing |
|
tlsf_free(directives); |
|
return true; |
|
} |
|
|
|
// Writes the fully parsed configuration to a BrowserConfiguration |
|
// object supplied by the user. |
|
void CFGFileParser::WriteConfig(BrowserConfiguration &config){ |
|
config.Settings = cfg->Settings; |
|
} |