CDataFile.cpp
Go to the documentation of this file.
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 //
00016 // CDataFile
00017 // The purpose of this class is to provide the means to easily store key/value
00018 // pairs in a config file, seperated by independant sections. Sections may not
00019 // have duplicate keys, although two or more sections can have the same key.
00020 // Simple support for comments is included. Each key, and each section may have
00021 // it's own multiline comment.
00022 //
00023 // An example might look like this;
00024 //
00025 // [UserSettings]
00026 // Name=Joe User
00027 // Date of Birth=12/25/01
00028 //
00029 // ;
00030 // ; Settings unique to this server
00031 // ;
00032 // [ServerSettings]
00033 // Port=1200
00034 // IP_Address=127.0.0.1
00035 // MachineName=ADMIN
00036 //
00037 
00038 #include <cstdlib>
00039 #include <cstdio>
00040 #include <cstdarg>
00041 #include <cfloat>
00042 #include <cctype>
00043 #include <cstring>
00044 #include <climits>
00045 #include <vector>
00046 #include <string>
00047 #include <fstream>
00048 
00049 #ifdef WIN32
00050 #include <windows.h>
00051 #endif
00052 
00053 #include <blort/Tracker/CDataFile.h>
00054 
00055 // Compatibility Defines ////////////////////////////////////////////////////////
00057 #ifdef WIN32
00058   #define snprintf  _snprintf
00059   #define vsnprintf _vsnprintf
00060 #endif
00061 
00062 using namespace std;
00063 
00064 // CDataFile
00065 // Our default contstructor.  If it can load the file, it will do so and populate
00066 // the section list with the values from the file.
00067 CDataFile::CDataFile(const t_Str& szFileName)
00068 {
00069         m_bDirty = false;
00070         m_szFileName = szFileName;
00071         m_Flags = (AUTOCREATE_SECTIONS | AUTOCREATE_KEYS);
00072         m_Sections.push_back( t_Section() );
00073 
00074         Load(m_szFileName);
00075 }
00076 
00077 CDataFile::CDataFile()
00078 {
00079         Clear();
00080         m_Flags = (AUTOCREATE_SECTIONS | AUTOCREATE_KEYS);
00081         m_Sections.push_back( t_Section() );
00082 }
00083 
00084 // ~CDataFile
00085 // Saves the file if any values have changed since the last save.
00086 CDataFile::~CDataFile()
00087 {
00088         //if ( m_bDirty )  // MZ: this does not seem to work!
00089         //      Save();
00090 }
00091 
00092 // Clear
00093 // Resets the member variables to their defaults
00094 void CDataFile::Clear()
00095 {
00096         m_bDirty = false;
00097         m_szFileName = t_Str("");
00098         m_Sections.clear();
00099 }
00100 
00101 // SetFileName
00102 // Set's the m_szFileName member variable. For use when creating the CDataFile
00103 // object by hand (-vs- loading it from a file
00104 void CDataFile::SetFileName(const t_Str& szFileName)
00105 {
00106         if (m_szFileName.size() != 0 && CompareNoCase(szFileName, m_szFileName) != 0)
00107         {
00108                 m_bDirty = true;
00109 
00110                 Report(E_WARN, "[CDataFile::SetFileName] The filename has changed from <%s> to <%s>.",
00111                            m_szFileName.c_str(), szFileName.c_str());
00112         }
00113 
00114         m_szFileName = szFileName;
00115 }
00116 
00117 // Load
00118 // Attempts to load in the text file. If successful it will populate the 
00119 // Section list with the key/value pairs found in the file. Note that comments
00120 // are saved so that they can be rewritten to the file later.
00121 bool CDataFile::Load(const t_Str& szFileName)
00122 {
00123         fstream File(szFileName.c_str(), ios::in);
00124 
00125         if ( File.is_open() )
00126         {
00127                 bool bDone = false;
00128                 bool bAutoKey = (m_Flags & AUTOCREATE_KEYS) == AUTOCREATE_KEYS;
00129                 bool bAutoSec = (m_Flags & AUTOCREATE_SECTIONS) == AUTOCREATE_SECTIONS;
00130                 
00131                 t_Str szLine;
00132                 t_Str szComment;
00133                 char buffer[MAX_BUFFER_LEN]; 
00134                 t_Section* pSection = GetSection("");
00135 
00136                 // These need to be set, we'll restore the original values later.
00137                 m_Flags |= AUTOCREATE_KEYS;
00138                 m_Flags |= AUTOCREATE_SECTIONS;
00139 
00140                 while ( !bDone )
00141                 {
00142                         memset(buffer, 0, MAX_BUFFER_LEN);
00143                         File.getline(buffer, MAX_BUFFER_LEN);
00144 
00145                         szLine = buffer;
00146                         Trim(szLine);
00147 
00148                         bDone = ( File.eof() || File.bad() || File.fail() );
00149 
00150                         if ( szLine.find_first_of(CommentIndicators) == 0 )
00151                         {
00152                                 szComment += "\n";
00153                                 szComment += szLine;
00154                         }
00155                         else
00156                         if ( szLine.find_first_of('[') == 0 ) // new section
00157                         {
00158                                 szLine.erase( 0, 1 );
00159                                 szLine.erase( szLine.find_last_of(']'), 1 );
00160 
00161                                 CreateSection(szLine, szComment);
00162                                 pSection = GetSection(szLine);
00163                                 szComment = t_Str("");
00164                         }
00165                         else 
00166                         if ( szLine.size() > 0 ) // we have a key, add this key/value pair
00167                         {
00168                                 t_Str szKey = GetNextWord(szLine);
00169                                 t_Str szValue = szLine;
00170 
00171                                 if ( szKey.size() > 0 && szValue.size() > 0 )
00172                                 {
00173                                         SetValue(szKey, szValue, szComment, pSection->szName);
00174                                         szComment = t_Str("");
00175                                 }
00176                         }
00177                 }
00178 
00179                 // Restore the original flag values.
00180                 if ( !bAutoKey )
00181                         m_Flags &= ~AUTOCREATE_KEYS;
00182 
00183                 if ( !bAutoSec )
00184                         m_Flags &= ~AUTOCREATE_SECTIONS;
00185         }
00186         else
00187         {
00188                 Report(E_INFO, "[CDataFile::Load] Unable to open file. Does it exist?");
00189                 return false;
00190         }
00191 
00192         File.close();
00193 
00194         return true;
00195 }
00196 
00197 
00198 // Save
00199 // Attempts to save the Section list and keys to the file. Note that if Load
00200 // was never called (the CDataFile object was created manually), then you
00201 // must set the m_szFileName variable before calling save.
00202 bool CDataFile::Save()
00203 {
00204         if ( KeyCount() == 0 && SectionCount() == 0 )
00205         {
00206                 // no point in saving
00207                 Report(E_INFO, "[CDataFile::Save] Nothing to save.");
00208                 return false; 
00209         }
00210 
00211         if ( m_szFileName.size() == 0 )
00212         {
00213                 Report(E_ERROR, "[CDataFile::Save] No filename has been set.");
00214                 return false;
00215         }
00216 
00217         fstream File(m_szFileName.c_str(), ios::out|ios::trunc);
00218 
00219         if ( File.is_open() )
00220         {
00221                 SectionItor s_pos;
00222                 KeyItor k_pos;
00223                 t_Section Section;
00224                 t_Key Key;
00225 
00226                 for (s_pos = m_Sections.begin(); s_pos != m_Sections.end(); ++s_pos)
00227                 {
00228                         Section = (*s_pos);
00229                         bool bWroteComment = false;
00230 
00231                         if ( Section.szComment.size() > 0 )
00232                         {
00233                                 bWroteComment = true;
00234                                 WriteLn(File, "\n%s", CommentStr(Section.szComment).c_str());
00235                         }
00236 
00237                         if ( Section.szName.size() > 0 )
00238                         {
00239                                 WriteLn(File, "%s[%s]", 
00240                                                 bWroteComment ? "" : "\n", 
00241                                                 Section.szName.c_str());
00242                         }
00243 
00244                         for (k_pos = Section.Keys.begin(); k_pos != Section.Keys.end(); ++k_pos)
00245                         {
00246                                 Key = (*k_pos);
00247 
00248                                 if ( Key.szKey.size() > 0 && Key.szValue.size() > 0 )
00249                                 {
00250                                         WriteLn(File, "%s%s%s%s%c%s", 
00251                                                 Key.szComment.size() > 0 ? "\n" : "",
00252                                                 CommentStr(Key.szComment).c_str(),
00253                                                 Key.szComment.size() > 0 ? "\n" : "",
00254                                                 Key.szKey.c_str(),
00255                                                 EqualIndicators[0],
00256                                                 Key.szValue.c_str());
00257                                 }
00258                         }
00259                 }
00260                 
00261         }
00262         else
00263         {
00264                 Report(E_ERROR, "[CDataFile::Save] Unable to save file.");
00265                 return false;
00266         }
00267 
00268         m_bDirty = false;
00269         
00270         File.flush();
00271         File.close();
00272 
00273         return true;
00274 }
00275 
00276 // SetKeyComment
00277 // Set the comment of a given key. Returns true if the key is not found.
00278 bool CDataFile::SetKeyComment(const t_Str& szKey, const t_Str& szComment,
00279          const t_Str& szSection)
00280 {
00281         KeyItor k_pos;
00282         t_Section* pSection;
00283 
00284         if ( (pSection = GetSection(szSection)) == NULL )
00285                 return false;
00286 
00287         for (k_pos = pSection->Keys.begin(); k_pos != pSection->Keys.end(); ++k_pos)
00288         {
00289                 if ( CompareNoCase( (*k_pos).szKey, szKey ) == 0 )
00290                 {
00291                         (*k_pos).szComment = szComment;
00292                         m_bDirty = true;
00293                         return true;
00294                 }
00295         }
00296 
00297         return false;
00298 
00299 }
00300 
00301 // SetSectionComment
00302 // Set the comment for a given section. Returns false if the section
00303 // was not found.
00304 bool CDataFile::SetSectionComment(const t_Str& szSection, const t_Str& szComment)
00305 {
00306         SectionItor s_pos;
00307 
00308         for (s_pos = m_Sections.begin(); s_pos != m_Sections.end(); ++s_pos)
00309         {
00310                 if ( CompareNoCase( (*s_pos).szName, szSection ) == 0 ) 
00311                 {
00312                     (*s_pos).szComment = szComment;
00313                         m_bDirty = true;
00314                         return true;
00315                 }
00316         }
00317 
00318         return false;
00319 }
00320 
00321 
00322 // SetValue
00323 // Given a key, a value and a section, this function will attempt to locate the
00324 // Key within the given section, and if it finds it, change the keys value to
00325 // the new value. If it does not locate the key, it will create a new key with
00326 // the proper value and place it in the section requested.
00327 bool CDataFile::SetValue(const t_Str& szKey, const t_Str& szValue,
00328          const t_Str& szComment, const t_Str& szSection)
00329 {
00330         t_Key* pKey = GetKey(szKey, szSection);
00331         t_Section* pSection = GetSection(szSection);
00332 
00333         if (pSection == NULL)
00334         {
00335                 if ( !(m_Flags & AUTOCREATE_SECTIONS) || !CreateSection(szSection,""))
00336                         return false;
00337 
00338                 pSection = GetSection(szSection);
00339         }
00340 
00341         // Sanity check...
00342         if ( pSection == NULL )
00343                 return false;
00344 
00345         // if the key does not exist in that section, and the value passed 
00346         // is not t_Str("") then add the new key.
00347         if ( pKey == NULL && szValue.size() > 0 && (m_Flags & AUTOCREATE_KEYS))
00348         {
00349                 t_Key Key;
00350 
00351                 Key.szKey = szKey;
00352                 Key.szValue = szValue;
00353                 Key.szComment = szComment;
00354 
00355                 m_bDirty = true;
00356 
00357                 pSection->Keys.push_back(Key);
00358 
00359                 return true;
00360         }
00361 
00362         if ( pKey != NULL )
00363         {
00364                 pKey->szValue = szValue;
00365                 pKey->szComment = szComment;
00366 
00367                 m_bDirty = true;
00368                 
00369                 return true;
00370         }
00371 
00372         return false;
00373 }
00374 
00375 // SetFloat
00376 // Passes the given float to SetValue as a string
00377 bool CDataFile::SetFloat(const t_Str& szKey, float fValue,
00378                 const t_Str& szComment, const t_Str& szSection)
00379 {
00380         char szStr[64];
00381 
00382         snprintf(szStr, 64, "%f", fValue);
00383 
00384         return SetValue(szKey, szStr, szComment, szSection);
00385 }
00386 
00387 // SetInt
00388 // Passes the given int to SetValue as a string
00389 bool CDataFile::SetInt(const t_Str& szKey, int nValue, const t_Str& szComment, const t_Str& szSection)
00390 {
00391         char szStr[64];
00392 
00393         snprintf(szStr, 64, "%d", nValue);
00394 
00395         return SetValue(szKey, szStr, szComment, szSection);
00396 
00397 }
00398 
00399 // SetBool
00400 // Passes the given bool to SetValue as a string
00401 bool CDataFile::SetBool(const t_Str& szKey, bool bValue, const t_Str& szComment, const t_Str& szSection)
00402 {
00403         t_Str szValue = bValue ?  "True" : "False";
00404 
00405         return SetValue(szKey, szValue, szComment, szSection);
00406 }
00407 
00408 // GetValue
00409 // Returns the key value as a t_Str object. A return value of
00410 // t_Str("") indicates that the key could not be found.
00411 t_Str CDataFile::GetValue(const t_Str& szKey, const t_Str& szSection) 
00412 {
00413         t_Key* pKey = GetKey(szKey, szSection);
00414 
00415         return (pKey == NULL) ? t_Str("") : pKey->szValue;
00416 }
00417 
00418 // GetString
00419 // Returns the key value as a t_Str object. A return value of
00420 // t_Str("") indicates that the key could not be found.
00421 t_Str CDataFile::GetString(const t_Str& szKey, const t_Str& szSection)
00422 {
00423         return GetValue(szKey, szSection);
00424 }
00425 
00426 // GetFloat
00427 // Returns the key value as a float type. Returns FLT_MIN if the key is
00428 // not found.
00429 float CDataFile::GetFloat(const t_Str& szKey, const t_Str& szSection)
00430 {
00431         t_Str szValue = GetValue(szKey, szSection);
00432 
00433         if ( szValue.size() == 0 )
00434                 return FLT_MIN;
00435         return (float)atof( szValue.c_str() );
00436 }
00437 
00438 // GetInt
00439 // Returns the key value as an integer type. Returns INT_MIN if the key is
00440 // not found.
00441 int     CDataFile::GetInt(const t_Str& szKey, const t_Str& szSection)
00442 {
00443         t_Str szValue = GetValue(szKey, szSection);
00444 
00445         if ( szValue.size() == 0 )
00446                 return INT_MIN;
00447 
00448         return atoi( szValue.c_str() );
00449 }
00450 
00451 // GetBool
00452 // Returns the key value as a bool type. Returns false if the key is
00453 // not found.
00454 bool CDataFile::GetBool(const t_Str& szKey, const t_Str& szSection)
00455 {
00456         bool bValue = false;
00457         t_Str szValue = GetValue(szKey, szSection);
00458 
00459         if ( szValue.find("1") == 0 
00460                 || CompareNoCase(szValue, "true") == 0
00461                 || CompareNoCase(szValue, "yes") == 0 )
00462         {
00463                 bValue = true;
00464         }
00465 
00466         return bValue;
00467 }
00468 
00469 // DeleteSection
00470 // Delete a specific section. Returns false if the section cannot be 
00471 // found or true when sucessfully deleted.
00472 bool CDataFile::DeleteSection(const t_Str& szSection)
00473 {
00474         SectionItor s_pos;
00475 
00476         for (s_pos = m_Sections.begin(); s_pos != m_Sections.end(); ++s_pos)
00477         {
00478                 if ( CompareNoCase( (*s_pos).szName, szSection ) == 0 ) 
00479                 {
00480                         m_Sections.erase(s_pos);
00481                         return true;
00482                 }
00483         }
00484 
00485         return false;
00486 }
00487 
00488 // DeleteKey
00489 // Delete a specific key in a specific section. Returns false if the key
00490 // cannot be found or true when sucessfully deleted.
00491 bool CDataFile::DeleteKey(const t_Str& szKey, const t_Str& szFromSection)
00492 {
00493         KeyItor k_pos;
00494         t_Section* pSection;
00495 
00496         if ( (pSection = GetSection(szFromSection)) == NULL )
00497                 return false;
00498 
00499         for (k_pos = pSection->Keys.begin(); k_pos != pSection->Keys.end(); ++k_pos)
00500         {
00501                 if ( CompareNoCase( (*k_pos).szKey, szKey ) == 0 )
00502                 {
00503                         pSection->Keys.erase(k_pos);
00504                         return true;
00505                 }
00506         }
00507 
00508         return false;
00509 }
00510 
00511 // CreateKey
00512 // Given a key, a value and a section, this function will attempt to locate the
00513 // Key within the given section, and if it finds it, change the keys value to
00514 // the new value. If it does not locate the key, it will create a new key with
00515 // the proper value and place it in the section requested.
00516 bool CDataFile::CreateKey(const t_Str& szKey, const t_Str& szValue,
00517                 const t_Str& szComment, const t_Str& szSection)
00518 {
00519         bool bAutoKey = (m_Flags & AUTOCREATE_KEYS) == AUTOCREATE_KEYS;
00520         bool bReturn  = false;
00521 
00522         m_Flags |= AUTOCREATE_KEYS;
00523 
00524         bReturn = SetValue(szKey, szValue, szComment, szSection);
00525 
00526         if ( !bAutoKey )
00527                 m_Flags &= ~AUTOCREATE_KEYS;
00528 
00529         return bReturn;
00530 }
00531 
00532 
00533 // CreateSection
00534 // Given a section name, this function first checks to see if the given section
00535 // allready exists in the list or not, if not, it creates the new section and
00536 // assigns it the comment given in szComment.  The function returns true if
00537 // sucessfully created, or false otherwise. 
00538 bool CDataFile::CreateSection(const t_Str& szSection, const t_Str& szComment)
00539 {
00540         t_Section* pSection = GetSection(szSection);
00541 
00542         if ( pSection )
00543         {
00544                 Report(E_INFO, "[CDataFile::CreateSection] Section <%s> allready exists. Aborting.", szSection.c_str());
00545                 return false;
00546         }
00547 
00548         t_Section Section;
00549 
00550         Section.szName = szSection;
00551         Section.szComment = szComment;
00552         m_Sections.push_back(Section);
00553         m_bDirty = true;
00554 
00555         return true;
00556 }
00557 
00558 // CreateSection
00559 // Given a section name, this function first checks to see if the given section
00560 // allready exists in the list or not, if not, it creates the new section and
00561 // assigns it the comment given in szComment.  The function returns true if
00562 // sucessfully created, or false otherwise. This version accpets a KeyList 
00563 // and sets up the newly created Section with the keys in the list.
00564 bool CDataFile::CreateSection(const t_Str& szSection, const t_Str& szComment,
00565                 const KeyList& Keys)
00566 {
00567         if ( !CreateSection(szSection, szComment) )
00568                 return false;
00569 
00570         t_Section* pSection = GetSection(szSection);
00571 
00572         if ( !pSection )
00573                 return false;
00574 
00575         pSection->Keys = Keys;
00576 
00577         m_bDirty = true;
00578 
00579         return true;
00580 }
00581 
00582 // SectionCount
00583 // Simply returns the number of sections in the list.
00584 int CDataFile::SectionCount() 
00585 { 
00586         return m_Sections.size(); 
00587 }
00588 
00589 // KeyCount
00590 // Returns the total number of keys contained within all the sections.
00591 int CDataFile::KeyCount()
00592 {
00593         int nCounter = 0;
00594         SectionItor s_pos;
00595 
00596         for (s_pos = m_Sections.begin(); s_pos != m_Sections.end(); ++s_pos)
00597                 nCounter += (*s_pos).Keys.size();
00598 
00599         return nCounter;
00600 }
00601 
00602 
00603 // Protected Member Functions ///////////////////////////////////////////////////
00605 
00606 // GetKey
00607 // Given a key and section name, looks up the key and if found, returns a
00608 // pointer to that key, otherwise returns NULL.
00609 t_Key*  CDataFile::GetKey(const t_Str& szKey, const t_Str& szSection)
00610 {
00611         KeyItor k_pos;
00612         t_Section* pSection;
00613 
00614         // Since our default section has a name value of t_Str("") this should
00615         // always return a valid section, wether or not it has any keys in it is
00616         // another matter.
00617         if ( (pSection = GetSection(szSection)) == NULL )
00618                 return NULL;
00619 
00620         for (k_pos = pSection->Keys.begin(); k_pos != pSection->Keys.end(); ++k_pos)
00621         {
00622                 if ( CompareNoCase( (*k_pos).szKey, szKey ) == 0 )
00623                         return (t_Key*)&(*k_pos);
00624         }
00625 
00626         return NULL;
00627 }
00628 
00629 // GetSection
00630 // Given a section name, locates that section in the list and returns a pointer
00631 // to it. If the section was not found, returns NULL
00632 t_Section* CDataFile::GetSection(const t_Str& szSection)
00633 {
00634         SectionItor s_pos;
00635 
00636         for (s_pos = m_Sections.begin(); s_pos != m_Sections.end(); ++s_pos)
00637         {
00638                 if ( CompareNoCase( (*s_pos).szName, szSection ) == 0 ) 
00639                         return (t_Section*)&(*s_pos);
00640         }
00641 
00642         return NULL;
00643 }
00644 
00645 
00646 t_Str CDataFile::CommentStr(const t_Str& szComment)
00647 {
00648         t_Str szNewStr = szComment;
00649 
00650         Trim(szNewStr);
00651 
00652         if ( szNewStr.size() == 0 )
00653                 return szNewStr;
00654         
00655         if ( szNewStr.find_first_of(CommentIndicators) != 0 )
00656         {
00657                 t_Str szPreStr;
00658                 szPreStr += CommentIndicators[0];
00659                 szPreStr += " ";
00660                 szNewStr.insert(0, szPreStr);
00661         }
00662 
00663         return szNewStr;
00664 }
00665 
00666 
00667 
00668 // Utility Functions ////////////////////////////////////////////////////////////
00670 
00671 // GetNextWord
00672 // Given a key +delimiter+ value string, pulls the key name from the string,
00673 // deletes the delimiter and alters the original string to contain the
00674 // remainder.  Returns the key
00675 t_Str GetNextWord(t_Str& CommandLine)
00676 {
00677         size_t nPos = CommandLine.find_first_of(EqualIndicators);
00678         t_Str sWord = t_Str("");
00679 
00680         if ( nPos != string::npos )
00681         {
00682                 sWord = CommandLine.substr(0, nPos);
00683                 CommandLine.erase(0, nPos+1);
00684         }
00685         else
00686         {
00687                 sWord = CommandLine;
00688                 CommandLine = t_Str("");
00689         }
00690 
00691         Trim(CommandLine);
00692         Trim(sWord);
00693         return sWord;
00694 }
00695 
00696 
00697 // CompareNoCase
00698 // it's amazing what features std::string lacks.  This function simply
00699 // does a lowercase compare against the two strings, returning 0 if they
00700 // match.
00701 int CompareNoCase(const t_Str& str1, const t_Str& str2)
00702 {
00703 #ifdef WIN32
00704         return _stricmp(str1.c_str(), str2.c_str());    
00705 #else
00706         return strcasecmp(str1.c_str(), str2.c_str());
00707 #endif
00708 }
00709 
00710 // Trim
00711 // Trims whitespace from both sides of a string.
00712 void Trim(t_Str& szStr)
00713 {
00714         t_Str szTrimChars = WhiteSpace;
00715         szTrimChars += EqualIndicators;
00716 
00717         // trim left
00718         size_t nPos = szStr.find_first_not_of(szTrimChars);
00719   if(nPos != string::npos)
00720   {
00721     szStr.erase(0, nPos);
00722     // trim right
00723     size_t rPos = szStr.find_last_not_of(szTrimChars);
00724     if (rPos != string::npos && rPos < szStr.size() - 1)
00725       szStr.erase(rPos + 1);
00726   }
00727   else // else the string is all white space
00728   {
00729     szStr.erase();
00730   }
00731 }
00732 
00733 // WriteLn
00734 // Writes the formatted output to the file stream, returning the number of
00735 // bytes written.
00736 int WriteLn(fstream& stream, const char* fmt, ...)
00737 {
00738         char buf[MAX_BUFFER_LEN];
00739         int nLength;
00740 
00741         memset(buf, 0, MAX_BUFFER_LEN);
00742         va_list args;
00743 
00744         va_start (args, fmt);
00745           nLength = vsnprintf(buf, MAX_BUFFER_LEN, fmt, args);
00746         va_end (args);
00747 
00748 
00749         if ( buf[nLength] != '\n' && buf[nLength] != '\r' )
00750                 buf[nLength++] = '\n';
00751 
00752 
00753         stream.write(buf, nLength);
00754 
00755         return nLength;
00756 }
00757 
00758 // Report
00759 // A simple reporting function. Outputs the report messages to stdout
00760 // This is a dumb'd down version of a simmilar function of mine, so if 
00761 // it looks like it should do more than it does, that's why...
00762 void Report(e_DebugLevel DebugLevel, const char *fmt, ...)
00763 {
00764         char buf[MAX_BUFFER_LEN];
00765         int nLength;
00766         t_Str szMsg;
00767 
00768         va_list args;
00769 
00770         memset(buf, 0, MAX_BUFFER_LEN);
00771 
00772         va_start (args, fmt);
00773           nLength = vsnprintf(buf, MAX_BUFFER_LEN, fmt, args);
00774         va_end (args);
00775 
00776 
00777         if ( buf[nLength] != '\n' && buf[nLength] != '\r' )
00778                 buf[nLength++] = '\n';
00779 
00780 
00781         switch ( DebugLevel )
00782         {
00783                 case E_DEBUG:
00784                         szMsg = "<debug> ";
00785                         break;
00786                 case E_INFO:
00787                         szMsg = "<info> ";
00788                         break;
00789                 case E_WARN:
00790                         szMsg = "<warn> ";
00791                         break;
00792                 case E_ERROR:
00793                         szMsg = "<error> ";
00794                         break;
00795                 case E_FATAL:
00796                         szMsg = "<fatal> ";
00797                         break;
00798                 case E_CRITICAL:
00799                         szMsg = "<critical> ";
00800                         break;
00801         }
00802 
00803 
00804         szMsg += buf;
00805 
00806 
00807 #ifdef WIN32
00808         OutputDebugString(szMsg.c_str());
00809 #endif
00810 
00811         printf("%s", szMsg.c_str());
00812 
00813 }
00814 


blort
Author(s): Thomas Mörwald , Michael Zillich , Andreas Richtsfeld , Johann Prankl , Markus Vincze , Bence Magyar
autogenerated on Wed Aug 26 2015 15:24:12