]> git.stg.codes - ssmd.git/blob - src/settingsfileparser.cpp
a21130766a8f997e23d50f4f9120b39e0be199df
[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     std::string text;
84     while(!in.eof()) {
85         std::string s;
86         std::getline(in, s);
87         text += s + "\n";
88     }
89
90     std::string::iterator begin = text.begin();
91     std::string::iterator end = text.end();
92
93     SectionsType data;
94     IniGrammar<std::string::iterator> parser; //  Our parser
95
96     if (!qi::parse(begin, end, parser, data)) {
97         throw std::runtime_error("Parse error");
98     }
99
100     std::string res;
101     _settings._isDaemon = fieldExists(data, "general", "daemon");
102     _settings._isDebug = fieldExists(data, "general", "debug");
103     if (fieldValue(data, "general", "log_file", res))
104         _settings._logFile = res;
105     if (fieldValue(data, "general", "pid_file", res))
106         _settings._PIDFile = res;
107     if (fieldValue(data, "sync", "switch_interval", res))
108         _settings._switchSyncInterval = boost::lexical_cast<time_t>(res);
109     if (fieldValue(data, "sync", "info_interval", res))
110         _settings._infoSyncInterval = boost::lexical_cast<time_t>(res);
111     if (fieldValue(data, "sync", "up_profile_id", res))
112         _settings._upProfileId = boost::lexical_cast<unsigned>(res);
113     if (fieldValue(data, "sync", "down_profile_id", res))
114         _settings._downProfileId = boost::lexical_cast<unsigned>(res);
115     if (fieldValue(data, "sync", "max_acl_per_pdu", res))
116         _settings._maxACLPerPDU = boost::lexical_cast<size_t>(res);
117     if (fieldValue(data, "sync", "data_url", res))
118         _settings._dataURL = res;
119     if (fieldValue(data, "sync", "script_base", res))
120         _settings._scriptBase = res;
121     _settings._dumpScripts = fieldExists(data, "sync", "dump_scripts");
122 }