11 #include <boost/spirit/include/qi.hpp>
12 #include <boost/spirit/include/phoenix.hpp>
13 #include <boost/fusion/adapted.hpp>
19 using FieldVal_t = boost::variant<std::string, std::vector<std::string>>;
20 using Lang_t = std::optional<std::string>;
27 using Fields_t = std::vector<Field>;
34 using Groups_t = std::vector<Group>;
59 namespace qi = boost::spirit::qi;
60 namespace phoenix = boost::phoenix;
62 template<
typename Iter>
63 struct Parser : qi::grammar<Iter, File ()>
65 qi::rule<Iter, File ()> Start_;
66 qi::rule<Iter, Group ()> Group_;
67 qi::rule<Iter, std::string ()> GroupName_;
68 qi::rule<Iter, std::string ()>
Lang_;
69 qi::rule<Iter, void ()> KeyValSep_;
70 qi::rule<Iter, std::string ()> LineValSingle_;
71 qi::rule<Iter, FieldVal_t ()> LineVal_;
72 qi::rule<Iter, Field ()> Line_;
73 qi::rule<Iter, void ()> Comment_;
76 : Parser::base_type (Start_)
78 auto eol = qi::lit (
"\n");
79 Comment_ %= qi::lit (
"#") >> *(qi::char_ -
'\r' -
'\n') >> eol;
81 Lang_ %=
'[' >> qi::lexeme [+(qi::char_ (
"a-zA-Z0-9@_-"))] >>
']';
83 KeyValSep_ %= *(qi::lit (
' ')) >>
'=' >> *(qi::lit (
' '));
85 LineValSingle_ %= qi::lexeme [+((qi::lit (
"\\;") | (qi::char_ -
';' -
'\r' -
'\n')))];
86 LineVal_ %= ((LineValSingle_ %
';') >> -qi::lit (
";")) | LineValSingle_;
88 Line_ %= qi::lexeme [+(qi::char_ (
"a-zA-Z0-9-"))] >>
94 GroupName_ %=
'[' >> qi::lexeme [+(qi::char_ (
"a-zA-Z0-9 "))] >>
']';
96 Group_ %= GroupName_ >> eol >>
97 *(Comment_ | Line_ | eol);
99 Start_ %= *eol >> *Comment_ >> +Group_;
101 qi::on_error<qi::fail> (Start_,
102 std::cout << phoenix::val (
"Error! Expecting") << qi::_4
103 << phoenix::val (
" here: \"") << phoenix::construct<std::string> (qi::_3, qi::_2)
104 << phoenix::val (
"\"") << std::endl);
108 template<
typename Iter>
109 File Parse (Iter begin, Iter end)
112 qi::parse (begin, end, Parser<Iter> (), res);
116 QString ToUtf8 (
const std::string& str)
118 return QString::fromUtf8 (str.c_str ());
121 struct ValGetter :
public boost::static_visitor<QStringList>
123 QStringList operator() (
const std::string& str)
const
125 return QStringList (ToUtf8 (str));
128 QStringList operator() (
const std::vector<std::string>& vec)
const
131 std::transform (vec.begin (), vec.end (), std::back_inserter (result), ToUtf8);
139 const auto& file = Parse (data.begin (), data.end ());
142 for (
const auto& item : file.Groups_)
145 for (
const auto& field : item.Fields_)
147 if (field.Name_.empty () && field.Val_ == FieldVal_t { std::string {} })
150 const auto& values = boost::apply_visitor (ValGetter (), field.Val_);
151 const auto& lang = field.Lang_ ? ToUtf8 (*field.Lang_) : QString ();
152 group [ToUtf8 (field.Name_)] [lang] = values;
154 result [ToUtf8 (item.Name_)] = group;