Ticket #12259: ini_parser.patch
File ini_parser.patch, 10.5 KB (added by , 5 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.size() > 0) 111 lastComment += Ch('\n'); 112 if (line.size() >= 2) 113 { 114 if (std::isspace(line[1]) ) 115 lastComment += line.substr(2); 116 else 117 lastComment += line.substr(1); 118 } 100 119 } 101 120 else if (line[0] == lbracket) 102 121 { … … 114 133 "duplicate section name", "", line_no)); 115 134 section = &local.push_back( 116 135 std::make_pair(key, Ptree()))->second; 136 if (lastComment.size() > 0) 137 { 138 if (section) 139 section->put(commentKey, lastComment); 140 lastComment.clear(); 141 } 117 142 } 118 143 else 119 144 { … … 132 157 if (container.find(key) != container.not_found()) 133 158 BOOST_PROPERTY_TREE_THROW(ini_parser_error( 134 159 "duplicate key name", "", line_no)); 135 container.push_back(std::make_pair(key, Ptree(data))); 160 Ptree* section = &container.push_back(std::make_pair(key, Ptree(data)))->second; 161 if (lastComment.size() > 0) 162 { 163 if (section) 164 section->put(commentKey, lastComment); 165 lastComment.clear(); 166 } 136 167 } 137 168 } 138 169 } … … 193 224 } 194 225 } 195 226 227 template<class Ptree> 228 void write_comment(std::basic_ostream< 229 typename Ptree::key_type::value_type 230 > &stream, 231 const typename Ptree::key_type& comment, 232 const typename Ptree::key_type& commentStart) 233 { 234 if (comment.size() <= 0) 235 return; 236 typename Ptree::key_type line; 237 bool hadNonEmptyLine = false; 238 for (size_t i = 0; i < comment.size(); i++) 239 { 240 if (comment[i] == '\n') 241 { 242 if (line.size() > 0 || hadNonEmptyLine) 243 { 244 // dump comment line 245 stream << commentStart << line << '\n'; 246 } 247 else 248 { 249 // preceding empty lines are output without the commentStart 250 // dump comment line 251 stream << '\n'; 252 } 253 line.clear(); 254 hadNonEmptyLine = hadNonEmptyLine || (line.size() > 0); 255 } 256 else if (comment[i] != '\r') 257 { 258 // Ignore '\r' (for Windows!) 259 line += comment[i]; 260 } 261 } 262 if (line.size() > 0 || hadNonEmptyLine) 263 { 264 // dump comment line 265 stream << commentStart << line << '\n'; 266 } 267 else 268 { 269 // preceding empty lines are output without the commentStart 270 // dump comment line 271 stream << '\n'; 272 } 273 } 274 196 275 template <typename Ptree> 197 276 void write_keys(std::basic_ostream< 198 277 typename Ptree::key_type::value_type 199 278 > &stream, 200 279 const Ptree& pt, 201 bool throw_on_children) 280 bool throw_on_children, 281 const typename Ptree::key_type& commentKey, 282 const typename Ptree::key_type& commentStart) 202 283 { 203 284 typedef typename Ptree::key_type::value_type Ch; 204 285 for (typename Ptree::const_iterator it = pt.begin(), end = pt.end(); 205 286 it != end; ++it) 206 287 { 207 if (!it->second.empty()) { 208 if (throw_on_children) { 288 if (it->first != commentKey) 289 { 290 // We ignore the ".comment"-nodes, as these have special meaning! 291 292 // check for existence of comment node 293 boost::optional<typename Ptree::key_type> comment = it->second.template get_optional<typename Ptree::key_type>(commentKey); 294 295 if (!it->second.empty() && !(it->second.size() == 1 && comment)) 296 { 297 //only two depth-levels are allowd in INI-files ... but we also have to filter out the additional .comment nodes 298 if (throw_on_children) 299 { 209 300 BOOST_PROPERTY_TREE_THROW(ini_parser_error( 210 "ptree is too deep", "", 0));301 "ptree is too deep (only two depth steps alowed in INI files)", "", 0)); 211 302 } 212 303 continue; 213 304 } 305 if (comment) 306 { 307 // ... if it exists: output the comment 308 write_comment<Ptree>(stream, *comment, commentStart); 309 } 214 310 stream << it->first << Ch(' ') << Ch('=') << Ch(' ') 215 311 << it->second.template get_value< 216 312 std::basic_string<Ch> >() 217 313 << Ch('\n'); 218 314 } 219 stream << Ch('\n');315 } 220 316 } 221 317 222 318 template <typename Ptree> 223 319 void write_top_level_keys(std::basic_ostream< 224 320 typename Ptree::key_type::value_type 225 321 > &stream, 226 const Ptree& pt) 322 const Ptree& pt, 323 const typename Ptree::key_type& commentKey, 324 const typename Ptree::key_type& commentStart) 227 325 { 228 write_keys(stream, pt, false );326 write_keys(stream, pt, false, commentKey, commentStart); 229 327 } 230 328 231 329 template <typename Ptree> 232 330 void write_sections(std::basic_ostream< 233 331 typename Ptree::key_type::value_type 234 332 > &stream, 235 const Ptree& pt) 333 const Ptree& pt, 334 const typename Ptree::key_type& commentKey, 335 const typename Ptree::key_type& commentStart) 236 336 { 237 337 typedef typename Ptree::key_type::value_type Ch; 238 338 for (typename Ptree::const_iterator it = pt.begin(), end = pt.end(); … … 243 343 if (!it->second.data().empty()) 244 344 BOOST_PROPERTY_TREE_THROW(ini_parser_error( 245 345 "mixed data and children", "", 0)); 346 // empty lines in front of a new section to better separate it from other sections 347 stream << Ch('\n'); 348 // check for existence of comment node 349 boost::optional<typename Ptree::key_type> comment = pt.template get_optional<typename Ptree::key_type>(it->first + "." + commentKey); 350 if (comment) 351 { 352 std::string c = *comment; 353 // eat linebreak from start of comment to account for the two explicit \n inserted above! 354 while (c.size() > 0 && c[0] == '\n') 355 c = c.substr(1); 356 // ... if it exists: output the comment 357 if (c.size() > 0) 358 write_comment<Ptree>(stream, c, commentStart); 359 } 246 360 stream << Ch('[') << it->first << Ch(']') << Ch('\n'); 247 write_keys(stream, it->second, true );361 write_keys(stream, it->second, true, commentKey, commentStart); 248 362 } 249 363 } 250 364 } … … 275 389 BOOST_ASSERT(validate_flags(flags)); 276 390 (void)flags; 277 391 392 const typename Ptree::key_type commentKey = comment_key<typename Ptree::key_type>(); 393 const typename Ptree::key_type commentStart = "#"; 394 278 395 if (!pt.data().empty()) 279 396 BOOST_PROPERTY_TREE_THROW(ini_parser_error( 280 397 "ptree has data on root", "", 0)); 281 398 detail::check_dupes(pt); 282 399 283 detail::write_top_level_keys(stream, pt );284 detail::write_sections(stream, pt );400 detail::write_top_level_keys(stream, pt, commentKey, commentStart); 401 detail::write_sections(stream, pt, commentKey, commentStart); 285 402 } 286 403 287 404 /**