Imported Debian patch 0.7.1-1
[hcoop/zz_old/debian/suphp.git] / src / IniFile.cpp
CommitLineData
623e7ab4 1/*
2 suPHP - (c)2002-2008 Sebastian Marsching <sebastian@marsching.com>
3
4 This file is part of suPHP.
5
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.
10
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.
15
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
19*/
20
21#include <string>
22#include <fstream>
23#include <sstream>
24#include <vector>
25
26#include "KeyNotFoundException.hpp"
27
28#include "IniFile.hpp"
29
30using namespace suPHP;
31
32const 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;
36 } else {
37 throw KeyNotFoundException("Section " + name + " not found",
38 __FILE__, __LINE__);
39 }
40}
41
42bool suPHP::IniFile::hasSection(const std::string& name) const {
43 if (this->sections.find(name) != this->sections.end()) {
44 return true;
45 } else {
46 return false;
47 }
48
49}
50
51const IniSection& suPHP::IniFile::operator[](const std::string& name) const
52 throw (KeyNotFoundException) {
53 return this->getSection(name);
54}
55
56
57void 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()) {
61 std::string line;
62 std::string tstr;
63 char dummy;
64 int startpos = 0;
65 int endpos = 0;
66
67 // Read line from file
68 getline(*is, line);
69
70 tstr = line;
71
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");
76
77 // Skip empty line, only containing whitespace
78 if (startpos == std::string::npos)
79 continue;
80
81 // Get trimmed string
82 tstr = tstr.substr(startpos, endpos - startpos + 1);
83
84 // Is line a comment (starting with ";")?
85 if (tstr[0] == ';') {
86 // Comments are not interessting => skip
87 continue;
88
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;
96 IniSection sect;
97 p.first = name;
98 p.second = sect;
99 this->sections.insert(p);
100 }
101 // Set current section
102 current_section = &(this->sections.find(name)->second);
103
104 // Is the line a key-value pair?
105 } else if (tstr.find_first_of('=') != std::string::npos) {
106 std::string name;
107 std::vector<std::string> values;
108 bool append_mode = false;
109
110 int eqpos = 0;
111
112 // Check wheter we already have a section
113 if (current_section == NULL) {
114 throw ParsingException("Option line \"" + tstr +
115 "\" before first section",
116 __FILE__, __LINE__);
117 }
118
119 // Extract name
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__);
123 }
124 if (tstr[eqpos-1] == '+') {
125 append_mode = true;
126 name = tstr.substr(0, eqpos-1);
127 } else {
128 name = tstr.substr(0, eqpos);
129 }
130
131 int temppos;
132 temppos = name.find_first_not_of(" \t");
133 if (temppos == std::string::npos) {
134 throw ParsingException("Malformed line: " + tstr, __FILE__, __LINE__);
135 }
136 name = name.substr(0, name.find_last_not_of(" \t") + 1);
137
138 bool in_quotes = false;
139 bool last_was_backslash = false;
140 int token_start = eqpos + 1;
141
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;
147 }
148 } else if (tstr[i] == '\\') {
149 if (!last_was_backslash) {
150 current_is_backslash = true;
151 }
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);
156 try {
157 token = parseValue(token);
158 } catch (ParsingException e) {
159 throw ParsingException("Malformed line: " + tstr, __FILE__, __LINE__);
160 }
161 if (token.length() == 0) {
162 throw ParsingException("Malformed line: " + tstr, __FILE__, __LINE__);
163 }
164 values.push_back(token);
165 token_start = i + 1;
166 }
167 }
168 if (i == tstr.length() - 1) {
169 if (in_quotes) {
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__);
173 }
174 std::string token = tstr.substr(token_start, i + 1 - token_start);
175 try {
176 token = parseValue(token);
177 } catch (ParsingException e) {
178 throw ParsingException("Malformed line: " + tstr, __FILE__, __LINE__);
179 }
180 if (token.length() == 0) {
181 throw ParsingException("Malformed line: " + tstr, __FILE__, __LINE__);
182 }
183 values.push_back(token);
184 }
185 last_was_backslash = current_is_backslash;
186 }
187
188 if (!append_mode) {
189 current_section->removeValues(name);
190 }
191 for (std::vector<std::string>::iterator i = values.begin(); i != values.end(); i++) {
192 current_section->putValue(name, *i);
193 }
194
195 // Line is something we do not know
196 } else {
197 throw ParsingException("Malformed line \"" + tstr + "\"",
198 __FILE__, __LINE__);
199 }
200 }
201 is->close();
202}
203
204std::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;
208 std::string output;
209
210 int startpos = value.find_first_not_of(" \t");
211 int endpos = value.find_last_not_of(" \t");
212 if (startpos == std::string::npos) {
213 return "";
214 }
215 if (endpos == std::string::npos) {
216 tempvalue = value;
217 } else {
218 tempvalue = value.substr(startpos, endpos - startpos + 1);
219 }
220
221 for (int i=0; i<value.length(); i++) {
222 bool current_is_backslash = false;
223
224 if (tempvalue[i] == '"') {
225 if (last_was_backslash) {
226 output.append("\"");
227 } else {
228 if (!in_quotes && i != 0) {
229 throw ParsingException("Content preceding quoted content", __FILE__, __LINE__);
230 }
231 if (in_quotes && i != tempvalue.length() - 1) {
232 throw ParsingException("Content following quoted content", __FILE__, __LINE__);
233 }
234 in_quotes = !in_quotes;
235 }
236 } else if (tempvalue[i] == '\\') {
237 if (last_was_backslash) {
238 output.append("\\");
239 } else {
240 current_is_backslash = true;
241 }
242 } else if (tempvalue[i] == ':') {
243 output.append(":");
244 } else {
245 if (last_was_backslash) {
246 throw ParsingException("Illegal character after backslash", __FILE__, __LINE__);
247 }
248 output.append(tempvalue.substr(i, 1));
249 }
250
251 last_was_backslash = current_is_backslash;
252 }
253
254 return output;
255}