LeechCraft  0.6.70-15082-g543737046d
Modular cross-platform feature rich live environment.
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/spirit/include/phoenix.hpp>
13 #include <boost/fusion/adapted.hpp>
14 
15 namespace LC::Util::XDG
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 
43 BOOST_FUSION_ADAPT_STRUCT (LC::Util::XDG::Field,
45  Lang_,
46  Val_)
47 
48 BOOST_FUSION_ADAPT_STRUCT (LC::Util::XDG::Group,
49  Name_,
51 
52 BOOST_FUSION_ADAPT_STRUCT (LC::Util::XDG::File,
53  Groups_)
54 
55 namespace 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_ >> +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 }
Lang_
Lang_t Lang_
Definition: desktopparser.cpp:36
Val_
FieldVal_t Val_
Definition: desktopparser.cpp:37
LC::Util::XDG::DesktopParser::operator()
UTIL_XDG_API Result_t operator()(const QByteArray &data)
Parses the XDG data.
Groups_
Groups_t Groups_
Definition: desktopparser.cpp:50
LC::Util::XDG
Definition: desktopparser.cpp:15
desktopparser.h
Fields_
Fields_t Fields_
Definition: desktopparser.cpp:44
BOOST_FUSION_ADAPT_STRUCT
BOOST_FUSION_ADAPT_STRUCT(Student, ID_, Name_) struct StudentInfo
Definition: oralfkeytest.cpp:30
Name_
std::string Name_
Definition: desktopparser.cpp:35