2 suPHP - (c)2002-2008 Sebastian Marsching <sebastian@marsching.com>
4 This file is part of suPHP.
6 suPHP is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 suPHP is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with suPHP; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include "KeyNotFoundException.hpp"
28 #include "IniFile.hpp"
30 using namespace suPHP
;
32 const IniSection
& suPHP::IniFile::getSection(const std::string
& name
) const
33 throw (KeyNotFoundException
) {
34 if (this->sections
.find(name
) != this->sections
.end()) {
35 return this->sections
.find(name
)->second
;
37 throw KeyNotFoundException("Section " + name
+ " not found",
42 bool suPHP::IniFile::hasSection(const std::string
& name
) const {
43 if (this->sections
.find(name
) != this->sections
.end()) {
51 const IniSection
& suPHP::IniFile::operator[](const std::string
& name
) const
52 throw (KeyNotFoundException
) {
53 return this->getSection(name
);
57 void suPHP::IniFile::parse(const File
& file
) throw (IOException
, ParsingException
) {
58 SmartPtr
<std::ifstream
> is
= file
.getInputStream();
59 IniSection
*current_section
= NULL
;
60 while (!is
->eof() && !is
->bad() && !is
->fail()) {
67 // Read line from file
72 // Find first char not being space or tab
73 startpos
= tstr
.find_first_not_of(" \t");
74 // Find last char not being space or tab
75 endpos
= tstr
.find_last_not_of(" \t");
77 // Skip empty line, only containing whitespace
78 if (startpos
== std::string::npos
)
82 tstr
= tstr
.substr(startpos
, endpos
- startpos
+ 1);
84 // Is line a comment (starting with ";")?
86 // Comments are not interessting => skip
89 // Is line a section mark ("[section]")?
90 } else if (tstr
[0] == '[' && tstr
[tstr
.size()-1] == ']') {
91 // Extract name of section
92 std::string name
= tstr
.substr(1, tstr
.size() - 2);
93 // If section is not yet existing, create it
94 if (!this->hasSection(name
)) {
95 std::pair
<std::string
, IniSection
> p
;
99 this->sections
.insert(p
);
101 // Set current section
102 current_section
= &(this->sections
.find(name
)->second
);
104 // Is the line a key-value pair?
105 } else if (tstr
.find_first_of('=') != std::string::npos
) {
107 std::vector
<std::string
> values
;
108 bool append_mode
= false;
112 // Check wheter we already have a section
113 if (current_section
== NULL
) {
114 throw ParsingException("Option line \"" + tstr
+
115 "\" before first section",
120 eqpos
= tstr
.find_first_of('=');
121 if (eqpos
== std::string::npos
|| eqpos
< 1 || eqpos
== tstr
.length()-1) {
122 throw ParsingException("Malformed line: " + tstr
, __FILE__
, __LINE__
);
124 if (tstr
[eqpos
-1] == '+') {
126 name
= tstr
.substr(0, eqpos
-1);
128 name
= tstr
.substr(0, eqpos
);
132 temppos
= name
.find_first_not_of(" \t");
133 if (temppos
== std::string::npos
) {
134 throw ParsingException("Malformed line: " + tstr
, __FILE__
, __LINE__
);
136 name
= name
.substr(0, name
.find_last_not_of(" \t") + 1);
138 bool in_quotes
= false;
139 bool last_was_backslash
= false;
140 int token_start
= eqpos
+ 1;
142 for (int i
=eqpos
+1; i
<tstr
.length(); i
++) {
143 bool current_is_backslash
= false;
144 if (tstr
[i
] == '"') {
145 if (!last_was_backslash
) {
146 in_quotes
= !in_quotes
;
148 } else if (tstr
[i
] == '\\') {
149 if (!last_was_backslash
) {
150 current_is_backslash
= true;
152 } else if (tstr
[i
] == ':') {
153 if (!in_quotes
&& !last_was_backslash
) {
154 // Save token and begin new one
155 std::string token
= tstr
.substr(token_start
, i
- token_start
);
157 token
= parseValue(token
);
158 } catch (ParsingException e
) {
159 throw ParsingException("Malformed line: " + tstr
, __FILE__
, __LINE__
);
161 if (token
.length() == 0) {
162 throw ParsingException("Malformed line: " + tstr
, __FILE__
, __LINE__
);
164 values
.push_back(token
);
168 if (i
== tstr
.length() - 1) {
170 throw ParsingException("Unended quotes in line: " + tstr
, __FILE__
, __LINE__
);
171 } else if (last_was_backslash
) {
172 throw ParsingException("Multiline values are not supported in line: " + tstr
, __FILE__
, __LINE__
);
174 std::string token
= tstr
.substr(token_start
, i
+ 1 - token_start
);
176 token
= parseValue(token
);
177 } catch (ParsingException e
) {
178 throw ParsingException("Malformed line: " + tstr
, __FILE__
, __LINE__
);
180 if (token
.length() == 0) {
181 throw ParsingException("Malformed line: " + tstr
, __FILE__
, __LINE__
);
183 values
.push_back(token
);
185 last_was_backslash
= current_is_backslash
;
189 current_section
->removeValues(name
);
191 for (std::vector
<std::string
>::iterator i
= values
.begin(); i
!= values
.end(); i
++) {
192 current_section
->putValue(name
, *i
);
195 // Line is something we do not know
197 throw ParsingException("Malformed line \"" + tstr
+ "\"",
204 std::string
suPHP::IniFile::parseValue(const std::string
& value
) const throw (ParsingException
) {
205 bool in_quotes
= false;
206 bool last_was_backslash
= false;
207 std::string tempvalue
;
210 int startpos
= value
.find_first_not_of(" \t");
211 int endpos
= value
.find_last_not_of(" \t");
212 if (startpos
== std::string::npos
) {
215 if (endpos
== std::string::npos
) {
218 tempvalue
= value
.substr(startpos
, endpos
- startpos
+ 1);
221 for (int i
=0; i
<value
.length(); i
++) {
222 bool current_is_backslash
= false;
224 if (tempvalue
[i
] == '"') {
225 if (last_was_backslash
) {
228 if (!in_quotes
&& i
!= 0) {
229 throw ParsingException("Content preceding quoted content", __FILE__
, __LINE__
);
231 if (in_quotes
&& i
!= tempvalue
.length() - 1) {
232 throw ParsingException("Content following quoted content", __FILE__
, __LINE__
);
234 in_quotes
= !in_quotes
;
236 } else if (tempvalue
[i
] == '\\') {
237 if (last_was_backslash
) {
240 current_is_backslash
= true;
242 } else if (tempvalue
[i
] == ':') {
245 if (last_was_backslash
) {
246 throw ParsingException("Illegal character after backslash", __FILE__
, __LINE__
);
248 output
.append(tempvalue
.substr(i
, 1));
251 last_was_backslash
= current_is_backslash
;