[4597] | 1 | /* |
---|
[2064] | 2 | orxonox - the future of 3D-vertical-scrollers |
---|
| 3 | |
---|
| 4 | Copyright (C) 2004 orx |
---|
| 5 | |
---|
| 6 | This program 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, or (at your option) |
---|
| 9 | any later version. |
---|
| 10 | |
---|
| 11 | ### File Specific: |
---|
[5014] | 12 | main-programmer: Benjamin Grauer |
---|
| 13 | co-programmer: Christian Meyer |
---|
| 14 | |
---|
| 15 | 2005-08-14: complete reimplementation: |
---|
| 16 | now the File is parsed at the initialisation, |
---|
| 17 | and informations is gathered there. |
---|
[9883] | 18 | 2006-10-10: Complete reimplementation again :) |
---|
| 19 | New STL-like style. The Parser has no state itself |
---|
| 20 | Elements as Nodes |
---|
[2064] | 21 | */ |
---|
| 22 | |
---|
| 23 | |
---|
| 24 | #include "ini_parser.h" |
---|
[4381] | 25 | |
---|
[9880] | 26 | #include <cassert> |
---|
| 27 | #include <algorithm> |
---|
| 28 | |
---|
[9881] | 29 | #define PARSELINELENGHT 1024 //!< how many chars to read at once |
---|
[5933] | 30 | |
---|
[2064] | 31 | |
---|
[9880] | 32 | /// /// /// /// /// /// |
---|
| 33 | /// INI-PARSER NODE /// |
---|
| 34 | /// /// /// /// /// /// |
---|
[9881] | 35 | /** |
---|
| 36 | * @brief Constructs a Node |
---|
| 37 | * @param name The name of the Node |
---|
| 38 | * @param comment The comment of the Node. |
---|
| 39 | */ |
---|
[9880] | 40 | IniParser::Node::Node(const std::string& name, const std::string& comment) |
---|
| 41 | { |
---|
| 42 | this->_name = name; |
---|
| 43 | this->_comment = comment; |
---|
| 44 | } |
---|
[9406] | 45 | |
---|
[9880] | 46 | /// /// /// /// /// //// |
---|
| 47 | /// INI-PARSER ENTRY /// |
---|
| 48 | /// /// /// /// /// //// |
---|
[9881] | 49 | /** |
---|
| 50 | * @brief Constructs a new Entry |
---|
| 51 | * @param name the Name of the Entry |
---|
| 52 | * @param value The name of the Value |
---|
| 53 | * @param comment The Comment used for the Entry |
---|
| 54 | */ |
---|
[9880] | 55 | IniParser::Entry::Entry(const std::string& name, const std::string& value, const std::string& comment) |
---|
| 56 | : IniParser::Node(name, comment), _value(value) |
---|
| 57 | {} |
---|
| 58 | |
---|
[9881] | 59 | /** |
---|
| 60 | * @brief Displays some nice debug info. |
---|
| 61 | */ |
---|
[9880] | 62 | void IniParser::Entry::debug() const |
---|
[2064] | 63 | { |
---|
[9880] | 64 | printf(" %s = %s\n", this->name().c_str(), this->_value.c_str()); |
---|
| 65 | } |
---|
[5933] | 66 | |
---|
[9880] | 67 | |
---|
| 68 | /// /// /// /// /// /// /// |
---|
| 69 | /// INI-PARSER SECTION /// |
---|
| 70 | /// /// /// /// /// /// /// |
---|
[9881] | 71 | /** |
---|
| 72 | * @brief constructs a new Section |
---|
| 73 | * @param sectionName The name of the Section |
---|
| 74 | * @param comment The Comment for this section |
---|
| 75 | */ |
---|
[9880] | 76 | IniParser::Section::Section(const std::string& sectionName, const std::string& comment) |
---|
| 77 | : IniParser::Node(sectionName, comment) |
---|
| 78 | {} |
---|
| 79 | |
---|
[9881] | 80 | /** |
---|
| 81 | * @brief Adds a new Entry to this Section |
---|
| 82 | * @param entryName The name of the Entry |
---|
| 83 | * @param value The Value of the Section |
---|
| 84 | * @param comment The Comment |
---|
| 85 | * @returns Reference to the Entry added. |
---|
| 86 | * @see IniParser::Entry::Entry |
---|
| 87 | */ |
---|
[9880] | 88 | IniParser::Entry& IniParser::Section::addEntry(const std::string& entryName, const std::string& value, const std::string& comment) |
---|
| 89 | { |
---|
| 90 | Entry::iterator entry = std::find(this->_entries.begin(), this->_entries.end(), entryName); |
---|
| 91 | if (entry == this->_entries.end()) |
---|
| 92 | { |
---|
| 93 | this->_entries.push_back(Entry(entryName, value, comment)); |
---|
| 94 | entry = --this->_entries.end(); |
---|
| 95 | } |
---|
| 96 | return *entry; |
---|
[2064] | 97 | } |
---|
| 98 | |
---|
[9881] | 99 | /** |
---|
| 100 | * @brief edits an Entry's Value |
---|
| 101 | * @param entryName The Entry to edit |
---|
| 102 | * @param value The Value to change |
---|
| 103 | * @param createMissing If the Entry is missing it is created if true. |
---|
| 104 | * @return true on success. |
---|
| 105 | */ |
---|
[9880] | 106 | bool IniParser::Section::editEntry(const std::string& entryName, const std::string& value, bool createMissing) |
---|
| 107 | { |
---|
| 108 | Entry::iterator entry = std::find(this->_entries.begin(), this->_entries.end(), entryName); |
---|
| 109 | if (entry == this->_entries.end()) |
---|
| 110 | { |
---|
| 111 | if (createMissing) |
---|
| 112 | { |
---|
| 113 | this->addEntry(entryName, value); |
---|
| 114 | return true; |
---|
| 115 | } |
---|
| 116 | else |
---|
| 117 | return false; |
---|
| 118 | } |
---|
| 119 | (*entry).setValue(value); |
---|
| 120 | return true; |
---|
| 121 | } |
---|
[5933] | 122 | |
---|
[9881] | 123 | /** |
---|
| 124 | * @param entryName The name of the entry to search for |
---|
| 125 | * @param defaultValue The returned value, if the entry is not found |
---|
| 126 | * @return The Value of the Entry, or defaultValue, if not found. |
---|
| 127 | */ |
---|
[9880] | 128 | const std::string& IniParser::Section::getValue(const std::string& entryName, const std::string& defaultValue) const |
---|
[2064] | 129 | { |
---|
[9880] | 130 | Entry::const_iterator entry = std::find(this->_entries.begin(), this->_entries.end(), entryName); |
---|
| 131 | if (entry != this->_entries.end()) |
---|
| 132 | return (*entry).value(); |
---|
| 133 | else |
---|
| 134 | return defaultValue; |
---|
[2064] | 135 | } |
---|
| 136 | |
---|
[9881] | 137 | /** |
---|
| 138 | * @brief sets a Comment to an Entry |
---|
| 139 | * @param entryName The Name of the Entry to set the comment to. |
---|
| 140 | * @param comment the Comment. |
---|
| 141 | * @return true on success (entry found and setup). |
---|
| 142 | */ |
---|
[9880] | 143 | bool IniParser::Section::setEntryComment(const std::string& entryName, const std::string& comment) |
---|
| 144 | { |
---|
| 145 | Entry::iterator entry = std::find(this->_entries.begin(), this->_entries.end(), entryName); |
---|
| 146 | if (entry != this->_entries.end()) |
---|
| 147 | { |
---|
| 148 | (*entry).setComment(comment); |
---|
| 149 | return true; |
---|
| 150 | } |
---|
| 151 | return false; |
---|
| 152 | } |
---|
[5933] | 153 | |
---|
[9881] | 154 | /** |
---|
| 155 | * @brief retrieves a Comment of an Entry |
---|
| 156 | * @param entryName The Entry to get the comment of. |
---|
| 157 | * @return The Comment, or "" if the Entry was not found. |
---|
| 158 | */ |
---|
[9880] | 159 | const std::string& IniParser::Section::getEntryComment(const std::string& entryName) const |
---|
| 160 | { |
---|
| 161 | Entry::const_iterator entry = std::find(this->_entries.begin(), this->_entries.end(), entryName); |
---|
| 162 | if (entry != this->_entries.end()) |
---|
| 163 | { |
---|
| 164 | return (*entry).comment(); |
---|
| 165 | } |
---|
| 166 | return IniParser::_emptyString; |
---|
| 167 | } |
---|
[7221] | 168 | |
---|
[9880] | 169 | |
---|
[9881] | 170 | /** |
---|
| 171 | * @brief retrieves a pointer to an Entry |
---|
| 172 | * @param entryName The Name of the Entry. |
---|
| 173 | * @return the located Entry or NULL! |
---|
| 174 | * @note beware of NULL! |
---|
| 175 | */ |
---|
[9880] | 176 | IniParser::Entry* IniParser::Section::getEntry(const std::string& entryName) |
---|
[2064] | 177 | { |
---|
[9880] | 178 | Entry::iterator entry = std::find(this->_entries.begin(), this->_entries.end(), entryName); |
---|
| 179 | if (entry != this->_entries.end()) |
---|
| 180 | return &(*entry); |
---|
| 181 | else |
---|
| 182 | return NULL; |
---|
| 183 | } |
---|
[5944] | 184 | |
---|
[9881] | 185 | /** |
---|
| 186 | * @brief retrieves an Iterator to an Entry called entryName within this section |
---|
| 187 | * @param entryName the name of the Entry |
---|
| 188 | * @return The iterator to the position, or end(); |
---|
| 189 | * @see Section::end(); |
---|
| 190 | */ |
---|
[9880] | 191 | IniParser::Entry::const_iterator IniParser::Section::getEntryIt(const std::string& entryName) const |
---|
| 192 | { |
---|
| 193 | return std::find(this->_entries.begin(), this->_entries.end(), entryName); |
---|
[2064] | 194 | } |
---|
| 195 | |
---|
[9881] | 196 | /** |
---|
| 197 | * @brief clears the Section's entries (flushes them) |
---|
| 198 | */ |
---|
[9880] | 199 | void IniParser::Section::clear() |
---|
| 200 | { |
---|
| 201 | this->_entries.clear(); |
---|
| 202 | } |
---|
[5933] | 203 | |
---|
[9881] | 204 | /** |
---|
| 205 | * @brief print out some debug info |
---|
| 206 | */ |
---|
[9880] | 207 | void IniParser::Section::debug() const |
---|
| 208 | { |
---|
| 209 | printf(" [%s]\n", this->name().c_str()); |
---|
| 210 | for(Entry::const_iterator entry = this->_entries.begin(); entry != this->_entries.end(); ++entry) |
---|
| 211 | (*entry).debug(); |
---|
| 212 | } |
---|
| 213 | |
---|
| 214 | |
---|
| 215 | |
---|
| 216 | /// /// /// /// /// /// /// |
---|
| 217 | /// INI-PARSER DOCUMENT /// |
---|
| 218 | /// /// /// /// /// /// /// |
---|
[9881] | 219 | /** |
---|
| 220 | * @brief Constructs a new Document |
---|
| 221 | * @param fileName The Name of the Document. |
---|
| 222 | * @param comment Some Comment |
---|
| 223 | */ |
---|
[9880] | 224 | IniParser::Document::Document(const std::string& fileName, const std::string& comment) |
---|
| 225 | : IniParser::Node(fileName, comment) |
---|
| 226 | {} |
---|
| 227 | |
---|
[9881] | 228 | /** |
---|
| 229 | * @brief Adds a new Section to the Document |
---|
| 230 | * @param sectionName The Name of the Section to add |
---|
| 231 | * @param comment A comment for the section. |
---|
| 232 | * @return A Reference to the newly added section. |
---|
| 233 | */ |
---|
[9880] | 234 | IniParser::Section& IniParser::Document::addSection(const std::string& sectionName, const std::string& comment) |
---|
| 235 | { |
---|
| 236 | Section::iterator section = std::find(this->_sections.begin(), this->_sections.end(), sectionName); |
---|
| 237 | if (section == this->_sections.end()) |
---|
| 238 | { |
---|
| 239 | this->_sections.push_back(Section(sectionName, comment)); |
---|
| 240 | return *(--_sections.end()); |
---|
| 241 | } |
---|
| 242 | else |
---|
| 243 | return *section; |
---|
| 244 | } |
---|
| 245 | |
---|
[9881] | 246 | /** |
---|
| 247 | * @brief removes a Section from the Document. |
---|
| 248 | * @param sectionName The section to remove |
---|
| 249 | * @return true on success (section was found). |
---|
| 250 | */ |
---|
[9880] | 251 | bool IniParser::Document::removeSection(const std::string& sectionName) |
---|
| 252 | { |
---|
| 253 | Section::iterator section = std::find(this->_sections.begin(), this->_sections.end(), sectionName); |
---|
| 254 | if (section != this->_sections.end()) |
---|
| 255 | { |
---|
| 256 | this->_sections.erase(section); |
---|
| 257 | return true; |
---|
| 258 | } |
---|
| 259 | else |
---|
| 260 | return false; |
---|
| 261 | } |
---|
| 262 | |
---|
[9881] | 263 | /** |
---|
| 264 | * @brief Sets a comment to a section |
---|
| 265 | * @param sectionName The name of the section |
---|
| 266 | * @param comment The Comment. |
---|
| 267 | * @return True on success (section was found). |
---|
| 268 | */ |
---|
[9883] | 269 | bool IniParser::Document::setSectionsComment(const std::string& sectionName, const std::string& comment) |
---|
[9880] | 270 | { |
---|
| 271 | Section::iterator section = std::find(this->_sections.begin(), this->_sections.end(), sectionName); |
---|
| 272 | if (section != this->_sections.end()) |
---|
| 273 | { |
---|
| 274 | (*section).setComment(comment); |
---|
| 275 | return true; |
---|
| 276 | } |
---|
| 277 | else |
---|
| 278 | return false; |
---|
| 279 | } |
---|
| 280 | |
---|
[9883] | 281 | /** |
---|
| 282 | * @brief Retrieves the comment for a specified section |
---|
| 283 | * @param sectionName The name of the section |
---|
| 284 | * @returns The Comment of the section. |
---|
| 285 | */ |
---|
| 286 | const std::string& IniParser::Document::getSectionsComment(const std::string& sectionName) const |
---|
| 287 | { |
---|
| 288 | Section::const_iterator section = std::find(this->_sections.begin(), this->_sections.end(), sectionName); |
---|
| 289 | if (section != this->_sections.end()) |
---|
| 290 | { |
---|
| 291 | return (*section).comment(); |
---|
| 292 | } |
---|
| 293 | else |
---|
| 294 | return IniParser::_emptyString; |
---|
| 295 | } |
---|
[9880] | 296 | |
---|
[9881] | 297 | /** |
---|
| 298 | * @brief Queries for a Section within the document returning a Pointer to it |
---|
| 299 | * @param sectionName The Section to search for. |
---|
| 300 | * @return A pointer to the section, of NULL if not found. |
---|
| 301 | * @brief beware of the NULL-pointer! |
---|
| 302 | */ |
---|
[9880] | 303 | IniParser::Section* IniParser::Document::getSection(const std::string& sectionName) |
---|
| 304 | { |
---|
| 305 | Section::iterator section = std::find(this->_sections.begin(), this->_sections.end(), sectionName); |
---|
| 306 | if (section != this->_sections.end()) |
---|
| 307 | { |
---|
| 308 | return &(*section); |
---|
| 309 | } |
---|
| 310 | else |
---|
| 311 | return NULL; |
---|
| 312 | } |
---|
| 313 | |
---|
[9881] | 314 | /** |
---|
| 315 | * @brief Queries for a Section within the document returning a Pointer to it |
---|
| 316 | * @param sectionName The Section to search for. |
---|
| 317 | * @return An iterator to the Section, or end() |
---|
| 318 | * @see Section::end(). |
---|
| 319 | */ |
---|
[9880] | 320 | IniParser::Section::const_iterator IniParser::Document::getSectionIt(const std::string& sectionName) const |
---|
| 321 | { |
---|
| 322 | Section::const_iterator section = std::find(this->_sections.begin(), this->_sections.end(), sectionName); |
---|
| 323 | return section; |
---|
| 324 | } |
---|
| 325 | |
---|
[9881] | 326 | /** |
---|
| 327 | * @brief adds a new Entry to a designated section. |
---|
| 328 | * @param sectionName The name of the Section |
---|
| 329 | * @param entryName The Name of the Entry to add |
---|
| 330 | * @param value The Value to set for the entry |
---|
| 331 | * @param comment optionally a comment. |
---|
| 332 | * @return true on success (always true) |
---|
| 333 | * |
---|
| 334 | * @note the section will also be created on the go, if it did not exists so far! |
---|
| 335 | */ |
---|
[9880] | 336 | bool IniParser::Document::addEntry(const std::string& sectionName, const std::string& entryName, const std::string& value, const std::string& comment) |
---|
| 337 | { |
---|
| 338 | // locating section |
---|
| 339 | Section::iterator section = std::find(this->_sections.begin(), this->_sections.end(), sectionName); |
---|
| 340 | if (section == this->_sections.end()) |
---|
| 341 | { |
---|
| 342 | // creating section if not found!! |
---|
| 343 | this->_sections.push_back(Section(sectionName)); |
---|
| 344 | section = --_sections.end(); |
---|
| 345 | } |
---|
| 346 | |
---|
| 347 | (*section).addEntry(entryName, value, comment); |
---|
| 348 | return true; |
---|
| 349 | } |
---|
| 350 | |
---|
[9881] | 351 | /** |
---|
| 352 | * @brief edits an Entry, and possibly creating it. |
---|
| 353 | * @param sectionName The Section's name to edit the entry in. |
---|
| 354 | * @param entryName The Name of the Entry to edit the value from |
---|
| 355 | * @param value The new value for the Entry. |
---|
| 356 | * @param createMissing if true, the Entry, (and the section) will be created. |
---|
| 357 | * @return true on success, false otherwise. |
---|
| 358 | */ |
---|
[9880] | 359 | bool IniParser::Document::editEntry(const std::string& sectionName, const std::string& entryName, const std::string& value, bool createMissing) |
---|
| 360 | { |
---|
| 361 | // locating section |
---|
| 362 | Section::iterator section = std::find(this->_sections.begin(), this->_sections.end(), sectionName); |
---|
| 363 | if (section == this->_sections.end()) |
---|
| 364 | { |
---|
| 365 | // creating section if not found!! |
---|
| 366 | if (createMissing) |
---|
| 367 | { |
---|
| 368 | this->_sections.push_back(Section(sectionName)); |
---|
| 369 | section = --_sections.end(); |
---|
| 370 | } |
---|
| 371 | else |
---|
| 372 | return false; |
---|
| 373 | } |
---|
| 374 | |
---|
| 375 | return (*section).editEntry(entryName, value, createMissing); |
---|
| 376 | } |
---|
| 377 | |
---|
[9881] | 378 | /** |
---|
| 379 | * @brief Retrieve a value from an Entry. |
---|
| 380 | * @param sectionName The Name of the Section the enrty is in |
---|
| 381 | * @param entryName The Name of the entry |
---|
| 382 | * @param defaultValue A default value, if the entry is not found |
---|
| 383 | * @return A string containing the value, or defaultValue, if the Section->Entry was not found. |
---|
| 384 | */ |
---|
[9880] | 385 | const std::string& IniParser::Document::getValue(const std::string& sectionName, const std::string& entryName, const std::string& defaultValue) const |
---|
| 386 | { |
---|
| 387 | // locating section |
---|
| 388 | Section::const_iterator section = std::find(this->_sections.begin(), this->_sections.end(), sectionName); |
---|
| 389 | if (section != this->_sections.end()) |
---|
| 390 | return (*section).getValue(entryName, defaultValue); |
---|
| 391 | return defaultValue; |
---|
| 392 | } |
---|
| 393 | |
---|
[9881] | 394 | /** |
---|
| 395 | * @brief Sets a Comment to an Entry. |
---|
| 396 | * @param sectionName The name of the Section. |
---|
| 397 | * @param entryName The name of the Entry. |
---|
| 398 | * @param comment The comment to set to this Entry |
---|
| 399 | * @return true on success (Section->Entry found). |
---|
| 400 | */ |
---|
[9880] | 401 | bool IniParser::Document::setEntryComment(const std::string& sectionName, const std::string& entryName, const std::string& comment) |
---|
| 402 | { |
---|
| 403 | // locating section |
---|
| 404 | Section::iterator section = std::find(this->_sections.begin(), this->_sections.end(), sectionName); |
---|
| 405 | if (section != this->_sections.end()) |
---|
| 406 | return (*section).setEntryComment(entryName, comment); |
---|
| 407 | else |
---|
| 408 | return false; |
---|
| 409 | } |
---|
| 410 | |
---|
[9881] | 411 | /** |
---|
| 412 | * @brief retrieved the comment of an Entry. |
---|
| 413 | * @param sectionName The section. |
---|
| 414 | * @param entryName The Entry to get the comment from |
---|
| 415 | * @return the Comment of the Entry. |
---|
| 416 | */ |
---|
[9880] | 417 | const std::string& IniParser::Document::getEntryComment(const std::string& sectionName, const std::string& entryName) const |
---|
| 418 | { |
---|
| 419 | Section::const_iterator section = std::find(this->_sections.begin(), this->_sections.end(), sectionName); |
---|
| 420 | if (section != this->_sections.end()) |
---|
| 421 | return (*section).getEntryComment(entryName); |
---|
| 422 | else |
---|
| 423 | return IniParser::_emptyString; |
---|
| 424 | } |
---|
| 425 | |
---|
[9881] | 426 | /** |
---|
| 427 | * @brief clears all sections. |
---|
| 428 | */ |
---|
[9880] | 429 | void IniParser::Document::clear() |
---|
| 430 | { |
---|
| 431 | this->_sections.clear(); |
---|
| 432 | } |
---|
| 433 | |
---|
[9881] | 434 | /** |
---|
| 435 | * @brief Print some nice debug output. |
---|
| 436 | */ |
---|
[9880] | 437 | void IniParser::Document::debug() const |
---|
| 438 | { |
---|
| 439 | for(Section::const_iterator section = this->_sections.begin(); section != this->_sections.end(); ++section) |
---|
| 440 | (*section).debug(); |
---|
| 441 | } |
---|
| 442 | |
---|
| 443 | |
---|
| 444 | |
---|
| 445 | |
---|
| 446 | /// /// /// /// /// /// // |
---|
| 447 | /// INI-PARSER ITSELF //// |
---|
| 448 | /// /// /// /// /// /// // |
---|
| 449 | const std::string IniParser::_emptyString = ""; |
---|
[2141] | 450 | /** |
---|
[9880] | 451 | * @brief constructs an IniParser using a file |
---|
| 452 | * @param fileName: the path and name of the file to parse |
---|
[5934] | 453 | */ |
---|
[9880] | 454 | IniParser::IniParser (const std::string& fileName) |
---|
| 455 | : _document(fileName) |
---|
[5934] | 456 | { |
---|
[9880] | 457 | this->_fileName = fileName; |
---|
| 458 | if (!fileName.empty()) |
---|
| 459 | this->readFile(fileName); |
---|
[5934] | 460 | } |
---|
| 461 | |
---|
| 462 | |
---|
| 463 | /** |
---|
[9880] | 464 | * @brief removes the IniParser from memory |
---|
| 465 | */ |
---|
| 466 | IniParser::~IniParser () |
---|
| 467 | {} |
---|
| 468 | |
---|
| 469 | /** |
---|
[5944] | 470 | * @brief opens a file to parse |
---|
[5017] | 471 | * @param fileName: path and name of the new file to parse |
---|
[9880] | 472 | * @param keepSettings if the Settings (if already some are set) should be kept (false by default) |
---|
[5014] | 473 | * @return true on success false otherwise; |
---|
[5934] | 474 | * |
---|
| 475 | * If there was already an opened file, the file will be closed, |
---|
| 476 | * and the new one will be opened. |
---|
[5933] | 477 | */ |
---|
[9880] | 478 | bool IniParser::readFile(const std::string& fileName, bool keepSettings) |
---|
[2064] | 479 | { |
---|
[5934] | 480 | FILE* stream; //< The stream we use to read the file. |
---|
[9880] | 481 | int lineCount = 0; //< The Count of lines read. |
---|
| 482 | std::list<std::string> commentList; //< A list of Comments. |
---|
| 483 | Section* currentSection = NULL; |
---|
[5934] | 484 | |
---|
[9880] | 485 | if (!keepSettings) |
---|
| 486 | this->_document.clear(); |
---|
[7221] | 487 | |
---|
| 488 | if( (stream = fopen (fileName.c_str(), "r")) == NULL) |
---|
[5014] | 489 | { |
---|
[9881] | 490 | printf("ERROR:: IniParser could not open %s for reading\n", fileName.c_str()); |
---|
[5014] | 491 | return false; |
---|
| 492 | } |
---|
| 493 | else |
---|
| 494 | { |
---|
[9880] | 495 | this->_fileName = fileName; |
---|
[5014] | 496 | |
---|
| 497 | ///////////////////////////// |
---|
| 498 | // READING IN THE INI-FILE // |
---|
| 499 | ///////////////////////////// |
---|
[7221] | 500 | char lineBuffer[PARSELINELENGHT+1]; |
---|
| 501 | char buffer[PARSELINELENGHT+1]; |
---|
[5021] | 502 | const char* lineBegin; |
---|
[5014] | 503 | char* ptr; |
---|
| 504 | |
---|
[5319] | 505 | while( fgets (lineBuffer, PARSELINELENGHT, stream)) |
---|
[2551] | 506 | { |
---|
[5021] | 507 | lineBegin = lineBuffer; |
---|
[5014] | 508 | // remove newline char, and \0-terminate |
---|
| 509 | if( (ptr = strchr( lineBuffer, '\n')) != NULL) |
---|
| 510 | *ptr = 0; |
---|
[7221] | 511 | else |
---|
| 512 | lineBuffer[PARSELINELENGHT] = 0; |
---|
[5021] | 513 | // cut up to the beginning of the line. |
---|
| 514 | while((*lineBegin == ' ' || *lineBegin == '\t') && lineBegin < lineBuffer + strlen(lineBuffer)) |
---|
| 515 | ++lineBegin; |
---|
[5946] | 516 | |
---|
[7221] | 517 | if ( !strcmp( lineBegin, "" ) ) |
---|
| 518 | continue; |
---|
| 519 | |
---|
[5946] | 520 | // check if we have a FileComment |
---|
| 521 | if ( (*lineBegin == '#' || *lineBegin == ';')) |
---|
| 522 | { |
---|
[9406] | 523 | std::string newCommenLine = lineBegin; |
---|
[9880] | 524 | commentList.push_back(newCommenLine); |
---|
[5946] | 525 | continue; |
---|
| 526 | } |
---|
[9880] | 527 | if (lineCount == 0 && !commentList.empty()) |
---|
[5946] | 528 | { |
---|
[9880] | 529 | this->setNodeComment(&this->_document, &commentList); |
---|
[5946] | 530 | lineCount++; |
---|
| 531 | } |
---|
| 532 | |
---|
[2551] | 533 | // check for section identifyer |
---|
[5021] | 534 | else if( sscanf (lineBegin, "[%s", buffer) == 1) |
---|
[5014] | 535 | { |
---|
| 536 | if( (ptr = strchr( buffer, ']')) != NULL) |
---|
[4597] | 537 | { |
---|
[5014] | 538 | *ptr = 0; |
---|
[9880] | 539 | Section& node = this->_document.addSection(buffer); |
---|
| 540 | setNodeComment(&node, &commentList); |
---|
| 541 | currentSection = &node; |
---|
[4597] | 542 | } |
---|
[5014] | 543 | } |
---|
[5018] | 544 | // check for Entry identifier (Entry = Value) |
---|
[5021] | 545 | else if( (ptr = strchr( lineBegin, '=')) != NULL) |
---|
[5014] | 546 | { |
---|
[9880] | 547 | if (currentSection == NULL) |
---|
[5014] | 548 | { |
---|
[9881] | 549 | printf("WARNING:: Not in a Section yet for %s\n", lineBegin); |
---|
[5946] | 550 | lineCount++; |
---|
[5014] | 551 | continue; |
---|
| 552 | } |
---|
[7221] | 553 | if( ptr == lineBegin) |
---|
| 554 | { |
---|
[5946] | 555 | lineCount++; |
---|
[5014] | 556 | continue; |
---|
[5946] | 557 | } |
---|
[5014] | 558 | char* valueBegin = ptr+1; |
---|
[5021] | 559 | while ((*valueBegin == ' ' || *valueBegin == '\t') && valueBegin <= lineBegin + strlen(lineBegin)) |
---|
[5014] | 560 | ++valueBegin; |
---|
[5022] | 561 | char* valueEnd = valueBegin + strlen(valueBegin)-1; |
---|
| 562 | while ((*valueEnd == ' ' || *valueEnd == '\t') && valueEnd >= valueBegin) |
---|
| 563 | --valueEnd; |
---|
| 564 | valueEnd[1] = '\0'; |
---|
[5018] | 565 | char* nameEnd = ptr-1; |
---|
[5021] | 566 | while ((*nameEnd == ' ' || *nameEnd == '\t' ) && nameEnd >= lineBegin) |
---|
[5014] | 567 | --nameEnd; |
---|
| 568 | nameEnd[1] = '\0'; |
---|
[5018] | 569 | |
---|
[9880] | 570 | Entry& node = currentSection->addEntry(lineBegin, valueBegin); |
---|
| 571 | this->setNodeComment(&node, &commentList); |
---|
[5945] | 572 | |
---|
| 573 | lineCount++; |
---|
[5014] | 574 | } |
---|
[2551] | 575 | } |
---|
[5014] | 576 | } |
---|
| 577 | fclose(stream); |
---|
| 578 | return true; |
---|
[2064] | 579 | } |
---|
| 580 | |
---|
[5933] | 581 | |
---|
[2141] | 582 | /** |
---|
[9881] | 583 | * @brief opens a file and writes to it. |
---|
| 584 | * @param fileName: path and name of the new file to write to. If empty the internal value is used. |
---|
[5020] | 585 | * @return true on success false otherwise |
---|
| 586 | */ |
---|
[7221] | 587 | bool IniParser::writeFile(const std::string& fileName) const |
---|
[5020] | 588 | { |
---|
[9881] | 589 | std::string parseFile; |
---|
[5020] | 590 | FILE* stream; //!< The stream we use to read the file. |
---|
[7221] | 591 | if( fileName.empty()) |
---|
[9881] | 592 | parseFile = _fileName; |
---|
| 593 | else |
---|
| 594 | parseFile = fileName; |
---|
[5020] | 595 | |
---|
[9881] | 596 | if( (stream = fopen (parseFile.c_str(), "w")) == NULL) |
---|
[5020] | 597 | { |
---|
[9881] | 598 | printf("ERROR:: IniParser could not open %s for writing\n", parseFile.c_str()); |
---|
[5020] | 599 | return false; |
---|
| 600 | } |
---|
| 601 | else |
---|
| 602 | { |
---|
[9880] | 603 | if (!this->_document.comment().empty()) |
---|
| 604 | fprintf(stream, "%s\n\n", this->_document.comment().c_str()); |
---|
[5949] | 605 | |
---|
[9880] | 606 | Section::const_iterator section; |
---|
| 607 | for (section = this->_document.sections().begin(); section != this->_document.sections().end(); ++section) |
---|
[7221] | 608 | { |
---|
[9880] | 609 | if (!(*section).comment().empty()) |
---|
| 610 | fprintf(stream, "%s", (*section).comment().c_str()); |
---|
| 611 | fprintf(stream, "\n [%s]\n", (*section).name().c_str()); |
---|
[7221] | 612 | |
---|
[9880] | 613 | Entry::const_iterator entry; |
---|
| 614 | for (entry = (*section).entries().begin(); entry != (*section).entries().end(); ++entry) |
---|
[5020] | 615 | { |
---|
[9880] | 616 | if (!(*entry).comment().empty()) |
---|
| 617 | fprintf(stream, "%s", (*entry).comment().c_str()); |
---|
| 618 | fprintf(stream, " %s = %s\n", (*entry).name().c_str(), (*entry).value().c_str()); |
---|
[5020] | 619 | } |
---|
[7221] | 620 | } |
---|
[5020] | 621 | } |
---|
| 622 | fclose(stream); |
---|
[9406] | 623 | return true; |
---|
[5020] | 624 | } |
---|
| 625 | |
---|
[5945] | 626 | |
---|
[5021] | 627 | /** |
---|
[9880] | 628 | * @brief output the whole tree in a nice and easy way. |
---|
[5945] | 629 | */ |
---|
[9880] | 630 | void IniParser::debug() const |
---|
[5945] | 631 | { |
---|
[9881] | 632 | printf("Iniparser '%s' - debug\n", this->_fileName.c_str()); |
---|
[9880] | 633 | if (!this->_document.comment().empty()) |
---|
[9881] | 634 | printf("FileComment:\n '%s'\n\n", this->_document.comment().c_str()); |
---|
[5945] | 635 | |
---|
[9880] | 636 | if (!this->_document.sections().empty()) |
---|
| 637 | this->_document.debug(); |
---|
[5945] | 638 | else |
---|
[9881] | 639 | printf("no Sections Defined in this ini-file (%s).\n", _fileName.c_str()); |
---|
[5945] | 640 | } |
---|
| 641 | |
---|
| 642 | |
---|
| 643 | /** |
---|
[9881] | 644 | * @brief takes lines together to form one NodeComment, ereasing the commentList |
---|
| 645 | * @param node the Node to apply the Comment to. |
---|
| 646 | * @param comments the CommentList to append. |
---|
[5935] | 647 | */ |
---|
[9880] | 648 | void IniParser::setNodeComment(Node* node, std::list<std::string>* comments) |
---|
[5935] | 649 | { |
---|
[9880] | 650 | assert(node != NULL); |
---|
| 651 | assert(comments != NULL); |
---|
[5935] | 652 | |
---|
[9880] | 653 | std::string comment; |
---|
| 654 | if (comments->empty()) |
---|
[7221] | 655 | { |
---|
[9880] | 656 | comment = ""; |
---|
[5946] | 657 | } |
---|
[9880] | 658 | else |
---|
[5946] | 659 | { |
---|
[9880] | 660 | while (!comments->empty()) |
---|
[5014] | 661 | { |
---|
[9880] | 662 | if (!comment.empty()) |
---|
| 663 | comment += "\n"; |
---|
| 664 | comment += comments->front(); |
---|
| 665 | comments->pop_front(); |
---|
[5014] | 666 | } |
---|
| 667 | } |
---|
[9880] | 668 | node->setComment(comment); |
---|
[5014] | 669 | } |
---|
[5938] | 670 | |
---|
[9880] | 671 | |
---|