add config file reader-parser
This commit is contained in:
parent
b9032f7034
commit
a9974aab04
@ -87,7 +87,8 @@ add_library(${CNTR_PROTO_LIB} STATIC ${CNTR_PROTO_LIB_SRC})
|
||||
|
||||
set(MOUNT_SERVER_APP_SRC mount.h mount_server.cpp comm_server.h comm_server_endpoint.h)
|
||||
set(MOUNT_SERVER_APP mount_server)
|
||||
add_executable(${MOUNT_SERVER_APP} ${MOUNT_SERVER_APP_SRC})
|
||||
add_executable(${MOUNT_SERVER_APP} ${MOUNT_SERVER_APP_SRC}
|
||||
comm_server_configfile.h)
|
||||
target_link_libraries(${MOUNT_SERVER_APP} ${CNTR_PROTO_LIB} spdlog::spdlog_header_only)
|
||||
|
||||
if (WITH_TESTS)
|
||||
@ -96,4 +97,7 @@ if (WITH_TESTS)
|
||||
target_link_libraries(${CNTR_PROTO_TEST_APP} ${CNTR_PROTO_LIB} spdlog::spdlog_header_only)
|
||||
# target_link_libraries(${CNTR_PROTO_TEST_APP} ${CNTR_PROTO_LIB})
|
||||
# target_include_directories(${CNTR_PROTO_TEST_APP} PUBLIC ${SPDLOG_INCLUDE_DIRS})
|
||||
|
||||
set(CFGFILE_TEST_APP configfile_test)
|
||||
add_executable(${CFGFILE_TEST_APP} tests/configfile_test.cpp)
|
||||
endif()
|
||||
|
||||
145
cxx/comm_server_configfile.h
Normal file
145
cxx/comm_server_configfile.h
Normal file
@ -0,0 +1,145 @@
|
||||
#pragma once
|
||||
|
||||
/* MOUNT CONTRO: COMPONENTS */
|
||||
|
||||
|
||||
#include <concepts>
|
||||
#include <cstddef>
|
||||
#include <fstream>
|
||||
#include <unordered_map>
|
||||
#include <variant>
|
||||
|
||||
#include "comm_server_endpoint.h"
|
||||
#include "utils.h"
|
||||
|
||||
namespace mcc
|
||||
{
|
||||
|
||||
|
||||
/*
|
||||
* A VERY SIMPLE CONFIG-FILE READER-PARSER
|
||||
*
|
||||
* format:
|
||||
* key = value1, value2, ...
|
||||
*
|
||||
* a line beginning from '#' symbol is a comment and will be skipped
|
||||
* a line containing from only ' ' is skipped
|
||||
*/
|
||||
|
||||
class MccConfigfile
|
||||
{
|
||||
public:
|
||||
static constexpr char COMMENT_SYMBOL = '#';
|
||||
static constexpr char KEY_VALUE_DELIM = '=';
|
||||
static constexpr char VALUE_VALUE_DELIM = ',';
|
||||
|
||||
|
||||
typedef std::unordered_map<std::string, std::variant<std::monostate, std::string, std::vector<std::string>>>
|
||||
config_t;
|
||||
|
||||
template <typename T = std::nullptr_t>
|
||||
MccConfigfile(T&& filename = nullptr)
|
||||
requires(std::same_as<std::decay_t<T>, std::nullptr_t> || traits::mcc_input_char_range<T>)
|
||||
{
|
||||
if constexpr (traits::mcc_input_char_range<T>) {
|
||||
if (load(std::forward<T>(filename))) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::error_code load(traits::mcc_input_char_range auto&& filename)
|
||||
{
|
||||
std::filesystem::path pt(filename.begin(), filename.end());
|
||||
|
||||
// first, check file existence
|
||||
|
||||
std::error_code ec;
|
||||
auto pt_cn = std::filesystem::canonical(pt, ec);
|
||||
if (ec) {
|
||||
return ec;
|
||||
}
|
||||
|
||||
std::ifstream fin(pt_cn);
|
||||
|
||||
if (!fin.is_open()) {
|
||||
return std::make_error_code(std::errc::no_such_file_or_directory);
|
||||
// return std::make_error_code(std::errc::permission_denied);
|
||||
}
|
||||
|
||||
_currentFilename = pt_cn.string();
|
||||
_currentConfig.clear();
|
||||
|
||||
// read line-by-line
|
||||
for (std::string line; std::getline(fin, line);) {
|
||||
if (line.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto sv = utils::trimSpaces(line, utils::TrimType::TRIM_LEFT);
|
||||
|
||||
if (sv.size()) {
|
||||
if (sv[0] == COMMENT_SYMBOL) { // comment string
|
||||
continue;
|
||||
}
|
||||
|
||||
auto it = std::ranges::find(sv, KEY_VALUE_DELIM);
|
||||
if (it == sv.begin()) { // empty key! skip!
|
||||
continue;
|
||||
}
|
||||
auto key = utils::trimSpaces(std::string_view{sv.begin(), it}, utils::TrimType::TRIM_RIGHT);
|
||||
std::string skey = {key.begin(), key.end()};
|
||||
|
||||
if (it == sv.end()) { // only key
|
||||
_currentConfig[skey] = {};
|
||||
} else { // key and value
|
||||
auto vals = utils::trimSpaces(std::string_view{it + 1, sv.end()});
|
||||
auto it_dlm = std::ranges::find(vals, VALUE_VALUE_DELIM);
|
||||
|
||||
if (it_dlm == vals.end()) { // scalar value
|
||||
_currentConfig[skey] = std::string{vals.begin(), vals.end()};
|
||||
} else { // vector of values
|
||||
std::vector<std::string> elems;
|
||||
while (it_dlm != vals.end()) {
|
||||
auto el = utils::trimSpaces(std::string_view{vals.begin(), it_dlm});
|
||||
elems.emplace_back(el.begin(), el.end());
|
||||
|
||||
vals = {it_dlm + 1, vals.end()};
|
||||
it_dlm = std::ranges::find(vals, VALUE_VALUE_DELIM);
|
||||
}
|
||||
|
||||
_currentConfig[skey] = elems;
|
||||
}
|
||||
}
|
||||
} else { // the string contains from only spaces
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
fin.close();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string currentFilename() const
|
||||
{
|
||||
return _currentFilename;
|
||||
}
|
||||
|
||||
const config_t& config() const
|
||||
{
|
||||
return _currentConfig;
|
||||
}
|
||||
|
||||
// config_t& config()
|
||||
// {
|
||||
// return _currentConfig;
|
||||
// }
|
||||
|
||||
private:
|
||||
std::string _currentFilename;
|
||||
|
||||
config_t _currentConfig;
|
||||
};
|
||||
|
||||
} // namespace mcc
|
||||
39
cxx/tests/configfile_test.cpp
Normal file
39
cxx/tests/configfile_test.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
#include <iostream>
|
||||
|
||||
#include "../comm_server_configfile.h"
|
||||
|
||||
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if (argc < 2) {
|
||||
std::cout << "Usage: " << argv[0] << " cfg_filename\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
mcc::MccConfigfile cfg;
|
||||
|
||||
auto ec = cfg.load(std::string_view{argv[1]});
|
||||
if (ec) {
|
||||
std::cout << "ERR: " << ec.message() << "\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (auto& [key, v] : cfg.config()) {
|
||||
std::cout << "<" << key << "> = ";
|
||||
if (v.index()) {
|
||||
if (v.index() > 1) {
|
||||
for (auto& el : std::get<2>(v)) {
|
||||
std::cout << "<" << el << "> ";
|
||||
}
|
||||
std::cout << "\n";
|
||||
} else {
|
||||
std::cout << "<" << std::get<1>(v) << ">\n";
|
||||
}
|
||||
} else {
|
||||
std::cout << "<no value>\n";
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user