1 /*
2  * Copyright (C) 2007 Tommi Maekitalo
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * As a special exception, you may use this file as part of a free
10  * software library without restriction. Specifically, if other files
11  * instantiate templates or use macros or inline functions from this
12  * file, or you compile this file and link it with other files to
13  * produce an executable, this file does not by itself cause the
14  * resulting executable to be covered by the GNU General Public
15  * License. This exception does not however invalidate any other
16  * reasons why the executable file might be covered by the GNU Library
17  * General Public License.
18  *
19  * This library is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22  * Lesser General Public License for more details.
23  *
24  * You should have received a copy of the GNU Lesser General Public
25  * License along with this library; if not, write to the Free Software
26  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
27  */
28 
29 #include <cxxtools/iniparser.h>
30 #include <cxxtools/log.h>
31 #include <cctype>
32 #include <iostream>
33 #include <stdexcept>
34 
35 log_define("cxxtools.iniparser")
36 
37 namespace cxxtools
38 {
onSection(const std::string & section)39   bool IniParser::Event::onSection(const std::string& section)
40   {
41     return false;
42   }
43 
onKey(const std::string & key)44   bool IniParser::Event::onKey(const std::string& key)
45   {
46     return false;
47   }
48 
onValue(const std::string & key)49   bool IniParser::Event::onValue(const std::string& key)
50   {
51     return false;
52   }
53 
onComment(const std::string & comment)54   bool IniParser::Event::onComment(const std::string& comment)
55   {
56     return false;
57   }
58 
onError()59   bool IniParser::Event::onError()
60   {
61     throw std::runtime_error("parse error in ini-file");
62     return true;
63   }
64 
parse(std::istream & in)65   void IniParser::parse(std::istream& in)
66   {
67     char ch;
68     while (in.get(ch) && !parse(ch))
69       ;
70     end();
71   }
72 
parse(char ch)73   bool IniParser::parse(char ch)
74   {
75     bool ret = false;
76     switch (state)
77     {
78       case state_0:
79         if (ch == '[')
80           state = state_section;
81         else if (std::isalnum(ch))
82         {
83           data = ch;
84           state = state_key;
85         }
86         else if (ch == '#' || ch == ';')
87         {
88           state = state_comment;
89         }
90         else if (std::isspace(ch))
91           ;
92         else
93         {
94           log_debug("onError");
95           ret = event.onError();
96         }
97         break;
98 
99       case state_section:
100         if (ch == ']')
101         {
102           log_debug("onSection(" << data << ')');
103           ret = event.onSection(data);
104           data.clear();
105           state = state_0;
106         }
107         else
108           data += ch;
109         break;
110 
111       case state_key:
112         if (ch == '=')
113         {
114           log_debug("onKey(" << data << ')');
115           ret = event.onKey(data);
116           state = state_value0;
117         }
118         else if (std::isspace(ch))
119         {
120           log_debug("onKey(" << data << ')');
121           ret = event.onKey(data);
122           state = state_key_sp;
123         }
124         else
125           data += ch;
126         break;
127 
128       case state_key_sp:
129         if (ch == '=')
130           state = state_value0;
131         else if (!std::isspace(ch))
132         {
133           log_debug("onError");
134           ret = event.onError();
135         }
136         break;
137 
138       case state_value0:
139         if (ch == '\n')
140         {
141           log_debug("onValue(\"\")");
142           ret = event.onValue(std::string());
143           state = state_0;
144         }
145         else if (!std::isspace(ch))
146         {
147           data = ch;
148           state = state_value;
149         }
150         break;
151 
152       case state_value:
153         if (ch == '\n')
154         {
155           log_debug("onValue(" << data << ')');
156           ret = event.onValue(data);
157           data.clear();
158           state = state_0;
159         }
160         else
161           data += ch;
162         break;
163 
164       case state_comment:
165         if (ch == '\n')
166           state = state_0;
167         break;
168     }
169 
170     return ret;
171   }
172 
end()173   void IniParser::end()
174   {
175     switch (state)
176     {
177       case state_0:
178       case state_comment:
179         break;
180 
181       case state_section:
182       case state_key:
183       case state_key_sp:
184         log_debug("onError");
185         event.onError();
186         break;
187 
188       case state_value0:
189         log_debug("onValue(\"\")");
190         event.onValue(std::string());
191         break;
192 
193       case state_value:
194         log_debug("onValue" << data << ')');
195         event.onValue(data);
196         break;
197     }
198   }
199 
200 }
201