00001 // 00002 // CDataFile Class Implementation 00003 // 00004 // The purpose of this class is to provide a simple, full featured means to 00005 // store persistent data to a text file. It uses a simple key/value paradigm 00006 // to achieve this. The class can read/write to standard Windows .ini files, 00007 // and yet does not rely on any windows specific calls. It should work as 00008 // well in a linux environment (with some minor adjustments) as it does in 00009 // a Windows one. 00010 // 00011 // Written July, 2002 by Gary McNickle <gary#sunstorm.net> 00012 // If you use this class in your application, credit would be appreciated. 00013 // 00014 00015 #ifndef __CDATAFILE_H__ 00016 #define __CDATAFILE_H__ 00017 00018 #include <vector> 00019 #include <string> 00020 #include <fstream> 00021 00022 // Globally defined structures, defines, & types 00024 00025 // AUTOCREATE_SECTIONS 00026 // When set, this define will cause SetValue() to create a new section, if 00027 // the requested section does not allready exist. 00028 #define AUTOCREATE_SECTIONS (1L<<1) 00029 00030 // AUOTCREATE_KEYS 00031 // When set, this define causes SetValue() to create a new key, if the 00032 // requested key does not allready exist. 00033 #define AUTOCREATE_KEYS (1L<<2) 00034 00035 // MAX_BUFFER_LEN 00036 // Used simply as a max size of some internal buffers. Determines the maximum 00037 // length of a line that will be read from or written to the file or the 00038 // report output. 00039 #define MAX_BUFFER_LEN 512 00040 00041 // eDebugLevel 00042 // Used by our Report function to classify levels of reporting and severity 00043 // of report. 00044 enum e_DebugLevel 00045 { 00046 // detailed programmatic informational messages used as an aid in 00047 // troubleshooting problems by programmers 00048 E_DEBUG = 0, 00049 // brief informative messages to use as an aid in troubleshooting 00050 // problems by production support and programmers 00051 E_INFO, 00052 // messages intended to notify help desk, production support and 00053 // programmers of possible issues with respect to the running application 00054 E_WARN, 00055 // messages that detail a programmatic error, these are typically 00056 // messages intended for help desk, production support, programmers and 00057 // occasionally users 00058 E_ERROR, 00059 // severe messages that are programmatic violations that will usually 00060 // result in application failure. These messages are intended for help 00061 // desk, production support, programmers and possibly users 00062 E_FATAL, 00063 // notice that all processing should be stopped immediately after the 00064 // log is written. 00065 E_CRITICAL 00066 }; 00067 00068 00069 typedef std::string t_Str; 00070 00071 // CommentIndicators 00072 // This constant contains the characters that we check for to determine if a 00073 // line is a comment or not. Note that the first character in this constant is 00074 // the one used when writing comments to disk (if the comment does not allready 00075 // contain an indicator) 00076 const t_Str CommentIndicators = t_Str("#;"); 00077 00078 // EqualIndicators 00079 // This constant contains the characters that we check against to determine if 00080 // a line contains an assignment ( key = value ) 00081 // Note that changing these from their defaults ("=:") WILL affect the 00082 // ability of CDataFile to read/write to .ini files. Also, note that the 00083 // first character in this constant is the one that is used when writing the 00084 // values to the file. (EqualIndicators[0]) 00085 const t_Str EqualIndicators = t_Str("=:"); 00086 00087 // WhiteSpace 00088 // This constant contains the characters that the Trim() function removes from 00089 // the head and tail of strings. 00090 const t_Str WhiteSpace = t_Str(" \t\n\r"); 00091 00092 // st_key 00093 // This structure stores the definition of a key. A key is a named identifier 00094 // that is associated with a value. It may or may not have a comment. All comments 00095 // must PRECEDE the key on the line in the config file. 00096 typedef struct st_key 00097 { 00098 t_Str szKey; 00099 t_Str szValue; 00100 t_Str szComment; 00101 00102 st_key() 00103 { 00104 szKey = t_Str(""); 00105 szValue = t_Str(""); 00106 szComment = t_Str(""); 00107 } 00108 00109 } t_Key; 00110 00111 typedef std::vector<t_Key> KeyList; 00112 typedef KeyList::iterator KeyItor; 00113 00114 // st_section 00115 // This structure stores the definition of a section. A section contains any number 00116 // of keys (see st_keys), and may or may not have a comment. Like keys, all 00117 // comments must precede the section. 00118 typedef struct st_section 00119 { 00120 t_Str szName; 00121 t_Str szComment; 00122 KeyList Keys; 00123 00124 st_section() 00125 { 00126 szName = t_Str(""); 00127 szComment = t_Str(""); 00128 Keys.clear(); 00129 } 00130 00131 } t_Section; 00132 00133 typedef std::vector<t_Section> SectionList; 00134 typedef SectionList::iterator SectionItor; 00135 00136 00137 00140 void Report(e_DebugLevel DebugLevel, const char *fmt, ...); 00141 t_Str GetNextWord(t_Str& CommandLine); 00142 int CompareNoCase(const t_Str& str1, const t_Str& str2); 00143 void Trim(t_Str& szStr); 00144 int WriteLn(std::fstream& stream, const char* fmt, ...); 00145 00146 00149 00150 00151 // CDataFile 00152 class CDataFile 00153 { 00154 // Methods 00155 public: 00156 // Constructors & Destructors 00158 CDataFile(); 00159 CDataFile(const t_Str& szFileName); 00160 virtual ~CDataFile(); 00161 00162 // File handling methods 00164 bool Load(const t_Str& szFileName); 00165 bool Save(); 00166 00167 // Data handling methods 00169 00170 // GetValue: Our default access method. Returns the raw t_Str value 00171 // Note that this returns keys specific to the given section only. 00172 t_Str GetValue(const t_Str& szKey, const t_Str& szSection = t_Str("")); 00173 // GetString: Returns the value as a t_Str 00174 t_Str GetString(const t_Str& szKey, const t_Str& szSection = t_Str("")); 00175 // GetFloat: Return the value as a float 00176 float GetFloat(const t_Str& szKey, const t_Str& szSection = t_Str("")); 00177 // GetInt: Return the value as an int 00178 int GetInt(const t_Str& szKey, const t_Str& szSection = t_Str("")); 00179 // GetBool: Return the value as a bool 00180 bool GetBool(const t_Str& szKey, const t_Str& szSection = t_Str("")); 00181 00182 // SetValue: Sets the value of a given key. Will create the 00183 // key if it is not found and AUTOCREATE_KEYS is active. 00184 bool SetValue(const t_Str& szKey, const t_Str& szValue, 00185 const t_Str& szComment = t_Str(""), const t_Str& szSection = t_Str("")); 00186 00187 // SetFloat: Sets the value of a given key. Will create the 00188 // key if it is not found and AUTOCREATE_KEYS is active. 00189 bool SetFloat(const t_Str& szKey, float fValue, 00190 const t_Str& szComment = t_Str(""), const t_Str& szSection = t_Str("")); 00191 00192 // SetInt: Sets the value of a given key. Will create the 00193 // key if it is not found and AUTOCREATE_KEYS is active. 00194 bool SetInt(const t_Str& szKey, int nValue, 00195 const t_Str& szComment = t_Str(""), const t_Str& szSection = t_Str("")); 00196 00197 // SetBool: Sets the value of a given key. Will create the 00198 // key if it is not found and AUTOCREATE_KEYS is active. 00199 bool SetBool(const t_Str& szKey, bool bValue, 00200 const t_Str& szComment = t_Str(""), const t_Str& szSection = t_Str("")); 00201 00202 // Sets the comment for a given key. 00203 bool SetKeyComment(const t_Str& szKey, const t_Str& szComment, 00204 const t_Str& szSection = t_Str("")); 00205 00206 // Sets the comment for a given section 00207 bool SetSectionComment(const t_Str& szSection, const t_Str& szComment); 00208 00209 // DeleteKey: Deletes a given key from a specific section 00210 bool DeleteKey(const t_Str& szKey, const t_Str& szFromSection = t_Str("")); 00211 00212 // DeleteSection: Deletes a given section. 00213 bool DeleteSection(const t_Str& szSection); 00214 00215 // Key/Section handling methods 00217 00218 // CreateKey: Creates a new key in the requested section. The 00219 // Section will be created if it does not exist and the 00220 // AUTOCREATE_SECTIONS bit is set. 00221 bool CreateKey(const t_Str& szKey, const t_Str& szValue, 00222 const t_Str& szComment = t_Str(""), const t_Str& szSection = t_Str("")); 00223 // CreateSection: Creates the new section if it does not allready 00224 // exist. Section is created with no keys. 00225 bool CreateSection(const t_Str& szSection, const t_Str& szComment = t_Str("")); 00226 // CreateSection: Creates the new section if it does not allready 00227 // exist, and copies the keys passed into it into the new section. 00228 bool CreateSection(const t_Str& szSection, const t_Str& szComment, const KeyList& Keys); 00229 00230 // Utility Methods 00232 // SectionCount: Returns the number of valid sections in the database. 00233 int SectionCount(); 00234 // KeyCount: Returns the total number of keys, across all sections. 00235 int KeyCount(); 00236 // Clear: Initializes the member variables to their default states 00237 void Clear(); 00238 // SetFileName: For use when creating the object by hand 00239 // initializes the file name so that it can be later saved. 00240 void SetFileName(const t_Str& szFileName); 00241 // CommentStr 00242 // Parses a string into a proper comment token/comment. 00243 t_Str CommentStr(const t_Str& szComment); 00244 00245 00246 protected: 00247 // Note: I've tried to insulate the end user from the internal 00248 // data structures as much as possible. This is by design. Doing 00249 // so has caused some performance issues (multiple calls to a 00250 // GetSection() function that would otherwise not be necessary,etc). 00251 // But, I believe that doing so will provide a safer, more stable 00252 // environment. You'll notice that nothing returns a reference, 00253 // to modify the data values, you have to call member functions. 00254 // think carefully before changing this. 00255 00256 // GetKey: Returns the requested key (if found) from the requested 00257 // Section. Returns NULL otherwise. 00258 t_Key* GetKey(const t_Str& szKey, const t_Str& szSection); 00259 // GetSection: Returns the requested section (if found), NULL otherwise. 00260 t_Section* GetSection(const t_Str& szSection); 00261 00262 00263 // Data 00264 public: 00265 long m_Flags; // Our settings flags. 00266 00267 protected: 00268 SectionList m_Sections; // Our list of sections 00269 t_Str m_szFileName; // The filename to write to 00270 bool m_bDirty; // Tracks whether or not data has changed. 00271 }; 00272 00273 00274 00275 #endif 00276