00001 00002 // 00003 // Copyright (C) 2000 00004 // Ralf Westram 00005 // (Coded@ReallySoft.de) 00006 // 00007 // Permission to use, copy, modify, distribute and sell this software 00008 // and its documentation for any purpose is hereby granted without fee, 00009 // provided that the above copyright notice appear in all copies and 00010 // that both that copyright notice and this permission notice appear 00011 // in supporting documentation. Ralf Westram makes no 00012 // representations about the suitability of this software for any 00013 // purpose. It is provided "as is" without express or implied warranty. 00014 // 00015 // This code is part of my library. 00016 // You may find a more recent version at http://www.reallysoft.de/ 00017 // 00019 00020 #ifndef INIFILE_H 00021 #define INIFILE_H 00022 00023 #ifndef __MAP__ 00024 #include <map> 00025 #endif 00026 00027 #ifndef ERR_H 00028 #include "Err.h" 00029 #endif 00030 #ifndef TOOLS_H 00031 #include "Tools.h" 00032 #endif 00033 #ifndef SMARTPTR_H 00034 #include <smartptr.h> 00035 #endif 00036 00037 namespace rs { 00038 00040 namespace ini { 00041 00042 // ---------------------- 00043 // class Comment 00044 // ---------------------- 00045 00046 const char comment_char = ';'; 00047 00053 enum ChangesState { 00054 NO_CHANGES, 00055 MINOR_CHANGES, 00056 MAJOR_CHANGES 00057 }; 00058 00059 extern bool need_check_for_changes; 00060 00062 class Comment { 00063 private: 00064 std::string text; 00065 Comment *next; 00066 00067 void split_multiline(); 00068 00069 public: 00071 Comment(const std::string& text_) : text(text_), next(0) { split_multiline(); } 00072 virtual ~Comment() { delete next; } 00073 00075 void append(Comment *comment); 00076 00078 void append(const std::string& text_) { append(new Comment(text_)); } 00079 00081 void dump(std::ostream& out) const; 00082 }; 00083 00084 // -------------------------- 00085 // class Commentable 00086 // -------------------------- 00087 00089 class Commentable { 00090 private: 00091 Comment *comment; 00092 00093 public: 00094 Commentable() : comment(0) {} 00095 virtual ~Commentable() { delete comment; } 00096 00097 void append(Comment *cmt) { 00098 if (comment) comment->append(cmt); 00099 else comment = cmt; 00100 } 00101 00105 void append(const std::string& text) { append(new Comment(text)); } 00106 00108 void dump(std::ostream& out) const { 00109 if (comment) { 00110 out << '\n'; 00111 comment->dump(out); 00112 } 00113 } 00114 00118 bool comment_exists() const { return comment != 0; } 00119 }; 00120 00121 #define UNDEFINED_FILEPOSITION (-1UL) 00122 00123 // ---------------------------- 00124 // class FilePosition 00125 // ---------------------------- 00127 class FilePosition { 00128 private: 00129 unsigned long lineNumber; 00130 00131 public: 00133 // FilePosition() : lineNumber(UNDEFINED_FILEPOSITION) {} 00134 00138 FilePosition(unsigned long lineNumber_) : lineNumber(lineNumber_) {} 00139 virtual ~FilePosition() {} 00140 00142 bool is_defined() const { return lineNumber != UNDEFINED_FILEPOSITION; } 00143 00145 unsigned long LineNumber() const { assert(is_defined()); return lineNumber; } 00146 00147 void throw_Error(const std::string& filename, const std::string& message) const; 00148 }; 00149 00150 00151 // -------------------------------------------------------------------------------- 00152 // class Entry 00153 // -------------------------------------------------------------------------------- 00154 00155 class Section; 00156 00158 class Entry : public Commentable, public FilePosition { 00159 private: 00160 std::string name; 00161 std::string content; 00162 bool changed; 00163 Section *my_section; 00164 00166 void set_changed() { changed = true; } 00167 00168 friend class Section; 00169 00170 public: 00171 00177 Entry(const std::string& name_, const std::string& content_, unsigned long line_number = UNDEFINED_FILEPOSITION) 00178 : FilePosition(line_number), name(name_), content(content_), changed(false), my_section(0) 00179 {} 00180 virtual ~Entry() {} 00181 00185 const Section *mySection() const { return my_section; } 00186 00190 bool changesMade() const { return changed; } 00191 00195 const std::string& getName() const { return name; } 00196 00198 const std::string& getContent() const { return content; } 00199 00201 void setContent(const std::string& content_) { 00202 if (content_ != content) { 00203 content = content_; 00204 set_changed(); 00205 } 00206 } 00207 00211 double getNumericContent() const; 00212 00216 long getIntegerContent() const; 00217 00218 00222 void setNumericContent(double content_) { 00223 setContent(rs::str::strf("%f", content_)); 00224 } 00225 00227 void mark_obsolete() { name = std::string("obsoleteEntry_")+name; set_changed(); } 00228 00230 bool operator<(const Entry& other) const { return str::stricmp(name, other.name) < 0; } 00231 00233 void dump(std::ostream& out) const { 00234 Commentable::dump(out); 00235 out << getName() << '=' << getContent() << "\n"; 00236 } 00237 // virtual void dump(ostream& out) const = 0; 00238 00240 DECLARE_STREAM_OP(Entry); 00242 00244 void throw_Error(const std::string& message) const; 00245 }; 00246 00248 typedef SmartPtr<Entry> EntryPtr; 00249 00250 // -------------------------------------------------------------------------------- 00251 // class Section 00252 // -------------------------------------------------------------------------------- 00253 00255 struct ltistr { 00256 bool operator()(const std::string& s1, const std::string& s2) const { 00257 return s1<s2; 00258 } 00259 }; 00260 00262 typedef std::map<std::string, EntryPtr, ltistr > Entries; 00263 00264 class Inifile; 00265 00267 class Section : public Commentable, public FilePosition { 00268 private: 00269 std::string name; 00270 Entries entries; 00271 mutable ChangesState changes_made; 00272 Inifile *my_inifile; 00273 00278 void set_changes_made(ChangesState mode) { 00279 if (mode>changes_made) { 00280 changes_made = mode; 00281 need_check_for_changes = true; 00282 } 00283 } 00284 00285 friend class Inifile; 00286 00287 EntryPtr expectEntry(const std::string& name_) const; 00288 00289 public: 00291 Section(const std::string& name_, unsigned long line_number) : FilePosition(line_number), name(name_), changes_made(NO_CHANGES), my_inifile(0) {} 00292 virtual ~Section() {} 00293 00297 const Inifile *myInifile() const { return my_inifile; } 00298 00300 const std::string& getName() const { return name; } 00301 00306 void insertEntry(EntryPtr entry, ChangesState mode=MINOR_CHANGES) { 00307 assert(entry->my_section == 0); 00308 entry->my_section = this; 00309 entry->set_changed(); 00310 00311 entries[entry->getName()] = entry; 00312 set_changes_made(mode); 00313 } 00314 00319 const EntryPtr findEntry(const std::string& name_) const { 00320 return const_cast<Section&>(*this).findEntry(name_); 00321 } 00323 EntryPtr findEntry(const std::string& name_) { 00324 Entries::iterator e = entries.find(name_); 00325 if (e==entries.end()) return EntryPtr(); 00326 return e->second; 00327 } 00328 00336 EntryPtr findOrCreateEntry(const std::string& name_, const std::string& content, ChangesState mode=MINOR_CHANGES, const char *add_comment=0); 00337 00339 EntryPtr findOrCreateEntry(const std::string& name_, long default_value, ChangesState mode=MINOR_CHANGES, const char *add_comment=0); 00340 00350 EntryPtr findOrCreateEntry(const std::string& name_, std::string (*get_content)(), ChangesState mode = MINOR_CHANGES, const char *add_comment=0); 00351 00357 const std::string& findStringEntry(const std::string& name_) const; 00358 00364 double findNumericEntry(const std::string& name_) const; 00365 00371 long findIntegerEntry(const std::string& name_) const; 00372 00374 Entries::const_iterator begin() const { return entries.begin(); } 00376 Entries::const_iterator end() const { return entries.end(); } 00377 00379 void clearEntries() { entries.clear(); } 00380 00382 void dump(std::ostream& out) const { 00383 Commentable::dump(out); 00384 out << '[' << name << ']' << "\n"; 00385 for (Entries::const_iterator e=entries.begin(); e!=entries.end(); ++e) { 00386 out << *(e->second); 00387 } 00388 out << "\n"; 00389 } 00391 DECLARE_STREAM_OP(Section); 00393 00397 ChangesState changesMade() const; 00398 00400 void fixState() { changes_made = NO_CHANGES; } 00401 00403 void throw_Error(const std::string& message) const; 00404 }; 00405 00407 typedef SmartPtr<Section> SectionPtr; 00408 00410 typedef std::map<std::string, SectionPtr, ltistr > Sections; 00411 00412 // ----------------------- 00413 // class Inifile 00414 // ----------------------- 00415 00417 class Inifile 00418 { 00419 private: 00421 Sections sections; 00422 00424 mutable ChangesState changes_made; 00425 00426 std::string loaded_from_file; 00427 00432 void set_changes_made(ChangesState mode) { if (mode>changes_made) changes_made = mode; } 00433 00434 public: 00439 Inifile(const std::string& loaded_from_file_) : changes_made(NO_CHANGES), loaded_from_file(loaded_from_file_) {} 00440 virtual ~Inifile() {} 00441 00443 Sections::const_iterator begin() const { return sections.begin(); } 00444 00446 Sections::const_iterator end() const { return sections.end(); } 00447 00449 const std::string& loadedFrom() const { return loaded_from_file; } 00450 00455 void insertSection(SectionPtr section, ChangesState mode=MINOR_CHANGES) { 00456 assert(section->my_inifile == 0); 00457 section->my_inifile = this; 00458 section->set_changes_made(mode); 00459 00460 sections[section->getName()] = section; 00461 set_changes_made(mode); 00462 } 00463 00468 const SectionPtr findSection(const std::string& name_) const { 00469 return const_cast<Inifile&>(*this).findSection(name_); 00470 } 00472 SectionPtr findSection(const std::string& name_); 00473 00478 SectionPtr expectSection(const std::string& name_) const; 00479 00488 SectionPtr findOrCreateSection(const std::string& name_, ChangesState mode=MINOR_CHANGES); 00489 00498 const EntryPtr findEntry(const std::string& section, const std::string& entry) const; 00499 00501 EntryPtr findEntry(const std::string& section, const std::string& entry) { 00502 return const_cast<const Inifile*>(this)->findEntry(section, entry); 00503 } 00504 00513 const std::string& findStringEntry(const std::string& section, const std::string& entry) const; 00514 00523 double findNumericEntry(const std::string& section, const std::string& entry) const; 00524 00533 long findIntegerEntry(const std::string& section, const std::string& entry) const; 00534 00536 void dump(std::ostream& out) const { 00537 for (Sections::const_iterator s = sections.begin(); s!=sections.end(); ++s) { 00538 out << *(s->second); 00539 } 00540 } 00542 DECLARE_STREAM_OP(Inifile); 00544 00549 ChangesState changesMade() const; 00550 00554 void fixState(); 00555 }; 00556 00558 typedef SmartPtr<Inifile> InifilePtr; 00559 00565 InifilePtr readInifile(const std::string& filename); 00566 00574 void writeInifile(const std::string& filename, InifilePtr ini); 00575 00577 typedef void (*InifileCompleter)(InifilePtr); 00578 00590 InifilePtr readOrCreateInifile(const std::string& inifilename, InifileCompleter complete_ini); 00591 00592 }; 00593 }; 00594 00595 #else 00596 #error inifile.h included twice 00597 #endif // INIFILE_H
Contact me in case of errors or questions. This documentation is powered by ![]() |
(C) 2000-2002 ![]() |