From 125d5ad15427d23295382ba04c5749576f6dd273 Mon Sep 17 00:00:00 2001 From: "Arens, Thomas (BSH)" Date: Thu, 9 Aug 2018 14:30:18 +0200 Subject: [PATCH] - added the possibility to load multiple INI files from the folder /etc/commonapi.d or the folder provided by the environment variable COMMONAPI_CONFIG (if it is a folder). Priority is as follows: 1. folder definded by COMMONAPI_CONFIG 2. file in the current folder 3. file definded by COMMONAPI_CONFIG 4. folder /etc/commonapi.d 5. file /etc/commonapi.ini - added the capability to use ; for comments --- CMakeLists.txt | 2 +- src/CommonAPI/IniFileReader.cpp | 84 ++++++++++++++++----------------- src/CommonAPI/Runtime.cpp | 82 +++++++++++++++++++++++--------- 3 files changed, 104 insertions(+), 64 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 78973456..fecae6d9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -127,7 +127,7 @@ link_directories( file(GLOB CAPI_SRCS "src/CommonAPI/*.cpp") list(SORT CAPI_SRCS) add_library(CommonAPI SHARED ${CAPI_SRCS}) -target_link_libraries(CommonAPI PRIVATE ${DL_LIBRARY} ${DLT_LIBRARIES}) +target_link_libraries(CommonAPI PRIVATE ${DL_LIBRARY} ${DLT_LIBRARIES} stdc++fs) set_target_properties(CommonAPI PROPERTIES VERSION ${LIBCOMMONAPI_MAJOR_VERSION}.${LIBCOMMONAPI_MINOR_VERSION}.${LIBCOMMONAPI_PATCH_VERSION} SOVERSION ${LIBCOMMONAPI_MAJOR_VERSION}.${LIBCOMMONAPI_MINOR_VERSION}.${LIBCOMMONAPI_PATCH_VERSION} LINKER_LANGUAGE C) set_target_properties (CommonAPI PROPERTIES INTERFACE_LINK_LIBRARY "") diff --git a/src/CommonAPI/IniFileReader.cpp b/src/CommonAPI/IniFileReader.cpp index 94057e0e..66ce5e9e 100644 --- a/src/CommonAPI/IniFileReader.cpp +++ b/src/CommonAPI/IniFileReader.cpp @@ -45,50 +45,50 @@ IniFileReader::load(const std::string &_path) { trim(line); - std::size_t start = line.find('['); - if (start == 0) { - std::size_t end = line.find(']'); - if (end != line.npos) { - currentSectionName = line.substr(++start, --end); - if (sections_.end() == sections_.find(currentSectionName)) { - currentSection = std::make_shared
(); - if (currentSection) { - sections_[currentSectionName] = currentSection; + if (!line.empty()) { + if (line.front() != ';') { + std::size_t start = line.find('['); + if (start == 0) { + std::size_t end = line.find(']'); + if (end != line.npos) { + currentSectionName = line.substr(++start, --end); + auto currentSectionIt = sections_.find(currentSectionName); + if (sections_.end() == currentSectionIt) { + currentSection = std::make_shared
(); + if (currentSection) { + sections_[currentSectionName] = currentSection; + } + } else { + currentSection = currentSectionIt->second; + } + } else { + COMMONAPI_ERROR("Missing \']\' in section definition (line ", + lineCounter, ")"); + } + } else if (currentSection) { + std::size_t pos = line.find('='); + if (pos != line.npos) { + std::string key = line.substr(0, pos); + trim(key); + if (currentSection->mappings_.end() + != currentSection->mappings_.find(key)) { + COMMONAPI_ERROR("Double definition for key \'", + key, + "'\' in section \'", + currentSectionName, + "\' (line ", + lineCounter, + ")"); + } else { + std::string value = line.substr(pos+1); + trim(value); + currentSection->mappings_[key] = value; + } + } else if (line.size() > 0) { + COMMONAPI_ERROR("Missing \'=\' in key=value definition (line ", + lineCounter, ")"); } - } else { - COMMONAPI_ERROR("Double definition of section \'", - currentSectionName, - "\' ignoring definition (line ", - lineCounter, - ")"); - currentSection = nullptr; - } - } else { - COMMONAPI_ERROR("Missing \']\' in section definition (line ", - lineCounter, ")"); - } - } else if (currentSection) { - std::size_t pos = line.find('='); - if (pos != line.npos) { - std::string key = line.substr(0, pos); - trim(key); - if (currentSection->mappings_.end() - != currentSection->mappings_.find(key)) { - COMMONAPI_ERROR("Double definition for key \'", - key, - "'\' in section \'", - currentSectionName, - "\' (line ", - lineCounter, - ")"); - } else { - std::string value = line.substr(pos+1); - trim(value); - currentSection->mappings_[key] = value; } - } else if (line.size() > 0) { - COMMONAPI_ERROR("Missing \'=\' in key=value definition (line ", - lineCounter, ")"); } } } diff --git a/src/CommonAPI/Runtime.cpp b/src/CommonAPI/Runtime.cpp index 9bae2e22..a7c7f2b1 100644 --- a/src/CommonAPI/Runtime.cpp +++ b/src/CommonAPI/Runtime.cpp @@ -19,12 +19,21 @@ #include #include +#if defined __cpp_lib_filesystem +#include +namespace fs_ns = std::filesystem; +#else +#include +namespace fs_ns = std::experimental::filesystem; +#endif + namespace CommonAPI { const char *COMMONAPI_DEFAULT_BINDING = "dbus"; const char *COMMONAPI_DEFAULT_FOLDER = "/usr/local/lib/commonapi"; const char *COMMONAPI_DEFAULT_CONFIG_FILE = "commonapi.ini"; const char *COMMONAPI_DEFAULT_CONFIG_FOLDER = "/etc"; +const char *COMMONAPI_DEFAULT_MULTIPLE_CONFIGS_FOLDER = "/etc/commonapi.d"; std::map properties__; static std::shared_ptr * theRuntimePtr__; @@ -126,14 +135,29 @@ void Runtime::init() { std::lock_guard itsLock(mutex_); #endif if (!isConfigured_) { - // Determine default configuration file + // Determine default configuration file/folder + defaultConfig_ = COMMONAPI_DEFAULT_MULTIPLE_CONFIGS_FOLDER; + const char *config = getenv("COMMONAPI_CONFIG"); if (config) { defaultConfig_ = config; - } else { - defaultConfig_ = COMMONAPI_DEFAULT_CONFIG_FOLDER; - defaultConfig_ += "/"; - defaultConfig_ += COMMONAPI_DEFAULT_CONFIG_FILE; + } + + // Check if there is a configuration folder: + if (fs_ns::exists(defaultConfig_) + && fs_ns::is_directory(defaultConfig_) + && !fs_ns::is_empty(defaultConfig_)) + { + + } + else + { + if (!config) + { + defaultConfig_ = COMMONAPI_DEFAULT_CONFIG_FOLDER; + defaultConfig_ += "/"; + defaultConfig_ += COMMONAPI_DEFAULT_CONFIG_FILE; + } } // TODO: evaluate return parameter and decide what to do @@ -172,31 +196,47 @@ Runtime::initFactories() { bool Runtime::readConfiguration() { + IniFileReader reader; + // Reading a complete folder: + if (fs_ns::is_directory(defaultConfig_)) + { + usedConfig_ = defaultConfig_; + + for (auto &dirEntry : fs_ns::directory_iterator(usedConfig_)) + { + if (!fs_ns::is_directory(dirEntry.path().string())) + { + reader.load(dirEntry.path().string()); + } + } + } + else + { #define MAX_PATH_LEN 255 - std::string config; - bool tryLoadConfig(true); - char currentDirectory[MAX_PATH_LEN]; + std::string config; + bool tryLoadConfig(true); + char currentDirectory[MAX_PATH_LEN]; #ifdef _WIN32 - if (GetCurrentDirectory(MAX_PATH_LEN, currentDirectory)) { + if (GetCurrentDirectory(MAX_PATH_LEN, currentDirectory)) { #else - if (getcwd(currentDirectory, MAX_PATH_LEN)) { + if (getcwd(currentDirectory, MAX_PATH_LEN)) { #endif - usedConfig_ = currentDirectory; - usedConfig_ += "/"; - usedConfig_ += COMMONAPI_DEFAULT_CONFIG_FILE; + usedConfig_ = currentDirectory; + usedConfig_ += "/"; + usedConfig_ += COMMONAPI_DEFAULT_CONFIG_FILE; - struct stat s; - if (stat(usedConfig_.c_str(), &s) != 0) { - usedConfig_ = defaultConfig_; + struct stat s; if (stat(usedConfig_.c_str(), &s) != 0) { - tryLoadConfig = false; + usedConfig_ = defaultConfig_; + if (stat(usedConfig_.c_str(), &s) != 0) { + tryLoadConfig = false; + } } } - } - IniFileReader reader; - if (tryLoadConfig && !reader.load(usedConfig_)) - return false; + if (tryLoadConfig && !reader.load(usedConfig_)) + return false; + } std::string itsConsole("true"); std::string itsFile;