File indexing completed on 2025-01-18 09:50:18
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef BOOST_PROPERTY_TREE_INI_PARSER_HPP_INCLUDED
0012 #define BOOST_PROPERTY_TREE_INI_PARSER_HPP_INCLUDED
0013
0014 #include <boost/property_tree/ptree.hpp>
0015 #include <boost/property_tree/detail/ptree_utils.hpp>
0016 #include <boost/property_tree/detail/file_parser_error.hpp>
0017 #include <fstream>
0018 #include <string>
0019 #include <sstream>
0020 #include <stdexcept>
0021 #include <locale>
0022
0023 namespace boost { namespace property_tree { namespace ini_parser
0024 {
0025
0026
0027
0028
0029
0030
0031 inline bool validate_flags(int flags)
0032 {
0033 return flags == 0;
0034 }
0035
0036
0037 class ini_parser_error: public file_parser_error
0038 {
0039 public:
0040
0041
0042
0043
0044
0045
0046
0047
0048 ini_parser_error(const std::string &message,
0049 const std::string &filename,
0050 unsigned long line)
0051 : file_parser_error(message, filename, line)
0052 {
0053 }
0054 };
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064 template<class Ptree>
0065 void read_ini(std::basic_istream<
0066 typename Ptree::key_type::value_type> &stream,
0067 Ptree &pt)
0068 {
0069 typedef typename Ptree::key_type::value_type Ch;
0070 typedef std::basic_string<Ch> Str;
0071 const Ch semicolon = stream.widen(';');
0072 const Ch hash = stream.widen('#');
0073 const Ch lbracket = stream.widen('[');
0074 const Ch rbracket = stream.widen(']');
0075
0076 Ptree local;
0077 unsigned long line_no = 0;
0078 Ptree *section = 0;
0079 Str line;
0080
0081
0082 while (stream.good())
0083 {
0084
0085
0086 ++line_no;
0087 std::getline(stream, line);
0088 if (!stream.good() && !stream.eof())
0089 BOOST_PROPERTY_TREE_THROW(ini_parser_error(
0090 "read error", "", line_no));
0091
0092
0093 line = property_tree::detail::trim(line, stream.getloc());
0094 if (!line.empty())
0095 {
0096
0097 if (line[0] == semicolon || line[0] == hash)
0098 {
0099
0100 }
0101 else if (line[0] == lbracket)
0102 {
0103
0104 if (section && section->empty())
0105 local.pop_back();
0106 typename Str::size_type end = line.find(rbracket);
0107 if (end == Str::npos)
0108 BOOST_PROPERTY_TREE_THROW(ini_parser_error(
0109 "unmatched '['", "", line_no));
0110 Str key = property_tree::detail::trim(
0111 line.substr(1, end - 1), stream.getloc());
0112 if (local.find(key) != local.not_found())
0113 BOOST_PROPERTY_TREE_THROW(ini_parser_error(
0114 "duplicate section name", "", line_no));
0115 section = &local.push_back(
0116 std::make_pair(key, Ptree()))->second;
0117 }
0118 else
0119 {
0120 Ptree &container = section ? *section : local;
0121 typename Str::size_type eqpos = line.find(Ch('='));
0122 if (eqpos == Str::npos)
0123 BOOST_PROPERTY_TREE_THROW(ini_parser_error(
0124 "'=' character not found in line", "", line_no));
0125 if (eqpos == 0)
0126 BOOST_PROPERTY_TREE_THROW(ini_parser_error(
0127 "key expected", "", line_no));
0128 Str key = property_tree::detail::trim(
0129 line.substr(0, eqpos), stream.getloc());
0130 Str data = property_tree::detail::trim(
0131 line.substr(eqpos + 1, Str::npos), stream.getloc());
0132 if (container.find(key) != container.not_found())
0133 BOOST_PROPERTY_TREE_THROW(ini_parser_error(
0134 "duplicate key name", "", line_no));
0135 container.push_back(std::make_pair(key, Ptree(data)));
0136 }
0137 }
0138 }
0139
0140 if (section && section->empty())
0141 local.pop_back();
0142
0143
0144 pt.swap(local);
0145
0146 }
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157 template<class Ptree>
0158 void read_ini(const std::string &filename,
0159 Ptree &pt,
0160 const std::locale &loc = std::locale())
0161 {
0162 std::basic_ifstream<typename Ptree::key_type::value_type>
0163 stream(filename.c_str());
0164 if (!stream)
0165 BOOST_PROPERTY_TREE_THROW(ini_parser_error(
0166 "cannot open file", filename, 0));
0167 stream.imbue(loc);
0168 try {
0169 read_ini(stream, pt);
0170 }
0171 catch (ini_parser_error &e) {
0172 BOOST_PROPERTY_TREE_THROW(ini_parser_error(
0173 e.message(), filename, e.line()));
0174 }
0175 }
0176
0177 namespace detail
0178 {
0179 template<class Ptree>
0180 void check_dupes(const Ptree &pt)
0181 {
0182 if(pt.size() <= 1)
0183 return;
0184 const typename Ptree::key_type *lastkey = 0;
0185 typename Ptree::const_assoc_iterator it = pt.ordered_begin(),
0186 end = pt.not_found();
0187 lastkey = &it->first;
0188 for(++it; it != end; ++it) {
0189 if(*lastkey == it->first)
0190 BOOST_PROPERTY_TREE_THROW(ini_parser_error(
0191 "duplicate key", "", 0));
0192 lastkey = &it->first;
0193 }
0194 }
0195
0196 template <typename Ptree>
0197 void write_keys(std::basic_ostream<
0198 typename Ptree::key_type::value_type
0199 > &stream,
0200 const Ptree& pt,
0201 bool throw_on_children)
0202 {
0203 typedef typename Ptree::key_type::value_type Ch;
0204 for (typename Ptree::const_iterator it = pt.begin(), end = pt.end();
0205 it != end; ++it)
0206 {
0207 if (!it->second.empty()) {
0208 if (throw_on_children) {
0209 BOOST_PROPERTY_TREE_THROW(ini_parser_error(
0210 "ptree is too deep", "", 0));
0211 }
0212 continue;
0213 }
0214 stream << it->first << Ch('=')
0215 << it->second.template get_value<
0216 std::basic_string<Ch> >()
0217 << Ch('\n');
0218 }
0219 }
0220
0221 template <typename Ptree>
0222 void write_top_level_keys(std::basic_ostream<
0223 typename Ptree::key_type::value_type
0224 > &stream,
0225 const Ptree& pt)
0226 {
0227 write_keys(stream, pt, false);
0228 }
0229
0230 template <typename Ptree>
0231 void write_sections(std::basic_ostream<
0232 typename Ptree::key_type::value_type
0233 > &stream,
0234 const Ptree& pt)
0235 {
0236 typedef typename Ptree::key_type::value_type Ch;
0237 for (typename Ptree::const_iterator it = pt.begin(), end = pt.end();
0238 it != end; ++it)
0239 {
0240 if (!it->second.empty()) {
0241 check_dupes(it->second);
0242 if (!it->second.data().empty())
0243 BOOST_PROPERTY_TREE_THROW(ini_parser_error(
0244 "mixed data and children", "", 0));
0245 stream << Ch('[') << it->first << Ch(']') << Ch('\n');
0246 write_keys(stream, it->second, true);
0247 }
0248 }
0249 }
0250 }
0251
0252
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263
0264
0265
0266
0267 template<class Ptree>
0268 void write_ini(std::basic_ostream<
0269 typename Ptree::key_type::value_type
0270 > &stream,
0271 const Ptree &pt,
0272 int flags = 0)
0273 {
0274 BOOST_ASSERT(validate_flags(flags));
0275 (void)flags;
0276
0277 if (!pt.data().empty())
0278 BOOST_PROPERTY_TREE_THROW(ini_parser_error(
0279 "ptree has data on root", "", 0));
0280 detail::check_dupes(pt);
0281
0282 detail::write_top_level_keys(stream, pt);
0283 detail::write_sections(stream, pt);
0284 }
0285
0286
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304 template<class Ptree>
0305 void write_ini(const std::string &filename,
0306 const Ptree &pt,
0307 int flags = 0,
0308 const std::locale &loc = std::locale())
0309 {
0310 std::basic_ofstream<typename Ptree::key_type::value_type>
0311 stream(filename.c_str());
0312 if (!stream)
0313 BOOST_PROPERTY_TREE_THROW(ini_parser_error(
0314 "cannot open file", filename, 0));
0315 stream.imbue(loc);
0316 try {
0317 write_ini(stream, pt, flags);
0318 }
0319 catch (ini_parser_error &e) {
0320 BOOST_PROPERTY_TREE_THROW(ini_parser_error(
0321 e.message(), filename, e.line()));
0322 }
0323 stream.flush();
0324 if (!stream)
0325 BOOST_PROPERTY_TREE_THROW(ini_parser_error(
0326 "write error", filename, 0));
0327 }
0328
0329 } } }
0330
0331 namespace boost { namespace property_tree
0332 {
0333 using ini_parser::ini_parser_error;
0334 using ini_parser::read_ini;
0335 using ini_parser::write_ini;
0336 } }
0337
0338 #endif