Ticket #12259: ini_parser.diff
File ini_parser.diff, 10.4 KB (added by , 4 years ago) |
---|
-
ini_parser.hpp
old new 22 22 23 23 namespace boost { namespace property_tree { namespace ini_parser 24 24 { 25 template <class Str> 26 inline Str comment_key() 27 { 28 return Str("inicomment"); 29 } 25 30 26 31 /** 27 32 * Determines whether the @c flags are valid for use with the ini_parser. … … 60 65 * @throw ini_parser_error If a format violation is found. 61 66 * @param stream Stream from which to read in the property tree. 62 67 * @param[out] pt The property tree to populate. 68 * 69 * Comments will be stored in the propertyTree alongside the actual property 70 * in an additional entry \c key.inicomment (wie von comment_key() returned). 63 71 */ 64 72 template<class Ptree> 65 73 void read_ini(std::basic_istream< … … 72 80 const Ch hash = stream.widen('#'); 73 81 const Ch lbracket = stream.widen('['); 74 82 const Ch rbracket = stream.widen(']'); 83 const Str commentKey = comment_key<Str>(); 75 84 76 85 Ptree local; 77 86 unsigned long line_no = 0; 78 87 Ptree *section = 0; 79 88 Str line; 89 Str lastComment; 80 90 81 91 // For all lines 82 92 while (stream.good()) … … 96 106 // Comment, section or key? 97 107 if (line[0] == semicolon || line[0] == hash) 98 108 { 99 // Ignore comments 109 // Save comments to intermediate storage 110 if (!lastComment.empty()) 111 lastComment += Ch('\n'); 112 lastComment += line.substr(1); 100 113 } 101 114 else if (line[0] == lbracket) 102 115 { … … 114 127 "duplicate section name", "", line_no)); 115 128 section = &local.push_back( 116 129 std::make_pair(key, Ptree()))->second; 130 if (!lastComment.empty()) 131 { 132 section->put(commentKey, lastComment); 133 lastComment.clear(); 134 } 117 135 } 118 136 else 119 137 { … … 132 150 if (container.find(key) != container.not_found()) 133 151 BOOST_PROPERTY_TREE_THROW(ini_parser_error( 134 152 "duplicate key name", "", line_no)); 135 container.push_back(std::make_pair(key, Ptree(data))); 153 Ptree* section = &container.push_back(std::make_pair(key, Ptree(data)))->second; 154 if (!lastComment.empty()) 155 { 156 section->put(commentKey, lastComment); 157 lastComment.clear(); 158 } 136 159 } 137 160 } 138 161 } … … 193 216 } 194 217 } 195 218 219 template<class Ptree> 220 void write_comment(std::basic_ostream< 221 typename Ptree::key_type::value_type 222 > &stream, 223 const typename Ptree::key_type& comment, 224 const typename Ptree::key_type& commentStart) 225 { 226 typedef typename Ptree::key_type::value_type Ch; 227 if (comment.empty()) 228 return; 229 typename Ptree::key_type line; 230 bool hadNonEmptyLine = false; 231 for (size_t i = 0; i < comment.size(); i++) 232 { 233 if (comment[i] == Ch('\n')) 234 { 235 if (!line.empty() || hadNonEmptyLine) 236 { 237 // dump comment line 238 stream << commentStart << line << Ch('\n'); 239 } 240 else 241 { 242 // preceding empty lines are output without the commentStart 243 // dump comment line 244 stream << Ch('\n'); 245 } 246 line.clear(); 247 hadNonEmptyLine |= (!line.empty()); 248 } 249 else if (comment[i] != Ch('\r')) 250 { 251 // Ignore '\r' (for Windows!) 252 line += comment[i]; 253 } 254 } 255 if (!line.empty() || hadNonEmptyLine) 256 { 257 // dump comment line 258 stream << commentStart << line << Ch('\n'); 259 } 260 else 261 { 262 // preceding empty lines are output without the commentStart 263 // dump comment line 264 stream << Ch('\n'); 265 } 266 } 267 196 268 template <typename Ptree> 197 269 void write_keys(std::basic_ostream< 198 270 typename Ptree::key_type::value_type 199 271 > &stream, 200 272 const Ptree& pt, 201 bool throw_on_children) 273 bool throw_on_children, 274 const typename Ptree::key_type& commentKey, 275 const typename Ptree::key_type& commentStart) 202 276 { 203 277 typedef typename Ptree::key_type::value_type Ch; 204 278 for (typename Ptree::const_iterator it = pt.begin(), end = pt.end(); 205 279 it != end; ++it) 206 280 { 207 if (!it->second.empty()) { 208 if (throw_on_children) { 281 if (it->first != commentKey) 282 { 283 // We ignore the ".comment"-nodes, as these have special meaning! 284 285 // check for existence of comment node 286 boost::optional<typename Ptree::key_type> comment = it->second.template get_optional<typename Ptree::key_type>(commentKey); 287 288 if (!it->second.empty() && !(it->second.size() == 1 && comment)) 289 { 290 //only two depth-levels are allowd in INI-files ... but we also have to filter out the additional .comment nodes 291 if (throw_on_children) 292 { 209 293 BOOST_PROPERTY_TREE_THROW(ini_parser_error( 210 "ptree is too deep", "", 0));294 "ptree is too deep (only two depth steps alowed in INI files)", "", 0)); 211 295 } 212 296 continue; 213 297 } 298 if (comment) 299 { 300 // ... if it exists: output the comment 301 write_comment<Ptree>(stream, *comment, commentStart); 302 } 214 303 stream << it->first << Ch(' ') << Ch('=') << Ch(' ') 215 304 << it->second.template get_value< 216 305 std::basic_string<Ch> >() 217 306 << Ch('\n'); 218 307 } 219 stream << Ch('\n');308 } 220 309 } 221 310 222 311 template <typename Ptree> 223 312 void write_top_level_keys(std::basic_ostream< 224 313 typename Ptree::key_type::value_type 225 314 > &stream, 226 const Ptree& pt) 315 const Ptree& pt, 316 const typename Ptree::key_type& commentKey, 317 const typename Ptree::key_type& commentStart) 227 318 { 228 write_keys(stream, pt, false );319 write_keys(stream, pt, false, commentKey, commentStart); 229 320 } 230 321 231 322 template <typename Ptree> 232 323 void write_sections(std::basic_ostream< 233 324 typename Ptree::key_type::value_type 234 325 > &stream, 235 const Ptree& pt) 326 const Ptree& pt, 327 const typename Ptree::key_type& commentKey, 328 const typename Ptree::key_type& commentStart) 236 329 { 237 330 typedef typename Ptree::key_type::value_type Ch; 238 331 for (typename Ptree::const_iterator it = pt.begin(), end = pt.end(); … … 243 336 if (!it->second.data().empty()) 244 337 BOOST_PROPERTY_TREE_THROW(ini_parser_error( 245 338 "mixed data and children", "", 0)); 339 // empty lines in front of a new section to better separate it from other sections 340 stream << Ch('\n'); 341 // check for existence of comment node 342 boost::optional<typename Ptree::key_type> comment = pt.template get_optional<typename Ptree::key_type>(it->first + "." + commentKey); 343 if (comment) 344 { 345 std::string c = *comment; 346 // eat linebreak from start of comment to account for the two explicit \n inserted above! 347 while (!c.empty() && c[0] == Ch('\n')) 348 c = c.substr(1); 349 // ... if it exists: output the comment 350 if (!c.empty()) 351 write_comment<Ptree>(stream, c, commentStart); 352 } 246 353 stream << Ch('[') << it->first << Ch(']') << Ch('\n'); 247 write_keys(stream, it->second, true );354 write_keys(stream, it->second, true, commentKey, commentStart); 248 355 } 249 356 } 250 357 } … … 275 382 BOOST_ASSERT(validate_flags(flags)); 276 383 (void)flags; 277 384 385 const typename Ptree::key_type commentKey = comment_key<typename Ptree::key_type>(); 386 const typename Ptree::key_type commentStart = "#"; 387 278 388 if (!pt.data().empty()) 279 389 BOOST_PROPERTY_TREE_THROW(ini_parser_error( 280 390 "ptree has data on root", "", 0)); 281 391 detail::check_dupes(pt); 282 392 283 detail::write_top_level_keys(stream, pt );284 detail::write_sections(stream, pt );393 detail::write_top_level_keys(stream, pt, commentKey, commentStart); 394 detail::write_sections(stream, pt, commentKey, commentStart); 285 395 } 286 396 287 397 /**