| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
|---|---|
| 2 | |
| 3 | #include "libconfig/libconfig.h" |
| 4 | |
| 5 | #include <fstream> |
| 6 | #include <iostream> |
| 7 | |
| 8 | std::optional<Config> Config::from_file(const std::string &filepath) |
| 9 | { |
| 10 | std::fstream f(filepath, f.in); |
| 11 | if (!f) |
| 12 | return std::nullopt; |
| 13 | |
| 14 | Config config; |
| 15 | |
| 16 | Config::SectionType current_section = std::make_pair(x: "global", y: Config::SectionContentType{}); |
| 17 | for (std::string line; std::getline(is&: f, str&: line);) |
| 18 | { |
| 19 | if (line.empty()) |
| 20 | continue; |
| 21 | |
| 22 | if (line.starts_with(x: '#')) |
| 23 | continue; |
| 24 | |
| 25 | if (line.starts_with(x: '[') && line.ends_with(x: ']')) |
| 26 | { |
| 27 | // a new section |
| 28 | config.sections.push_back(x: current_section); |
| 29 | current_section = std::make_pair(x: line.substr(pos: 1, n: line.size() - 2), y: Config::SectionContentType{}); // remove the brackets |
| 30 | } |
| 31 | else |
| 32 | { |
| 33 | // a key-value pair |
| 34 | size_t pos = line.find(c: '='); |
| 35 | if (pos == std::string::npos) |
| 36 | { |
| 37 | std::cerr << "Invalid line: "<< line << std::endl; |
| 38 | continue; |
| 39 | } |
| 40 | |
| 41 | std::string key = line.substr(pos: 0, n: pos); |
| 42 | std::string value = line.substr(pos: pos + 1); |
| 43 | |
| 44 | const auto remove_leading_trailing_spaces = [](std::string &str) |
| 45 | { |
| 46 | while (!str.empty() && str.front() == ' ') |
| 47 | str.erase(pos: 0, n: 1); |
| 48 | while (!str.empty() && str.back() == ' ') |
| 49 | str.pop_back(); |
| 50 | }; |
| 51 | |
| 52 | remove_leading_trailing_spaces(key); |
| 53 | remove_leading_trailing_spaces(value); |
| 54 | |
| 55 | current_section.second.push_back(x: { key, value }); |
| 56 | } |
| 57 | } |
| 58 | |
| 59 | config.sections.push_back(x: current_section); |
| 60 | |
| 61 | return config; |
| 62 | } |
| 63 | |
| 64 | std::optional<Config::SectionType> Config::get_section(const std::string §ion_name) const |
| 65 | { |
| 66 | for (const auto §ion : sections) |
| 67 | if (section.first == section_name) |
| 68 | return section; |
| 69 | |
| 70 | return std::nullopt; |
| 71 | } |
| 72 | |
| 73 | std::vector<Config::EntryType> Config::get_entry(const std::string §ion_name, const std::string &key) const |
| 74 | { |
| 75 | auto entries = get_section(section_name); |
| 76 | if (!entries) |
| 77 | return {}; |
| 78 | return entries->second | std::ranges::views::filter([&key](const auto &entry) { return entry.first == key; }) | std::ranges::to<std::vector<EntryType>>(); |
| 79 | } |
| 80 | |
| 81 | std::vector<Config::EntryType> Config::get_entries(const std::string §ion_name) const |
| 82 | { |
| 83 | auto entries = get_section(section_name); |
| 84 | if (!entries) |
| 85 | return {}; |
| 86 | return entries->second; |
| 87 | } |
| 88 |