diff --git a/src/kamokan_impl/ini_file.cpp b/src/kamokan_impl/ini_file.cpp index 6ca107e..fcba593 100644 --- a/src/kamokan_impl/ini_file.cpp +++ b/src/kamokan_impl/ini_file.cpp @@ -26,11 +26,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -57,6 +59,31 @@ namespace kamokan { Iterator m_begin; }; + template + struct IniCommentSkipper : boost::spirit::qi::grammar { + IniCommentSkipper() : + IniCommentSkipper::base_type(start), + first_char(true) + { + namespace px = boost::phoenix; + using boost::spirit::qi::blank; + using boost::spirit::qi::lit; + using boost::spirit::qi::eol; + using boost::spirit::qi::char_; + using boost::spirit::qi::eps; + + start = skipping[px::ref(first_char) = false]; + skipping = comment | blank; + comment = (eps(px::cref(first_char) == true) | eol) >> + *blank >> lit("#") >> *(char_ - eol); + } + + boost::spirit::qi::rule start; + boost::spirit::qi::rule skipping; + boost::spirit::qi::rule comment; + bool first_char; + }; + template IniGrammar::IniGrammar (const std::string* parString) : IniGrammar::base_type(start), @@ -68,6 +95,7 @@ namespace kamokan { using boost::spirit::qi::_val; using boost::spirit::_1; using boost::spirit::qi::eol; + using boost::spirit::qi::eoi; using boost::spirit::qi::raw; using boost::string_view; using boost::spirit::qi::hold; @@ -79,28 +107,28 @@ namespace kamokan { [_val = px::bind( &string_view::substr, px::construct(px::ref(*m_master_string)), - px::begin(_1) - px::ref(m_begin), px::size(_1) + px::begin(_1) - px::cref(m_begin), px::size(_1) )] >> ']'; key = raw[(graph - '[' - '=') >> *(graph - '=') >> *(hold[+blank >> +(graph - '=')])][_val = px::bind( &string_view::substr, px::construct(px::ref(*m_master_string)), - px::begin(_1) - px::ref(m_begin), px::size(_1) + px::begin(_1) - px::cref(m_begin), px::size(_1) )]; key_value = key[px::bind(&refpair::first, _val) = _1] >> '=' >> - raw[*(graph - eol) >> *(hold[+blank >> +(graph - eol)])][px::bind(&refpair::second, _val) = px::bind( + raw[*(graph - eol) % +blank][px::bind(&refpair::second, _val) = px::bind( &string_view::substr, px::construct(px::ref(*m_master_string)), - px::begin(_1) - px::ref(m_begin), px::size(_1) + px::begin(_1) - px::cref(m_begin), px::size(_1) )]; key_values = -(key_value % (+eol)); - start = *(*eol >> section >> +eol >> key_values >> *eol); + start = *eol >> *(section >> +eol >> key_values >> *eol); } IniFile::IniMapType parse_ini (const std::string* parIni, bool& parParseOk, int& parParsedCharCount) { - using boost::spirit::qi::blank; using boost::spirit::qi::blank_type; + using skipper_type = IniCommentSkipper; - IniGrammar gramm(parIni); + IniGrammar gramm(parIni); IniFile::IniMapType result; parParseOk = false; @@ -112,7 +140,7 @@ namespace kamokan { start_it, parIni->cend(), gramm, - blank, + skipper_type(), result ); diff --git a/test/unit/test_ini_file.cpp b/test/unit/test_ini_file.cpp index 30a7a1c..86bbd68 100644 --- a/test/unit/test_ini_file.cpp +++ b/test/unit/test_ini_file.cpp @@ -97,3 +97,35 @@ TEST_CASE ("Test parsing an ini text", "[ini][parser]") { //CHECK(ini.parsed_characters() == 27); } } + +TEST_CASE ("Test parsing an ini with comments", "[ini][parser][comments]") { + using kamokan::IniFile; + + std::string text( + "#leading comment\n" + "[section]\n" + "value = key\n" + "#this = shoul be ignored\n" + "\t#indented = comments should also be ignored\n" + "this = #should not be ignored #lol\n" + "#comment without newline" + ); + const int text_len = static_cast(text.size()); + IniFile ini(std::move(text)); + + CHECK(ini.parse_success()); + REQUIRE(ini.parsed_characters() == text_len); + + const IniFile::IniMapType& parsed = ini.parsed(); + CHECK(parsed.size() == 1); + REQUIRE_NOTHROW(parsed.at("section")); + + const IniFile::KeyValueMapType& section = parsed.at("section"); + REQUIRE(section.size() == 2); + REQUIRE_NOTHROW(section.at("value")); + REQUIRE_NOTHROW(section.at("this")); + CHECK_THROWS(section.at("#this")); + + CHECK(section.at("value") == "key"); + CHECK(section.at("this") == "#should not be ignored #lol"); +}