LeechCraft 0.6.70-17609-g3dde4097dd
Modular cross-platform feature rich live environment.
Loading...
Searching...
No Matches
desktopparser.cpp
Go to the documentation of this file.
1/**********************************************************************
2 * LeechCraft - modular cross-platform feature rich internet client.
3 * Copyright (C) 2006-2014 Georg Rudoy
4 *
5 * Distributed under the Boost Software License, Version 1.0.
6 * (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt)
7 **********************************************************************/
8
9#include "desktopparser.h"
10#include <optional>
11#include <boost/spirit/include/qi.hpp>
12#include <boost/fusion/adapted.hpp>
13#include <boost/phoenix.hpp>
14
16{
17 namespace
18 {
19 using FieldVal_t = boost::variant<std::string, std::vector<std::string>>;
20 using Lang_t = std::optional<std::string>;
21 struct Field
22 {
23 std::string Name_;
24 Lang_t Lang_;
25 FieldVal_t Val_;
26 };
27 using Fields_t = std::vector<Field>;
28
29 struct Group
30 {
31 std::string Name_;
32 Fields_t Fields_;
33 };
34 using Groups_t = std::vector<Group>;
35
36 struct File
37 {
38 Groups_t Groups_;
39 };
40 }
41}
42
43BOOST_FUSION_ADAPT_STRUCT (LC::Util::XDG::Field,
44 Name_,
45 Lang_,
46 Val_)
47
48BOOST_FUSION_ADAPT_STRUCT (LC::Util::XDG::Group,
49 Name_,
50 Fields_)
51
52BOOST_FUSION_ADAPT_STRUCT (LC::Util::XDG::File,
53 Groups_)
54
55namespace LC::Util::XDG
56{
57 namespace
58 {
59 namespace qi = boost::spirit::qi;
60 namespace phoenix = boost::phoenix;
61
62 template<typename Iter>
63 struct Parser : qi::grammar<Iter, File ()>
64 {
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_;
74
75 Parser ()
76 : Parser::base_type (Start_)
77 {
78 auto eol = qi::lit ("\n");
79 Comment_ %= qi::lit ("#") >> *(qi::char_ - '\r' - '\n') >> eol;
80
81 Lang_ %= '[' >> qi::lexeme [+(qi::char_ ("a-zA-Z0-9@_-"))] >> ']';
82
83 KeyValSep_ %= *(qi::lit (' ')) >> '=' >> *(qi::lit (' '));
84
85 LineValSingle_ %= qi::lexeme [+((qi::lit ("\\;") | (qi::char_ - ';' - '\r' - '\n')))];
86 LineVal_ %= ((LineValSingle_ % ';') >> -qi::lit (";")) | LineValSingle_;
87
88 Line_ %= qi::lexeme [+(qi::char_ ("a-zA-Z0-9-"))] >>
89 -Lang_ >>
90 KeyValSep_ >>
91 -LineVal_ >>
92 eol;
93
94 GroupName_ %= '[' >> qi::lexeme [+(qi::char_ ("a-zA-Z0-9 "))] >> ']';
95
96 Group_ %= GroupName_ >> eol >>
97 *(Comment_ | Line_ | eol);
98
99 Start_ %= *eol >> *Comment_ >> *eol >> +Group_;
100
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);
105 }
106 };
107
108 template<typename Iter>
109 File Parse (Iter begin, Iter end)
110 {
111 File res;
112 qi::parse (begin, end, Parser<Iter> (), res);
113 return res;
114 }
115
116 QString ToUtf8 (const std::string& str)
117 {
118 return QString::fromUtf8 (str.c_str ());
119 }
120
121 struct ValGetter : public boost::static_visitor<QStringList>
122 {
123 QStringList operator() (const std::string& str) const
124 {
125 return QStringList (ToUtf8 (str));
126 }
127
128 QStringList operator() (const std::vector<std::string>& vec) const
129 {
130 QStringList result;
131 std::transform (vec.begin (), vec.end (), std::back_inserter (result), ToUtf8);
132 return result;
133 }
134 };
135 }
136
137 auto DesktopParser::operator() (const QByteArray& data) -> Result_t
138 {
139 const auto& file = Parse (data.begin (), data.end ());
140
141 Result_t result;
142 for (const auto& item : file.Groups_)
143 {
144 Group_t group;
145 for (const auto& field : item.Fields_)
146 {
147 if (field.Name_.empty () && field.Val_ == FieldVal_t { std::string {} })
148 continue;
149
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;
153 }
154 result [ToUtf8 (item.Name_)] = group;
155 }
156 return result;
157 }
158}
UTIL_XDG_API Result_t operator()(const QByteArray &data)
Parses the XDG data.