From ad8c3a178ddbf561e08d800372979eaf54986a9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Nusser?= Date: Tue, 7 Apr 2020 22:19:10 +0200 Subject: Refactoring configfile. The most important changes are: * general cleaning up * changing to platform independent newline in reading and writing * changing the Windows config directory to DrumGizmo (instead of .drumgizmo) And also, regarding the old code: C called, they wanted all their file operations back. ;-p --- src/configfile.cc | 178 +++++++++++++++++++++-------------------------------- src/configfile.h | 8 +-- test/configtest.cc | 46 +++++++------- 3 files changed, 97 insertions(+), 135 deletions(-) diff --git a/src/configfile.cc b/src/configfile.cc index 54fb4d1..a1494a8 100644 --- a/src/configfile.cc +++ b/src/configfile.cc @@ -26,13 +26,7 @@ */ #include "configfile.h" -#include -#include -#include -#include - #include -#include #include "platform.h" @@ -47,28 +41,34 @@ #include #if DG_PLATFORM == DG_PLATFORM_WINDOWS -#define SEP "\\" +static const std::string SEP = "\\"; +#else +static const std::string SEP = "/"; +#endif + +#if DG_PLATFORM == DG_PLATFORM_WINDOWS +static const std::string CONFIGDIRNAME = "DrumGizmo"; #else -#define SEP "/" +static const std::string CONFIGDIRNAME = ".drumgizmo"; #endif -#define CONFIGDIRNAME ".drumgizmo" +namespace +{ /** * Return the path containing the config files. */ -static std::string getConfigPath() +std::string getConfigPath() { -#if DG_PLATFORM == DG_PLATFORM_WINDOWS std::string configpath; +#if DG_PLATFORM == DG_PLATFORM_WINDOWS TCHAR szPath[256]; - if(SUCCEEDED(SHGetFolderPath( - NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, szPath))) + if(SUCCEEDED(SHGetFolderPath(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, szPath))) { configpath = szPath; } #else - std::string configpath = getenv("HOME"); + configpath = getenv("HOME"); #endif configpath += SEP; configpath += CONFIGDIRNAME; @@ -79,9 +79,9 @@ static std::string getConfigPath() /** * Calling this makes sure that the config path exists */ -static bool createConfigPath() +bool createConfigPath() { - std::string configpath = getConfigPath(); + std::string const configpath = getConfigPath(); struct stat st; if(stat(configpath.c_str(), &st) != 0) @@ -90,11 +90,10 @@ static bool createConfigPath() configpath.c_str()); #if DG_PLATFORM == DG_PLATFORM_WINDOWS if(mkdir(configpath.c_str()) < 0) - { #else if(mkdir(configpath.c_str(), 0755) < 0) - { #endif + { DEBUG(configfile, "Could not create config directory\n"); } @@ -104,24 +103,26 @@ static bool createConfigPath() return true; } +} // end anonymous namespace + ConfigFile::ConfigFile(std::string const& filename) : filename(filename) - , fp(nullptr) { } ConfigFile::~ConfigFile() { - if (fp != nullptr) + if (current_file.is_open()) { DEBUG(configfile, "File has not been closed by the client...\n"); + current_file.close(); } } bool ConfigFile::load() { DEBUG(configfile, "Loading config file...\n"); - if(!open("r")) + if(!open(std::ios_base::in)) { return false; } @@ -129,20 +130,15 @@ bool ConfigFile::load() values.clear(); std::string line; - while(true) + while(std::getline(current_file, line) && line != "") { - line = readLine(); - - if(line == "") - break; - if(!parseLine(line)) { return false; } } - close(); + current_file.close(); return true; } @@ -153,18 +149,16 @@ bool ConfigFile::save() createConfigPath(); - if(!open("w")) + if(!open(std::ios_base::out)) { return false; } - std::map::iterator v = values.begin(); - for(; v != values.end(); ++v) + for(auto const& value: values) { - fprintf(fp, "%s:%s\n", v->first.c_str(), v->second.c_str()); + current_file << value.first << ":" << value.second << std::endl; } - - close(); + current_file.close(); return true; } @@ -185,65 +179,26 @@ void ConfigFile::setValue(const std::string& key, const std::string& value) values[key] = value; } -bool ConfigFile::open(std::string mode) +bool ConfigFile::open(std::ios_base::openmode mode) { - if(fp) + if(current_file.is_open()) { - close(); + current_file.close(); } - std::string configpath = getConfigPath(); - - std::string configfile = configpath; - configfile += SEP; - configfile += filename; + std::string filename = getConfigPath(); + filename += SEP; + filename += filename; - DEBUG(configfile, "Opening config file '%s'\n", configfile.c_str()); - fp = fopen(configfile.c_str(), mode.c_str()); + DEBUG(configfile, "Opening config file '%s'\n", filename.c_str()); + current_file.open(filename, mode); - if(!fp) - { - return false; - } - - return true; -} - -void ConfigFile::close() -{ - fclose(fp); - fp = nullptr; -} - -std::string ConfigFile::readLine() -{ - if(!fp) - { - return ""; - } - - std::string line; - - char buf[1024]; - while(!feof(fp)) - { - char* s = fgets(buf, sizeof(buf), fp); - if(s) - { - line += buf; - if(buf[strlen(buf) - 1] == '\n') - break; - } - } - - return line; + return current_file.is_open(); } bool ConfigFile::parseLine(const std::string& line) { - std::string key; - std::string value; - enum + enum State { before_key, in_key, @@ -253,47 +208,52 @@ bool ConfigFile::parseLine(const std::string& line) in_value_single_quoted, in_value_double_quoted, after_value, - } state = before_key; + }; + + std::string key; + std::string value; + State state = before_key; - for(std::size_t p = 0; p < line.size(); ++p) + for(std::size_t pos = 0; pos < line.size(); ++pos) { + auto c = line[pos]; switch(state) { case before_key: - if(line[p] == '#') + if(c == '#') { // Comment: Ignore line. - p = line.size(); + pos = line.size(); continue; } - if(std::isspace(line[p])) + if(std::isspace(c)) { continue; } - key += line[p]; + key += c; state = in_key; break; case in_key: - if(std::isspace(line[p])) + if(std::isspace(c)) { state = after_key; continue; } - if(line[p] == ':' || line[p] == '=') + if(c == ':' || c == '=') { state = before_value; continue; } - key += line[p]; + key += c; break; case after_key: - if(std::isspace(line[p])) + if(std::isspace(c)) { continue; } - if(line[p] == ':' || line[p] == '=') + if(c == ':' || c == '=') { state = before_value; continue; @@ -305,67 +265,67 @@ bool ConfigFile::parseLine(const std::string& line) return false; case before_value: - if(std::isspace(line[p])) + if(std::isspace(c)) { continue; } - if(line[p] == '\'') + if(c == '\'') { state = in_value_single_quoted; continue; } - if(line[p] == '"') + if(c == '"') { state = in_value_double_quoted; continue; } - value += line[p]; + value += c; state = in_value; break; case in_value: - if(std::isspace(line[p])) + if(std::isspace(c)) { state = after_value; continue; } - if(line[p] == '#') + if(c == '#') { // Comment: Ignore the rest of the line. - p = line.size(); + pos = line.size(); state = after_value; continue; } - value += line[p]; + value += c; break; case in_value_single_quoted: - if(line[p] == '\'') + if(c == '\'') { state = after_value; continue; } - value += line[p]; + value += c; break; case in_value_double_quoted: - if(line[p] == '"') + if(c == '"') { state = after_value; continue; } - value += line[p]; + value += c; break; case after_value: - if(std::isspace(line[p])) + if(std::isspace(c)) { continue; } - if(line[p] == '#') + if(c == '#') { // Comment: Ignore the rest of the line. - p = line.size(); + pos = line.size(); continue; } ERR(configfile, diff --git a/src/configfile.h b/src/configfile.h index 47ae80b..1513897 100644 --- a/src/configfile.h +++ b/src/configfile.h @@ -28,7 +28,7 @@ #include #include -#include +#include class ConfigFile { @@ -45,11 +45,9 @@ public: protected: std::map values; std::string filename; + std::fstream current_file; - virtual bool open(std::string mode); - void close(); + virtual bool open(std::ios_base::openmode mode); std::string readLine(); bool parseLine(const std::string& line); - - FILE* fp; }; diff --git a/test/configtest.cc b/test/configtest.cc index 85a59ca..953c899 100644 --- a/test/configtest.cc +++ b/test/configtest.cc @@ -41,10 +41,10 @@ public: protected: // Overload the built-in open method to use local file instead of homedir. - virtual bool open(std::string mode) + virtual bool open(std::ios_base::openmode mode) { - fp = fopen("test.conf", mode.c_str()); - return fp != NULL; + current_file.open("test.conf", mode); + return current_file.is_open(); } }; @@ -77,16 +77,20 @@ public: unlink("test.conf"); } - void writeFile(const char* str) + void writeFile(const std::string& content, bool newline = true) { - FILE* fp = fopen("test.conf", "w"); - fprintf(fp, "%s", str); - fclose(fp); + std::fstream file("test.conf", std::ios_base::out); + file << content; + if (newline) + { + file << std::endl; + } + file.close(); } void loading_no_newline() { - writeFile("a:b"); + writeFile("a:b", false); TestConfigFile cf; DGUNIT_ASSERT_EQUAL(true, cf.load()); @@ -95,7 +99,7 @@ public: void loading_equal_sign() { - writeFile(" a =\tb\t\n"); + writeFile(" a =\tb\t"); TestConfigFile cf; DGUNIT_ASSERT_EQUAL(true, cf.load()); @@ -104,7 +108,7 @@ public: void loading_newline() { - writeFile("a:b\n"); + writeFile("a:b"); TestConfigFile cf; DGUNIT_ASSERT_EQUAL(true, cf.load()); @@ -113,7 +117,7 @@ public: void loading_padding_space() { - writeFile(" a : b "); + writeFile(" a : b ", false); TestConfigFile cf; DGUNIT_ASSERT_EQUAL(true, cf.load()); @@ -122,7 +126,7 @@ public: void loading_padding_tab() { - writeFile("\ta\t:\tb\t"); + writeFile("\ta\t:\tb\t", false); TestConfigFile cf; DGUNIT_ASSERT_EQUAL(true, cf.load()); @@ -131,7 +135,7 @@ public: void loading_padding_space_newline() { - writeFile(" a : b \n"); + writeFile(" a : b "); TestConfigFile cf; DGUNIT_ASSERT_EQUAL(true, cf.load()); @@ -140,7 +144,7 @@ public: void loading_padding_tab_newline() { - writeFile("\ta\t:\tb\t\n"); + writeFile("\ta\t:\tb\t"); TestConfigFile cf; DGUNIT_ASSERT_EQUAL(true, cf.load()); @@ -149,7 +153,7 @@ public: void loading_comment() { - writeFile("# comment\na:b\n"); + writeFile("# comment\na:b"); TestConfigFile cf; DGUNIT_ASSERT_EQUAL(true, cf.load()); @@ -158,7 +162,7 @@ public: void loading_inline_comment() { - writeFile("a:b #comment\n"); + writeFile("a:b #comment"); TestConfigFile cf; DGUNIT_ASSERT_EQUAL(true, cf.load()); @@ -167,7 +171,7 @@ public: void loading_single_quoted_string() { - writeFile("a: '#\"b\" ' \n"); + writeFile("a: '#\"b\" ' "); TestConfigFile cf; DGUNIT_ASSERT(cf.load()); @@ -176,7 +180,7 @@ public: void loading_double_quoted_string() { - writeFile("a: \"#'b' \" \n"); + writeFile("a: \"#'b' \" "); TestConfigFile cf; DGUNIT_ASSERT_EQUAL(true, cf.load()); @@ -201,7 +205,7 @@ public: void loading_error_string_not_terminated_single() { - writeFile("a:'b\n"); + writeFile("a:'b"); TestConfigFile cf; DGUNIT_ASSERT_EQUAL(false, cf.load()); @@ -209,7 +213,7 @@ public: void loading_error_string_not_terminated_double() { - writeFile("a:\"b\n"); + writeFile("a:\"b"); TestConfigFile cf; DGUNIT_ASSERT_EQUAL(false, cf.load()); @@ -217,7 +221,7 @@ public: void empty_value() { - writeFile("a:\n"); + writeFile("a:"); TestConfigFile cf; DGUNIT_ASSERT_EQUAL(true, cf.load()); -- cgit v1.2.3