31 #include <boost/spirit/include/qi.hpp>
32 #include <boost/spirit/include/phoenix.hpp>
33 #include <boost/fusion/adapted.hpp>
43 typedef boost::variant<std::string, std::vector<std::string>> FieldVal_t;
44 typedef boost::optional<std::string> Lang_t;
51 typedef std::vector<Field> Fields_t;
58 typedef std::vector<Group> Groups_t;
69 BOOST_FUSION_ADAPT_STRUCT (LeechCraft::Util::XDG::Field,
74 BOOST_FUSION_ADAPT_STRUCT (LeechCraft::Util::XDG::Group,
78 BOOST_FUSION_ADAPT_STRUCT (LeechCraft::Util::XDG::File,
89 namespace ascii = boost::spirit::ascii;
90 namespace qi = boost::spirit::qi;
91 namespace phoenix = boost::phoenix;
93 template<
typename Iter>
94 struct Parser : qi::grammar<Iter, File ()>
99 qi::rule<Iter, std::string ()>
Lang_;
107 :
Parser::base_type (Start_)
109 auto eol = qi::lit (
"\n");
110 Comment_ %= qi::lit (
"#") >> *(qi::char_ -
'\r' -
'\n') >> eol;
112 Lang_ %=
'[' >> qi::lexeme [+(qi::char_ (
"a-zA-Z0-9@_-"))] >>
']';
114 KeyValSep_ %= *(qi::lit (
' ')) >>
'=' >> *(qi::lit (
' '));
116 LineValSingle_ %= qi::lexeme [+((qi::lit (
"\\;") | (qi::char_ -
';' -
'\r' -
'\n')))];
117 LineVal_ %= ((LineValSingle_ %
';') >> -qi::lit (
";")) | LineValSingle_;
119 Line_ %= qi::lexeme [+(qi::char_ (
"a-zA-Z0-9-"))] >>
125 GroupName_ %=
'[' >> qi::lexeme [+(qi::char_ (
"a-zA-Z0-9 "))] >>
']';
127 Group_ %= GroupName_ >> eol >>
128 *(Comment_ | Line_ | eol);
130 Start_ %= *Comment_ >> +Group_;
132 qi::on_error<qi::fail> (Start_,
133 std::cout << phoenix::val (
"Error! Expecting") << qi::_4
134 << phoenix::val (
" here: \"") << phoenix::construct<std::string> (qi::_3, qi::_2)
135 << phoenix::val (
"\"") << std::endl);
139 template<
typename Iter>
149 return QString::fromUtf8 (str.c_str ());
152 struct ValGetter :
public boost::static_visitor<QStringList>
154 QStringList operator() (
const std::string& str)
const
156 return QStringList (
ToUtf8 (str));
159 QStringList operator() (
const std::vector<std::string>& vec)
const
162 std::transform (vec.begin (), vec.end (), std::back_inserter (result),
ToUtf8);
168 auto DesktopParser::operator() (
const QByteArray& data) ->
Result_t
170 const auto& file =
Parse (data.begin (), data.end ());
173 for (
const auto& item : file.Groups_)
176 for (
const auto& field : item.Fields_)
178 const auto& values = boost::apply_visitor (
ValGetter (), field.Val_);
179 const auto& lang = field.Lang_ ?
ToUtf8 (*field.Lang_) : QString ();
180 group [
ToUtf8 (field.Name_)] [lang] = values;
182 result [
ToUtf8 (item.Name_)] = group;
QString ToUtf8(const std::string &str)
File Parse(Iter begin, Iter end)
qi::rule< Iter, Group()> Group_
qi::rule< Iter, std::string()> GroupName_
qi::rule< Iter, void()> KeyValSep_
qi::rule< Iter, FieldVal_t()> LineVal_
qi::rule< Iter, File()> Start_
qi::rule< Iter, Field()> Line_
qi::rule< Iter, std::string()> LineValSingle_
qi::rule< Iter, void()> Comment_
qi::rule< Iter, std::string()> Lang_
QHash< QString, LangValue_t > Group_t
Mapping from a field name to the list of language-dependent values of that field. ...
QHash< QString, Group_t > Result_t
Mapping from a group name to the group itself.