Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

inifile.h

Go to the documentation of this file.
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 Doxygen.
(C) 2000-2002 Doxygen