]> git.stg.codes - ssmd.git/blob - src/settingsfileparser.cpp
bf2fda2ca27a2bb92c0c023da7c36df21947162d
[ssmd.git] / src / settingsfileparser.cpp
1 #include <fstream>
2 #include <numeric>
3 #include <map>
4 #include <string>
5
6 #include <boost/spirit/include/qi.hpp>
7 #include <boost/fusion/include/std_pair.hpp>
8
9 #include "settings.h"
10
11 namespace qi = boost::spirit::qi;
12
13 namespace {
14
15 typedef std::map<std::string, std::string> PairsType;
16 typedef std::map<std::string, PairsType> SectionsType;
17
18 template <typename Iterator>
19 struct IniGrammar 
20   : qi::grammar<Iterator, SectionsType()>
21 {
22     IniGrammar()
23       : IniGrammar::base_type(query)
24     {
25         query          = +(section | (comment >> eol) | (space >> eol));
26         section        =  sectionHeader >> -sectionContent;
27         sectionHeader  =  '[' >> space >> key >> space >> ']' >> eol;
28         sectionContent = +((line | comment | space) >> eol);
29         comment        =  (qi::char_(';') | '#') >> *qi::print;
30         line           =  space >> key >> space >> -('=' >> space >> value >> space);
31         key            =  qi::char_("a-zA-Z_") >> *qi::char_("a-zA-Z_0-9");
32         value          = +qi::print;
33         space          = *qi::char_("\t ");
34         eol            =  qi::lit("\r\n") | '\r' | '\n';
35     }
36
37     qi::rule<Iterator, SectionsType()> query;
38     qi::rule<Iterator, std::pair<std::string, PairsType>()> section;
39     qi::rule<Iterator, PairsType()> sectionContent;
40     qi::rule<Iterator, std::pair<std::string, std::string>()> line;
41     qi::rule<Iterator, std::string()> key, value, sectionHeader;
42     qi::rule<Iterator> comment, space, eol;
43 };
44
45 inline
46 bool sectionExists(const SectionsType & data, const std::string & sectionName) throw()
47 {
48     return data.find(sectionName) != data.end();
49 }
50
51 inline
52 bool fieldExists(const SectionsType & data, const std::string & sectionName, const std::string & fieldName) throw()
53 {
54     const SectionsType::const_iterator sectionIterator(data.find(sectionName));
55     if (sectionIterator == data.end())
56         return false;
57     return sectionIterator->second.find(fieldName) != sectionIterator->second.end();
58 }
59
60 inline
61 bool fieldValue(const SectionsType & data, const std::string & sectionName, const std::string & fieldName, std::string & value) throw()
62 {
63     const SectionsType::const_iterator sectionIterator(data.find(sectionName));
64     if (sectionIterator == data.end())
65         return false;
66     const PairsType::const_iterator pairIterator(sectionIterator->second.find(fieldName));
67     if (pairIterator == sectionIterator->second.end())
68         return false;
69     value = pairIterator->second;
70     return true;
71 }
72
73 }
74
75 using SSMD::SettingsParser;
76
77 void SettingsParser::parseFile(const std::string & fileName)
78 {
79     std::ifstream in(fileName.c_str());
80     if (!in) {
81         throw std::runtime_error("Can't open file");
82     }
83
84     std::string text;
85     while(!in.eof()) {
86         std::string s;
87         std::getline(in, s);
88         text += s + "\n";
89     }
90
91     std::string::iterator begin = text.begin();
92     std::string::iterator end = text.end();
93
94     SectionsType data;
95     IniGrammar<std::string::iterator> parser; //  Our parser
96
97     if (!qi::parse(begin, end, parser, data)) {
98         throw std::runtime_error("Parse error");
99     }
100
101     std::string res;
102     _settings._isDaemon = fieldExists(data, "general", "daemon");
103     _settings._isDebug = fieldExists(data, "general", "debug");
104     if (fieldValue(data, "general", "log_file", res)){
105         _settings._logFile = res;
106     }
107     if (fieldValue(data, "general", "pid_file", res)){
108         _settings._PIDFile = res;
109     }
110     if (fieldValue(data, "sync", "switch_interval", res)){
111         _settings._switchSyncInterval = boost::lexical_cast<time_t>(res);
112     }
113     if (fieldValue(data, "sync", "info_interval", res)){
114         _settings._infoSyncInterval = boost::lexical_cast<time_t>(res);
115     }
116     if (fieldValue(data, "sync", "up_profile_id", res)){
117         _settings._upProfileId = boost::lexical_cast<unsigned>(res);
118     }
119     if (fieldValue(data, "sync", "down_profile_id", res)){
120         _settings._downProfileId = boost::lexical_cast<unsigned>(res);
121     }
122     if (fieldValue(data, "sync", "max_acl_per_pdu", res)){
123         _settings._maxACLPerPDU = boost::lexical_cast<size_t>(res);
124     }
125     if (fieldValue(data, "sync", "data_url", res)){
126         _settings._dataURL = res;
127     }
128 }