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;