]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/property_tree/ini_parser.hpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / boost / property_tree / ini_parser.hpp
1 // ----------------------------------------------------------------------------
2 // Copyright (C) 2002-2006 Marcin Kalicinski
3 // Copyright (C) 2009 Sebastian Redl
4 //
5 // Distributed under the Boost Software License, Version 1.0.
6 // (See accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt)
8 //
9 // For more information, see www.boost.org
10 // ----------------------------------------------------------------------------
11 #ifndef BOOST_PROPERTY_TREE_INI_PARSER_HPP_INCLUDED
12 #define BOOST_PROPERTY_TREE_INI_PARSER_HPP_INCLUDED
13
14 #include <boost/property_tree/ptree.hpp>
15 #include <boost/property_tree/detail/ptree_utils.hpp>
16 #include <boost/property_tree/detail/file_parser_error.hpp>
17 #include <fstream>
18 #include <string>
19 #include <sstream>
20 #include <stdexcept>
21 #include <locale>
22
23 namespace boost { namespace property_tree { namespace ini_parser
24 {
25
26 /**
27 * Determines whether the @c flags are valid for use with the ini_parser.
28 * @param flags value to check for validity as flags to ini_parser.
29 * @return true if the flags are valid, false otherwise.
30 */
31 inline bool validate_flags(int flags)
32 {
33 return flags == 0;
34 }
35
36 /** Indicates an error parsing INI formatted data. */
37 class ini_parser_error: public file_parser_error
38 {
39 public:
40 /**
41 * Construct an @c ini_parser_error
42 * @param message Message describing the parser error.
43 * @param filename The name of the file being parsed containing the
44 * error.
45 * @param line The line in the given file where an error was
46 * encountered.
47 */
48 ini_parser_error(const std::string &message,
49 const std::string &filename,
50 unsigned long line)
51 : file_parser_error(message, filename, line)
52 {
53 }
54 };
55
56 /**
57 * Read INI from a the given stream and translate it to a property tree.
58 * @note Clears existing contents of property tree. In case of error
59 * the property tree is not modified.
60 * @throw ini_parser_error If a format violation is found.
61 * @param stream Stream from which to read in the property tree.
62 * @param[out] pt The property tree to populate.
63 */
64 template<class Ptree>
65 void read_ini(std::basic_istream<
66 typename Ptree::key_type::value_type> &stream,
67 Ptree &pt)
68 {
69 typedef typename Ptree::key_type::value_type Ch;
70 typedef std::basic_string<Ch> Str;
71 const Ch semicolon = stream.widen(';');
72 const Ch hash = stream.widen('#');
73 const Ch lbracket = stream.widen('[');
74 const Ch rbracket = stream.widen(']');
75
76 Ptree local;
77 unsigned long line_no = 0;
78 Ptree *section = 0;
79 Str line;
80
81 // For all lines
82 while (stream.good())
83 {
84
85 // Get line from stream
86 ++line_no;
87 std::getline(stream, line);
88 if (!stream.good() && !stream.eof())
89 BOOST_PROPERTY_TREE_THROW(ini_parser_error(
90 "read error", "", line_no));
91
92 // If line is non-empty
93 line = property_tree::detail::trim(line, stream.getloc());
94 if (!line.empty())
95 {
96 // Comment, section or key?
97 if (line[0] == semicolon || line[0] == hash)
98 {
99 // Ignore comments
100 }
101 else if (line[0] == lbracket)
102 {
103 // If the previous section was empty, drop it again.
104 if (section && section->empty())
105 local.pop_back();
106 typename Str::size_type end = line.find(rbracket);
107 if (end == Str::npos)
108 BOOST_PROPERTY_TREE_THROW(ini_parser_error(
109 "unmatched '['", "", line_no));
110 Str key = property_tree::detail::trim(
111 line.substr(1, end - 1), stream.getloc());
112 if (local.find(key) != local.not_found())
113 BOOST_PROPERTY_TREE_THROW(ini_parser_error(
114 "duplicate section name", "", line_no));
115 section = &local.push_back(
116 std::make_pair(key, Ptree()))->second;
117 }
118 else
119 {
120 Ptree &container = section ? *section : local;
121 typename Str::size_type eqpos = line.find(Ch('='));
122 if (eqpos == Str::npos)
123 BOOST_PROPERTY_TREE_THROW(ini_parser_error(
124 "'=' character not found in line", "", line_no));
125 if (eqpos == 0)
126 BOOST_PROPERTY_TREE_THROW(ini_parser_error(
127 "key expected", "", line_no));
128 Str key = property_tree::detail::trim(
129 line.substr(0, eqpos), stream.getloc());
130 Str data = property_tree::detail::trim(
131 line.substr(eqpos + 1, Str::npos), stream.getloc());
132 if (container.find(key) != container.not_found())
133 BOOST_PROPERTY_TREE_THROW(ini_parser_error(
134 "duplicate key name", "", line_no));
135 container.push_back(std::make_pair(key, Ptree(data)));
136 }
137 }
138 }
139 // If the last section was empty, drop it again.
140 if (section && section->empty())
141 local.pop_back();
142
143 // Swap local ptree with result ptree
144 pt.swap(local);
145
146 }
147
148 /**
149 * Read INI from a the given file and translate it to a property tree.
150 * @note Clears existing contents of property tree. In case of error the
151 * property tree unmodified.
152 * @throw ini_parser_error In case of error deserializing the property tree.
153 * @param filename Name of file from which to read in the property tree.
154 * @param[out] pt The property tree to populate.
155 * @param loc The locale to use when reading in the file contents.
156 */
157 template<class Ptree>
158 void read_ini(const std::string &filename,
159 Ptree &pt,
160 const std::locale &loc = std::locale())
161 {
162 std::basic_ifstream<typename Ptree::key_type::value_type>
163 stream(filename.c_str());
164 if (!stream)
165 BOOST_PROPERTY_TREE_THROW(ini_parser_error(
166 "cannot open file", filename, 0));
167 stream.imbue(loc);
168 try {
169 read_ini(stream, pt);
170 }
171 catch (ini_parser_error &e) {
172 BOOST_PROPERTY_TREE_THROW(ini_parser_error(
173 e.message(), filename, e.line()));
174 }
175 }
176
177 namespace detail
178 {
179 template<class Ptree>
180 void check_dupes(const Ptree &pt)
181 {
182 if(pt.size() <= 1)
183 return;
184 const typename Ptree::key_type *lastkey = 0;
185 typename Ptree::const_assoc_iterator it = pt.ordered_begin(),
186 end = pt.not_found();
187 lastkey = &it->first;
188 for(++it; it != end; ++it) {
189 if(*lastkey == it->first)
190 BOOST_PROPERTY_TREE_THROW(ini_parser_error(
191 "duplicate key", "", 0));
192 lastkey = &it->first;
193 }
194 }
195
196 template <typename Ptree>
197 void write_keys(std::basic_ostream<
198 typename Ptree::key_type::value_type
199 > &stream,
200 const Ptree& pt,
201 bool throw_on_children)
202 {
203 typedef typename Ptree::key_type::value_type Ch;
204 for (typename Ptree::const_iterator it = pt.begin(), end = pt.end();
205 it != end; ++it)
206 {
207 if (!it->second.empty()) {
208 if (throw_on_children) {
209 BOOST_PROPERTY_TREE_THROW(ini_parser_error(
210 "ptree is too deep", "", 0));
211 }
212 continue;
213 }
214 stream << it->first << Ch('=')
215 << it->second.template get_value<
216 std::basic_string<Ch> >()
217 << Ch('\n');
218 }
219 }
220
221 template <typename Ptree>
222 void write_top_level_keys(std::basic_ostream<
223 typename Ptree::key_type::value_type
224 > &stream,
225 const Ptree& pt)
226 {
227 write_keys(stream, pt, false);
228 }
229
230 template <typename Ptree>
231 void write_sections(std::basic_ostream<
232 typename Ptree::key_type::value_type
233 > &stream,
234 const Ptree& pt)
235 {
236 typedef typename Ptree::key_type::value_type Ch;
237 for (typename Ptree::const_iterator it = pt.begin(), end = pt.end();
238 it != end; ++it)
239 {
240 if (!it->second.empty()) {
241 check_dupes(it->second);
242 if (!it->second.data().empty())
243 BOOST_PROPERTY_TREE_THROW(ini_parser_error(
244 "mixed data and children", "", 0));
245 stream << Ch('[') << it->first << Ch(']') << Ch('\n');
246 write_keys(stream, it->second, true);
247 }
248 }
249 }
250 }
251
252 /**
253 * Translates the property tree to INI and writes it the given output
254 * stream.
255 * @pre @e pt cannot have data in its root.
256 * @pre @e pt cannot have keys both data and children.
257 * @pre @e pt cannot be deeper than two levels.
258 * @pre There cannot be duplicate keys on any given level of @e pt.
259 * @throw ini_parser_error In case of error translating the property tree to
260 * INI or writing to the output stream.
261 * @param stream The stream to which to write the INI representation of the
262 * property tree.
263 * @param pt The property tree to tranlsate to INI and output.
264 * @param flags The flags to use when writing the INI file.
265 * No flags are currently supported.
266 */
267 template<class Ptree>
268 void write_ini(std::basic_ostream<
269 typename Ptree::key_type::value_type
270 > &stream,
271 const Ptree &pt,
272 int flags = 0)
273 {
274 BOOST_ASSERT(validate_flags(flags));
275 (void)flags;
276
277 if (!pt.data().empty())
278 BOOST_PROPERTY_TREE_THROW(ini_parser_error(
279 "ptree has data on root", "", 0));
280 detail::check_dupes(pt);
281
282 detail::write_top_level_keys(stream, pt);
283 detail::write_sections(stream, pt);
284 }
285
286 /**
287 * Translates the property tree to INI and writes it the given file.
288 * @pre @e pt cannot have data in its root.
289 * @pre @e pt cannot have keys both data and children.
290 * @pre @e pt cannot be deeper than two levels.
291 * @pre There cannot be duplicate keys on any given level of @e pt.
292 * @throw info_parser_error In case of error translating the property tree
293 * to INI or writing to the file.
294 * @param filename The name of the file to which to write the INI
295 * representation of the property tree.
296 * @param pt The property tree to tranlsate to INI and output.
297 * @param flags The flags to use when writing the INI file.
298 * The following flags are supported:
299 * @li @c skip_ini_validity_check -- Skip check if ptree is a valid ini. The
300 * validity check covers the preconditions but takes <tt>O(n log n)</tt>
301 * time.
302 * @param loc The locale to use when writing the file.
303 */
304 template<class Ptree>
305 void write_ini(const std::string &filename,
306 const Ptree &pt,
307 int flags = 0,
308 const std::locale &loc = std::locale())
309 {
310 std::basic_ofstream<typename Ptree::key_type::value_type>
311 stream(filename.c_str());
312 if (!stream)
313 BOOST_PROPERTY_TREE_THROW(ini_parser_error(
314 "cannot open file", filename, 0));
315 stream.imbue(loc);
316 try {
317 write_ini(stream, pt, flags);
318 }
319 catch (ini_parser_error &e) {
320 BOOST_PROPERTY_TREE_THROW(ini_parser_error(
321 e.message(), filename, e.line()));
322 }
323 }
324
325 } } }
326
327 namespace boost { namespace property_tree
328 {
329 using ini_parser::ini_parser_error;
330 using ini_parser::read_ini;
331 using ini_parser::write_ini;
332 } }
333
334 #endif