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