...
This commit is contained in:
parent
4fcb5af94b
commit
5e3cc5b31a
@ -34,44 +34,61 @@ public:
|
|||||||
static constexpr char VALUE_VALUE_DELIM = ',';
|
static constexpr char VALUE_VALUE_DELIM = ',';
|
||||||
|
|
||||||
|
|
||||||
|
typedef std::variant<std::monostate, std::string, std::vector<std::string>> config_value_t;
|
||||||
typedef std::unordered_map<std::string, std::variant<std::monostate, std::string, std::vector<std::string>>>
|
typedef std::unordered_map<std::string, std::variant<std::monostate, std::string, std::vector<std::string>>>
|
||||||
config_t;
|
config_t;
|
||||||
|
|
||||||
template <typename T = std::nullptr_t>
|
MccConfigfile() = default;
|
||||||
MccConfigfile(T&& filename = nullptr)
|
|
||||||
requires(std::same_as<std::decay_t<T>, std::nullptr_t> || traits::mcc_input_char_range<T>)
|
MccConfigfile(std::derived_from<std::basic_istream<char>> auto const& stream) : MccConfigfile()
|
||||||
{
|
{
|
||||||
if constexpr (traits::mcc_input_char_range<T>) {
|
load(stream);
|
||||||
if (load(std::forward<T>(filename))) {
|
}
|
||||||
}
|
|
||||||
}
|
MccConfigfile(traits::mcc_input_char_range auto const& filename) : MccConfigfile()
|
||||||
|
{
|
||||||
|
load(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::error_code load(traits::mcc_input_char_range auto&& filename)
|
// factor for default config
|
||||||
|
static MccConfigfile generateDefault()
|
||||||
{
|
{
|
||||||
std::filesystem::path pt(filename.begin(), filename.end());
|
MccConfigfile cfg;
|
||||||
|
|
||||||
// first, check file existence
|
// default listen TCP port
|
||||||
|
cfg["endpoint"] = "tcp://0.0.0.0:3490";
|
||||||
|
|
||||||
std::error_code ec;
|
// default minimal pointable altitude (in degrees)
|
||||||
auto pt_cn = std::filesystem::canonical(pt, ec);
|
cfg["min_alt"] = "10.0";
|
||||||
if (ec) {
|
|
||||||
return ec;
|
return cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
config_value_t& operator[](traits::mcc_input_char_range auto&& key)
|
||||||
|
{
|
||||||
|
if constexpr (std::convertible_to<std::decay_t<decltype(key)>, typename config_t::key_type>) {
|
||||||
|
return _currentConfig[key];
|
||||||
|
} else {
|
||||||
|
typename config_t::key_type skey;
|
||||||
|
std::ranges::copy(std::forward<decltype(key)>(key), std::back_inserter(skey));
|
||||||
|
return _currentConfig[key];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::ifstream fin(pt_cn);
|
const config_value_t& operator[](traits::mcc_input_char_range auto&& key) const
|
||||||
|
{
|
||||||
|
return const_cast<const MccConfigfile&>(*this).operator[](std::forward<decltype(key)>(key));
|
||||||
|
}
|
||||||
|
|
||||||
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();
|
std::error_code load(std::derived_from<std::basic_istream<char>> auto& stream)
|
||||||
|
{
|
||||||
_currentConfig.clear();
|
_currentConfig.clear();
|
||||||
|
|
||||||
// read line-by-line
|
// read line-by-line
|
||||||
for (std::string line; std::getline(fin, line);) {
|
for (std::string line; std::getline(stream, line);) {
|
||||||
if (line.empty()) {
|
if (line.empty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -100,14 +117,19 @@ public:
|
|||||||
_currentConfig[skey] = std::string{vals.begin(), vals.end()};
|
_currentConfig[skey] = std::string{vals.begin(), vals.end()};
|
||||||
} else { // vector of values
|
} else { // vector of values
|
||||||
std::vector<std::string> elems;
|
std::vector<std::string> elems;
|
||||||
while (it_dlm != vals.end()) {
|
// while (it_dlm != vals.end()) {
|
||||||
auto el = utils::trimSpaces(std::string_view{vals.begin(), it_dlm});
|
// 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);
|
||||||
|
// }
|
||||||
|
|
||||||
|
for (const auto& el :
|
||||||
|
std::views::split(vals, VALUE_VALUE_DELIM) |
|
||||||
|
std::views::transform([](const auto& sv) { return utils::trimSpaces(sv); })) {
|
||||||
elems.emplace_back(el.begin(), el.end());
|
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;
|
_currentConfig[skey] = elems;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -116,11 +138,85 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::error_code load(traits::mcc_input_char_range auto const& 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();
|
||||||
|
|
||||||
|
load(fin);
|
||||||
|
|
||||||
fin.close();
|
fin.close();
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::error_code save() const
|
||||||
|
{
|
||||||
|
std::ofstream fst(_currentFilename, std::ios::trunc);
|
||||||
|
|
||||||
|
if (!fst.is_open()) {
|
||||||
|
return std::make_error_code(std::errc::no_such_file_or_directory);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
|
||||||
|
|
||||||
|
fst << "#\n";
|
||||||
|
fst << "# Created by MccConfigfile class (" << std::put_time(std::localtime(&now), "[%F %T]") << ")\n";
|
||||||
|
fst << "#\n";
|
||||||
|
|
||||||
|
for (auto& [key, value] : _currentConfig) {
|
||||||
|
fst << key << " = ";
|
||||||
|
|
||||||
|
if (auto v_str = std::get_if<1>(&value)) {
|
||||||
|
fst << *v_str;
|
||||||
|
} else if (auto v_vec = std::get_if<2>(&value)) {
|
||||||
|
fst << (*v_vec)[0];
|
||||||
|
for (size_t i = 1; i < v_vec->size(); ++i) {
|
||||||
|
fst << ", " << (*v_vec)[i];
|
||||||
|
}
|
||||||
|
} // std::monostate here
|
||||||
|
|
||||||
|
fst << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
fst.close();
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::error_code save(traits::mcc_input_char_range auto const& filename)
|
||||||
|
{
|
||||||
|
if (std::distance(filename.begin(), filename.end()) == 0) {
|
||||||
|
return std::make_error_code(std::errc::no_such_file_or_directory);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ranges::copy(filename, std::back_inserter(_currentFilename));
|
||||||
|
|
||||||
|
return save();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string currentFilename() const
|
std::string currentFilename() const
|
||||||
{
|
{
|
||||||
return _currentFilename;
|
return _currentFilename;
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <strstream>
|
||||||
|
|
||||||
#include "../comm_server_configfile.h"
|
#include "../comm_server_configfile.h"
|
||||||
|
|
||||||
@ -11,29 +12,50 @@ int main(int argc, char* argv[])
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto print_cfg = [](auto const& cfg) {
|
||||||
|
for (auto& [key, v] : cfg.config()) {
|
||||||
|
std::cout << key << " = ";
|
||||||
|
if (auto v_str = std::get_if<1>(&v)) {
|
||||||
|
std::cout << *v_str;
|
||||||
|
} else if (auto v_vec = std::get_if<2>(&v)) {
|
||||||
|
for (auto& el : *v_vec) {
|
||||||
|
std::cout << "<" << el << "> ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "\n";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
mcc::MccConfigfile cfg;
|
mcc::MccConfigfile cfg;
|
||||||
|
|
||||||
|
std::string str = R"--(key_no_val
|
||||||
|
# comment example
|
||||||
|
scalar_key = scalar-value
|
||||||
|
|
||||||
|
vec_key = 1,2,3 , 345, 4576, 79
|
||||||
|
)--";
|
||||||
|
|
||||||
|
std::istrstream ist(str.c_str());
|
||||||
|
cfg.load(ist);
|
||||||
|
|
||||||
|
std::cout << "From input stream: \n";
|
||||||
|
print_cfg(cfg);
|
||||||
|
|
||||||
|
cfg["vec_key"] = std::vector<std::string>{"10", "20", "30"};
|
||||||
|
cfg["new_key"] = "new-key-value";
|
||||||
|
|
||||||
|
|
||||||
|
cfg.save(std::string_view{argv[1]});
|
||||||
|
|
||||||
auto ec = cfg.load(std::string_view{argv[1]});
|
auto ec = cfg.load(std::string_view{argv[1]});
|
||||||
if (ec) {
|
if (ec) {
|
||||||
std::cout << "ERR: " << ec.message() << "\n";
|
std::cout << "ERR: " << ec.message() << "\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& [key, v] : cfg.config()) {
|
std::cout << "\n\nFrom file (edited):\n";
|
||||||
std::cout << "<" << key << "> = ";
|
print_cfg(cfg);
|
||||||
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user