| @@ -81,4 +81,33 @@ void lm::write_pairs(fs::path fpath, const std::vector<pair>& pairs) { | |||
| for (auto& pair : pairs) { | |||
| fstream << pair.key() << ": " << pair.value() << '\n'; | |||
| } | |||
| } | |||
| nested_kvlist nested_kvlist::parse(const std::string_view line_) { | |||
| const auto line = trim(line_); | |||
| const auto semi_pos = line.find(';'); | |||
| const auto primary = trim(line.substr(0, semi_pos)); | |||
| auto tail = semi_pos == line.npos ? ""sv : trim(line.substr(semi_pos + 1)); | |||
| std::vector<pair> pairs; | |||
| while (!tail.empty()) { | |||
| const auto space_pos = tail.find(' '); | |||
| const auto item = tail.substr(0, space_pos); | |||
| const auto eq_pos = item.find('='); | |||
| if (eq_pos == item.npos) { | |||
| pairs.emplace_back(item, ""sv); | |||
| } else { | |||
| const auto key = item.substr(0, eq_pos); | |||
| const auto value = item.substr(eq_pos + 1); | |||
| pairs.emplace_back(key, value); | |||
| } | |||
| if (space_pos == tail.npos) { | |||
| break; | |||
| } | |||
| tail = trim(tail.substr(space_pos + 1)); | |||
| } | |||
| return nested_kvlist{std::string(primary), pair_list{std::move(pairs)}}; | |||
| } | |||
| @@ -125,6 +125,13 @@ inline void write_pairs(const std::filesystem::path& fpath, const pair_list& pai | |||
| write_pairs(fpath, pairs.items()); | |||
| } | |||
| struct nested_kvlist { | |||
| std::string primary; | |||
| pair_list pairs; | |||
| static nested_kvlist parse(std::string_view s); | |||
| }; | |||
| template <typename What> | |||
| class read_required { | |||
| std::string_view _key; | |||
| @@ -80,9 +80,52 @@ void test_multi() { | |||
| CHECK(!iter); | |||
| } | |||
| void test_nested_kvlist() { | |||
| auto check_1 = [](auto str) { | |||
| auto result = nested_kvlist::parse(str); | |||
| CHECK(result.primary == "Foo"); | |||
| CHECK(result.pairs.size() == 1); | |||
| REQUIRE(result.pairs.find("bar")); | |||
| CHECK(result.pairs.find("bar")->value() == "baz"); | |||
| }; | |||
| check_1("Foo; bar=baz"); | |||
| check_1("Foo ; bar=baz"); | |||
| check_1("Foo ; bar=baz"); | |||
| check_1("Foo ; bar=baz "); | |||
| check_1("Foo;bar=baz "); | |||
| check_1("Foo;bar=baz"); | |||
| auto check_2 = [](auto str) { | |||
| auto result = nested_kvlist::parse(str); | |||
| CHECK(result.primary == "Foo"); | |||
| CHECK(result.pairs.size() == 0); | |||
| }; | |||
| check_2("Foo"); | |||
| check_2("Foo;"); | |||
| check_2("Foo ;"); | |||
| check_2("Foo ; "); | |||
| check_2("Foo; "); | |||
| auto check_3 = [](auto str) { | |||
| auto result = nested_kvlist::parse(str); | |||
| CHECK(result.primary == "Foo bar"); | |||
| CHECK(result.pairs.size() == 2); | |||
| REQUIRE(result.pairs.find("baz")); | |||
| CHECK(result.pairs.find("baz")->value() == "meow"); | |||
| REQUIRE(result.pairs.find("quux")); | |||
| CHECK(result.pairs.find("quux")->value() == ""); | |||
| }; | |||
| check_3("Foo bar; baz=meow quux"); | |||
| check_3("Foo bar ; baz=meow quux="); | |||
| check_3("Foo bar ; quux= baz=meow"); | |||
| check_3("Foo bar ;quux= baz=meow"); | |||
| } | |||
| void run_tests() { | |||
| test_simple(); | |||
| test_multi(); | |||
| test_nested_kvlist(); | |||
| } | |||
| DDS_TEST_MAIN; | |||