Index: ext/libicpf/src/libicpf/cfg.cpp =================================================================== diff -u -r21847bff9bc6958b98f3fe8bac319590b790fc0f -r86310fdf8a767b700985ebd1b255004d9eb85fb7 --- ext/libicpf/src/libicpf/cfg.cpp (.../cfg.cpp) (revision 21847bff9bc6958b98f3fe8bac319590b790fc0f) +++ ext/libicpf/src/libicpf/cfg.cpp (.../cfg.cpp) (revision 86310fdf8a767b700985ebd1b255004d9eb85fb7) @@ -27,6 +27,9 @@ #include "exception.h" #include #include +#include "err_codes.h" +#include "cfg_xml.h" +#include "cfg_ini.h" BEGIN_ICPF_NAMESPACE @@ -48,7 +51,6 @@ property_tracker::property_tracker(const property_tracker& rSrc) : m_hProperties((ptr_t)new std::set(*(std::set*)rSrc.m_hProperties)) { - } /** Destructs the property tracker object. @@ -98,7 +100,7 @@ for (std::set::iterator it=m_psProperties->begin();it != m_psProperties->end();it++) { puiProps[tIndex++]=(*it); - if (tIndex >= stMaxCount) + if(tIndex >= stMaxCount) break; } @@ -115,7 +117,7 @@ { for (std::set::iterator it=m_psProperties->begin();it != m_psProperties->end();it++) { - if (!(*pfn)((*it), pParam)) + if(!(*pfn)((*it), pParam)) break; } } @@ -129,18 +131,31 @@ * \param[in] pCfgBase - pointer to a base handler of the configuration strings * cound be pointer to xml handler, ini handler or any other */ -config::config(config_base* pCfgBase) : +config::config(config_base_types eCfgType) : m_lock(), m_hProps((ptr_t)new std::vector), - m_pCfgBase(pCfgBase) + m_pszCurrentPath(NULL) { + switch(eCfgType) + { + case eXml: + m_pCfgBase = new xml_cfg; + break; + case eIni: + m_pCfgBase = new ini_cfg; + break; + default: + THROW(_t("Undefined config base type"), 0, 0, 0); + } } /** Destructs the config class. */ config::~config() { delete m_pvProps; + delete [] m_pszCurrentPath; + delete m_pCfgBase; } /** Function opens the specified file using the underlying config base @@ -152,6 +167,20 @@ void config::read(const tchar_t* pszPath) { assert(pszPath); + if(!pszPath) + THROW(_T("Path to the file not provided."), FERR_OPEN, 0, 0); + + // remembering path before operation and not freeing it on fail is done on purpose here + // (to support future write() to this file in case file does not exist yet) + size_t stLen = _tcslen(pszPath); + if(stLen) + { + delete [] m_pszCurrentPath; + m_pszCurrentPath = new tchar_t[stLen + 1]; + _tcscpy(m_pszCurrentPath, pszPath); + m_pszCurrentPath[stLen] = _t('\0'); + } + m_lock.lock(); try { @@ -176,15 +205,29 @@ */ void config::write(const tchar_t* pszPath) { + if(!m_pszCurrentPath && !pszPath) + THROW(_T("No path specified"), FERR_OPEN, 0, 0); m_lock.lock(); try { // store current properties to the underlying object store_registered(); + if(pszPath) + { + size_t stLen = _tcslen(pszPath); + if(stLen) + { + delete [] m_pszCurrentPath; + m_pszCurrentPath = new tchar_t[stLen + 1]; + _tcscpy(m_pszCurrentPath, pszPath); + m_pszCurrentPath[stLen] = _t('\0'); + } + } + // and save - m_pCfgBase->save(pszPath); + m_pCfgBase->save(m_pszCurrentPath); } catch(...) { @@ -277,7 +320,7 @@ // get the value for the property name ptr_t hFind=NULL; - if ( (hFind=m_pCfgBase->find(pszName)) != NULL ) + if( (hFind=m_pCfgBase->find(pszName)) != NULL ) { const tchar_t* psz=NULL; while( (psz=m_pCfgBase->find_next(hFind)) != NULL) @@ -287,7 +330,7 @@ m_pCfgBase->find_close(hFind); } - else if (!(uiFlags & property::flag_array)) + else if(!(uiFlags & property::flag_array)) prop.set_signed_num(llDef); // add to the vector @@ -321,7 +364,7 @@ // get the value for the property name ptr_t hFind=NULL; - if ( (hFind=m_pCfgBase->find(pszName)) != NULL ) + if( (hFind=m_pCfgBase->find(pszName)) != NULL ) { const tchar_t* psz=NULL; while( (psz=m_pCfgBase->find_next(hFind)) != NULL) @@ -331,7 +374,7 @@ m_pCfgBase->find_close(hFind); } - else if (!(uiFlags & property::flag_array)) + else if(!(uiFlags & property::flag_array)) prop.set_unsigned_num(ullDef); // add to the vector @@ -362,7 +405,7 @@ // get the value for the property name ptr_t hFind=NULL; - if ( (hFind=m_pCfgBase->find(pszName)) != NULL ) + if( (hFind=m_pCfgBase->find(pszName)) != NULL ) { const tchar_t* psz=NULL; while( (psz=m_pCfgBase->find_next(hFind)) != NULL) @@ -372,7 +415,7 @@ m_pCfgBase->find_close(hFind); } - else if (!(uiFlags & property::flag_array)) + else if(!(uiFlags & property::flag_array)) prop.set_bool(bDef); // add to the vector @@ -403,7 +446,7 @@ // get the value for the property name ptr_t hFind=NULL; - if ( (hFind=m_pCfgBase->find(pszName)) != NULL ) + if( (hFind=m_pCfgBase->find(pszName)) != NULL ) { const tchar_t* psz=NULL; while( (psz=m_pCfgBase->find_next(hFind)) != NULL) @@ -413,7 +456,7 @@ m_pCfgBase->find_close(hFind); } - else if (!(uiFlags & property::flag_array)) + else if(!(uiFlags & property::flag_array)) prop.set_string(pszDef); // add to the vector @@ -507,6 +550,30 @@ return psz; } +/** Function retrieves the string value. +* +* \param[in] uiProp - property to retrieve the value of +* \param[in] stIndex - index of the value to retrieve (meaningful only for +* array-based properties) +* \return Property value. +*/ +const tchar_t* config::get_string(uint_t uiProp, tchar_t* pszBuffer, size_t stBufferSize, size_t stIndex) +{ + if(!pszBuffer || stBufferSize < 1) + return NULL; + + m_lock.lock(); + const tchar_t* psz=m_pvProps->at(uiProp).get_string(stIndex); + size_t stLen = _tcslen(psz); + if(stLen >= stBufferSize) + stLen = stBufferSize - 1; + + _tcsncpy(pszBuffer, psz, stLen); + pszBuffer[stLen] = _t('\0'); + m_lock.unlock(); + return pszBuffer; +} + /** Function sets the property value from string. * * \param[in] uiProp - property id to set the value for @@ -519,9 +586,10 @@ { m_lock.lock(); m_pvProps->at(uiProp).set_value(pszVal, a, tIndex); - if (pTracker) + if(pTracker) pTracker->add(uiProp); m_lock.unlock(); + property_changed_notify(uiProp); } /** Function sets the signed number property value. @@ -536,9 +604,10 @@ { m_lock.lock(); m_pvProps->at(uiProp).set_signed_num(llVal, a, tIndex); - if (pTracker) + if(pTracker) pTracker->add(uiProp); m_lock.unlock(); + property_changed_notify(uiProp); } /** Function sets the unsigned number property value. @@ -553,9 +622,10 @@ { m_lock.lock(); m_pvProps->at(uiProp).set_unsigned_num(ullVal, a, tIndex); - if (pTracker) + if(pTracker) pTracker->add(uiProp); m_lock.unlock(); + property_changed_notify(uiProp); } /** Function sets the bool property value. @@ -570,9 +640,10 @@ { m_lock.lock(); m_pvProps->at(uiProp).set_bool(bVal, a, tIndex); - if (pTracker) + if(pTracker) pTracker->add(uiProp); m_lock.unlock(); + property_changed_notify(uiProp); } /** Function sets the string property value. @@ -587,11 +658,22 @@ { m_lock.lock(); m_pvProps->at(uiProp).set_string(pszVal, a, tIndex); - if (pTracker) + if(pTracker) pTracker->add(uiProp); m_lock.unlock(); + property_changed_notify(uiProp); } +/** Function sets the callback function to be called on property change. + * \param[in] pfnCallback - pointer to the function + * \param[in] pParam - user defined parameter to pass to the callback + */ +void config::set_callback(PFNPROPERTYCHANGED pfnCallback, ptr_t pParam) +{ + m_pfnNotifyCallback = pfnCallback; + m_pCallbackParam = pParam; +} + /** Function reads the values for the registered properties from the underlying * base config object. */ @@ -604,11 +686,11 @@ for (std::vector::iterator it=m_pvProps->begin();it != m_pvProps->end();it++) { // is this an array property ? - if ((*it).is_array()) + if((*it).is_array()) (*it).clear_array(); // and fill with value(s) - if ( (hFind=m_pCfgBase->find((*it).get_name())) != NULL) + if( (hFind=m_pCfgBase->find((*it).get_name())) != NULL) { while( (psz=m_pCfgBase->find_next(hFind)) != NULL) { @@ -646,4 +728,13 @@ m_lock.unlock(); } +/** Function executes the callback to notify about property value change. + * \param[in] uiPropID - property ID that changed + */ +void config::property_changed_notify(uint_t uiPropID) +{ + if(m_pfnNotifyCallback) + (*m_pfnNotifyCallback)(uiPropID, m_pCallbackParam); +} + END_ICPF_NAMESPACE Index: ext/libicpf/src/libicpf/cfg.h =================================================================== diff -u -rb337c059691a6940b52a86388ff427c734be8eb6 -r86310fdf8a767b700985ebd1b255004d9eb85fb7 --- ext/libicpf/src/libicpf/cfg.h (.../cfg.h) (revision b337c059691a6940b52a86388ff427c734be8eb6) +++ ext/libicpf/src/libicpf/cfg.h (.../cfg.h) (revision 86310fdf8a767b700985ebd1b255004d9eb85fb7) @@ -31,6 +31,9 @@ BEGIN_ICPF_NAMESPACE +/// Callback function definition +typedef void(*PFNPROPERTYCHANGED)(uint_t, ptr_t); + /** \brief Property group handling class * * Class is being used to manipulate the property groups (in connection with config::begin_group() and @@ -74,9 +77,15 @@ class LIBICPF_API config { public: + enum config_base_types + { + eXml, + eIni + }; +public: /** \name Construction/destruction */ /**@{*/ - config(config_base* pCfgBase); ///< Standard constructor + config(config_base_types eCfgType); ///< Standard constructor ~config(); ///< Standard destructor /**@}*/ @@ -130,6 +139,8 @@ bool get_bool(uint_t uiProp, size_t stIndex=0); /// Gets the value of string-type property const tchar_t* get_string(uint_t uiProp, size_t stIndex=0); + /// Retrieves the copy of the string + const tchar_t* get_string(uint_t uiProp, tchar_t* pszBuffer, size_t stBufferSize, size_t stIndex=0); // setting property data /// Sets the value from the string @@ -144,14 +155,23 @@ void set_string(uint_t uiProp, const tchar_t* pszVal, property::actions a=property::action_replace, size_t tIndex=0, property_tracker* pTracker=NULL); /**@}*/ +/** \name Notifications */ +/**@{*/ + void set_callback(PFNPROPERTYCHANGED pfnCallback, ptr_t pParam); +/**@}*/ + protected: void load_registered(); ///< Loads the registered property values from the underlying config base void store_registered(); ///< Stores the registered property values to the underlying config base + void property_changed_notify(uint_t uiPropID); ///< Calls the callback function to notify about the property value change protected: mutex m_lock; ///< Lock for the multi-threaded access to the properties ptr_t m_hProps; ///< Handle to the registered property storage - config_base* m_pCfgBase; ///< Underlying base for this class + config_base* m_pCfgBase; ///< Underlying base for this class + tchar_t* m_pszCurrentPath; ///< Current path (one specified when reading the file) + PFNPROPERTYCHANGED m_pfnNotifyCallback; ///< Function to be called when property changes + ptr_t m_pCallbackParam; ///< User-defined parameter to pass to the callback function }; END_ICPF_NAMESPACE Index: ext/libicpf/src/libicpf/cfg_ini.cpp =================================================================== diff -u --- ext/libicpf/src/libicpf/cfg_ini.cpp (revision 0) +++ ext/libicpf/src/libicpf/cfg_ini.cpp (revision 86310fdf8a767b700985ebd1b255004d9eb85fb7) @@ -0,0 +1,379 @@ +#include "cfg_ini.h" +#include "exception.h" +#include +#include +#include +#include "str_help.h" + +BEGIN_ICPF_NAMESPACE + +/// Buffer size for reading xml data from a file +#define INI_BUFFER 65536 + +// definition of line ending - system dependent +#if defined(_WIN32) || defined(_WIN64) +#define ENDL _t("\r\n") +#else +#define ENDL _t("\n") +#endif + +#ifdef _UNICODE + #define TEOF WEOF +#else + #define TEOF EOF +#endif + +/// String storage (key(s)=>value(s)) +typedef std::multimap attr_storage; +/// Ini node storage +typedef std::map ini_storage; + +/** Xml find handle structure - used for searching. +*/ +struct INIFINDHANDLE +{ + attr_storage::iterator it; ///< Iterator of currently retrieved string + attr_storage::iterator itEnd; ///< Iterator of a last string matching the criteria +}; + +/// Macro for faster access to the xml storage +#define m_pMainNode ((ini_storage*)m_hMainNode) + +/** Constructs the ini_cfg object. +*/ +ini_cfg::ini_cfg() : + m_hMainNode((ptr_t)new ini_storage) +{ + +} + +/** Destructs the xml config object. +*/ +ini_cfg::~ini_cfg() +{ + delete m_pMainNode; +} + +/** Function reads the contents of the xml file, parses it using expat parser +* and then creates xml nodes in memory that could be read using find functions. +* +* \param[in] pszPath - path to the file to be read +*/ +void ini_cfg::read(const tchar_t* pszPath) +{ + // clear current contents + clear(); + + // read the data from file + FILE* pFile=_tfopen(pszPath, _t("rb")); + if(pFile == NULL) + THROW(icpf::exception::format(_t("Cannot open the file ") TSTRFMT _t(" for reading."), pszPath), 0, errno, 0); + + // prepare buffer for data + tchar_t* pszBuffer = new tchar_t[INI_BUFFER]; + tchar_t* pszLine = NULL; + while((pszLine = _fgetts(pszBuffer, INI_BUFFER, pFile)) != NULL) + { + // parse line + parse_line(pszBuffer); + } + + // check if that was eof or error + if(feof(pFile) == 0) + { + fclose(pFile); + // error while reading file + THROW(_T("Error while reading ini file."), 0, errno, 0); + } + + // close the file + fclose(pFile); +} + +/** Saves the internal xml nodes to the specified xml file. +* +* \param[in] pszPath - path to the file the data should be written to +* +* \note Function overwrites the contents of a file +*/ +void ini_cfg::save(const tchar_t* pszPath) +{ + FILE* pFile=_tfopen(pszPath, _t("wb")); + if(pFile == NULL) + THROW(icpf::exception::format(_t("Cannot open the file ") TSTRFMT _t(" for writing."), pszPath), 0, errno, 0); + + // put BOM into the file +/* +#if(defined(_WIN32) || defined(_WIN64)) + // utf-16le + const uint_t uiBOM=0x0000feff; + const uint_t uiCount=2; +#else + // utf-8 + const uint_t uiBOM=0x00bfbbef; + const uint_t uiCount=3; +#endif +*/ + + try + { + // write bom, check if it succeeded +// if(fwrite(&uiBOM, 1, uiCount, pFile) != uiCount) +// THROW(_t("Cannot write the BOM to the file '") TSTRFMT _t("'"), 0, errno, 0); + + // and write + tstring_t strLine; + for(ini_storage::iterator iterSections = m_pMainNode->begin(); iterSections != m_pMainNode->end(); iterSections++) + { + strLine = _t("[") + (*iterSections).first + _t("]") + ENDL; + if(_fputts(strLine.c_str(), pFile) == TEOF) + THROW(_t("Cannot put section name"), 0, errno, 0); + for(attr_storage::iterator iterAttribute = (*iterSections).second.begin(); iterAttribute != (*iterSections).second.end(); iterAttribute++) + { + strLine = (*iterAttribute).first + _t("=") + (*iterAttribute).second + ENDL; + if(_fputts(strLine.c_str(), pFile) == TEOF) + THROW(_t("Cannot put attribute"), 0, errno, 0); + } + + if(_fputts(ENDL, pFile) == TEOF) + THROW(_t("Cannot put end-of-line marker into the file"), 0, errno, 0); + } + } + catch(...) + { + fclose(pFile); + throw; + } + + // close the file + fclose(pFile); +} + +/** Function starts a search operation. Given the name of the property +* to be searched for(ie. "ch/program/startup"), funtion searches for +* it and returns a handle that can be used by subsequent calls to the +* find_next(). Free the handle using find_close() after finish. +* +* \param[in] pszName - name of the property to search for(in the form of +* "ch/program/startup" +* \return Handle to the search (NULL if not found). +*/ +ptr_t ini_cfg::find(const tchar_t* pszName) +{ + // parse the path + tstring_t strSection; + tstring_t strAttr; + if(!parse_property_name(pszName, strSection, strAttr)) + return NULL; + + ini_storage::iterator iterSection = m_pMainNode->find(strSection); + if(iterSection == m_pMainNode->end()) + return NULL; + + std::pair pairRange; + if(strAttr == _t("*")) + { + pairRange.first = (*iterSection).second.begin(); + pairRange.second = (*iterSection).second.end(); + } + else + pairRange = (*iterSection).second.equal_range(strAttr); + if(pairRange.first != (*iterSection).second.end()) + { + INIFINDHANDLE* pHandle = new INIFINDHANDLE; + pHandle->it = pairRange.first; + pHandle->itEnd = pairRange.second; + + return pHandle; + } + + return NULL; +} + +/** Finds the next string that belong to a specific key (as defined in +* a call to find() function. +* +* \param[in] pFindHandle - handle to the search (as returned from find()) +* \return Pointer to a next string found, NULL if none. +*/ +const tchar_t* ini_cfg::find_next(ptr_t pFindHandle) +{ + INIFINDHANDLE* pfh=(INIFINDHANDLE*)pFindHandle; + if(pfh->it != pfh->itEnd) + return (*pfh->it++).second.c_str(); + else + return NULL; +} + +/** Closes the find handle. +* +* \param[in] pFindHandle - handle to the search (as returned from find()) +*/ +void ini_cfg::find_close(ptr_t pFindHandle) +{ + delete ((INIFINDHANDLE*)pFindHandle); +} + +/** Sets the specified value in the given key name. Value can be either added to +* the current ones (multi-string support) or replace them completely. +* +* \param[in] pszName - key name for which the string should be set at +* \param[in] pszValue - value to set +* \param[in] a - action to take while setting +*/ +void ini_cfg::set_value(const tchar_t* pszName, const tchar_t* pszValue, actions a) +{ + // parse the path + tstring_t strSection; + tstring_t strAttr; + if(!parse_property_name(pszName, strSection, strAttr)) + THROW(_t("Property not found"), 0, 0, 0); + + if(strAttr == _t("*")) + THROW(_t("Wildcards not available in set_value mode"), 0, 0, 0); + + // search + ini_storage::iterator iterSection = m_pMainNode->find(strSection.c_str()); + if(iterSection == m_pMainNode->end()) + { + std::pair pairSection = m_pMainNode->insert(ini_storage::value_type(strSection, attr_storage())); + iterSection = pairSection.first; + if(iterSection == m_pMainNode->end()) + THROW(_t("Problem with creating section"), 0, 0, 0); + } + + attr_storage& rAttrs = (*iterSection).second; + + // clear if we're replacing + switch(a) + { + case config_base::action_replace: + { + std::pair pairRange = (*iterSection).second.equal_range(strAttr); + rAttrs.erase(pairRange.first, pairRange.second); + // do not break here - we are about to insert the data + } + case config_base::action_add: + { + rAttrs.insert(attr_storage::value_type(strAttr, pszValue)); + break; + } + default: + assert(false); + } +} + +/** Clears the contents of this class +* +* \param[in] pszName - name of the property to clear the values for +*/ +void ini_cfg::clear() +{ + m_pMainNode->clear(); +} + +/** Recursive clear function - searches recursively for a proper node +* and finally clears the string map. +* +* \param[in] pNodePtr - pointer to a node to be processed +* \param[in] pszName - name of the property to search for in the given node +*/ +void ini_cfg::clear(const tchar_t* pszName) +{ + if(pszName == NULL || pszName[0] == _t('*')) + m_pMainNode->clear(); + else + { + tstring_t strSection; + tstring_t strAttr; + if(!parse_property_name(pszName, strSection, strAttr)) + THROW(_t("Invalid name"), 0, 0, 0); + + ini_storage::iterator iterSection = m_pMainNode->find(strSection); + if(iterSection != m_pMainNode->end()) + { + attr_storage& rAttrs = (*iterSection).second; + std::pair pairRange; + + if(strAttr == _t("*")) + { + pairRange.first = rAttrs.begin(); + pairRange.second = rAttrs.end(); + } + else + pairRange = (*iterSection).second.equal_range(strAttr); + rAttrs.erase(pairRange.first, pairRange.second); + } + } +} + +void ini_cfg::parse_line(const tchar_t* pszLine) +{ + assert(pszLine); + if(!pszLine) + THROW(_t("Invalid parameter"), 0, 0, 0); + + tstring_t strLine = pszLine; + + // trim whitespaces + while(strLine.begin() != strLine.end() && string_tool::is_whitespace(*strLine.begin())) + { + strLine.erase(strLine.begin()); + } + while(strLine.rbegin() != strLine.rend() && string_tool::is_whitespace(*strLine.rbegin())) + { + strLine.erase(strLine.end() - 1); + } + + // detect line type + if(strLine.begin() == strLine.end()) + return; + if(strLine[0] == _t('[')) + { + // trim [ and ] + strLine.erase(strLine.begin()); + if(strLine.empty() || (*strLine.rbegin()) != _t(']')) + THROW(_t("Wrong section name"), 0, 0, 0); + strLine.erase(strLine.end() - 1); + + // a new section + m_strCurrentSection = strLine; + m_pMainNode->insert(ini_storage::value_type(strLine, attr_storage())); + } + else + { + // key=value + tstring_t::size_type stPos = strLine.find_first_of(_t('=')); + if(stPos != tstring_t::npos) + { + ini_storage::iterator iterSection = m_pMainNode->find(m_strCurrentSection); + if(iterSection == m_pMainNode->end()) + THROW(_t("Internal processing error. Section should already be included."), 0, 0, 0); + tstring_t strLeft, strRight; + strLeft.insert(strLeft.begin(), strLine.begin(), strLine.begin() + stPos); + strRight.insert(strRight.begin(), strLine.begin() + stPos + 1, strLine.end()); + (*iterSection).second.insert(attr_storage::value_type(strLeft, strRight)); + } + } +} + +bool ini_cfg::parse_property_name(const tchar_t* pszName, tstring_t& rstrSection, tstring_t& rstrName) +{ + // parse the path + tstring_t strPath = pszName; + tstring_t::size_type stPos = strPath.find_first_of(_t('/')); + if(stPos == tstring_t::npos) + return false; + tstring_t::size_type stPos2 = strPath.find_first_of(_t('/'), stPos + 1); + if(stPos2 != tstring_t::npos && stPos2 != stPos) + return false; // paths with two or more '/' are not supported + + rstrName.clear(); + rstrName.clear(); + rstrSection.insert(rstrSection.begin(), strPath.begin(), strPath.begin() + stPos); + rstrName.insert(rstrName.begin(), strPath.begin() + stPos + 1, strPath.end()); + + return true; +} + +END_ICPF_NAMESPACE Index: ext/libicpf/src/libicpf/cfg_ini.h =================================================================== diff -u --- ext/libicpf/src/libicpf/cfg_ini.h (revision 0) +++ ext/libicpf/src/libicpf/cfg_ini.h (revision 86310fdf8a767b700985ebd1b255004d9eb85fb7) @@ -0,0 +1,62 @@ +#ifndef __CFGINI_H__ +#define __CFGINI_H__ + +#include "gen_types.h" +#include "libicpf.h" +#include "config_base.h" + +BEGIN_ICPF_NAMESPACE + +/** Class provides the necessary base handlers for config class. +* It handles the ini data streams contained in the files, providing +* a way to set and retrieve data contained in the ini document. +*/ +class ini_cfg : public config_base +{ +public: + /** \name Construction/destruction/operators */ + /**@{*/ + ini_cfg(); ///< Standard constructor + ini_cfg(const ini_cfg& rSrc); ///< Copy constructor + virtual ~ini_cfg(); ///< Standard destructor + /**@}*/ + + /** \name File operations */ + /**@{*/ + /// Reads the xml document from the specified file + virtual void read(const tchar_t* pszPath); + /// Saves the internal data to a specified file as the xml document + virtual void save(const tchar_t* pszPath); + /**@}*/ + + /** \name Key and value handling */ + /**@{*/ + /// Searches for a specified key (given all the path to a specific string) + virtual ptr_t find(const tchar_t* pszName); + /// Searches for the next string + virtual const tchar_t* find_next(ptr_t pFindHandle); + /// Closes the search operation + virtual void find_close(ptr_t pFindHandle); + + /// Sets a value for a given key + virtual void set_value(const tchar_t* pszName, const tchar_t* pszValue, actions a=action_add); + /// Clear values for a given property name + virtual void clear(const tchar_t* pszName); + /// Clears all entries + virtual void clear(); + /**@}*/ + +private: + /// Parses a single line of the ini file + void parse_line(const tchar_t* pszLine); + + /// Parses the name of the property + bool parse_property_name(const tchar_t* pszName, tstring_t& rstrSection, tstring_t& rstrName); +protected: + ptr_t m_hMainNode; ///< Handle to the internal ini storage + tstring_t m_strCurrentSection; ///< Current section of the config file +}; + +END_ICPF_NAMESPACE + +#endif Index: ext/libicpf/src/libicpf/config_base.h =================================================================== diff -u -rb337c059691a6940b52a86388ff427c734be8eb6 -r86310fdf8a767b700985ebd1b255004d9eb85fb7 --- ext/libicpf/src/libicpf/config_base.h (.../config_base.h) (revision b337c059691a6940b52a86388ff427c734be8eb6) +++ ext/libicpf/src/libicpf/config_base.h (.../config_base.h) (revision 86310fdf8a767b700985ebd1b255004d9eb85fb7) @@ -1,26 +1,26 @@ -#ifndef __CONFIG_BASE_H__ -#define __CONFIG_BASE_H__ - -#include "gen_types.h" -#include "libicpf.h" - -BEGIN_ICPF_NAMESPACE - -/** Base config class. Manages the data that can be directly - * read or written to the storage medium (xml file, ini file, - * registry, ...). - */ -class config_base -{ -public: - /// Actions used when setting value - enum actions - { - action_add, - action_replace - }; - -public: +#ifndef __CONFIG_BASE_H__ +#define __CONFIG_BASE_H__ + +#include "gen_types.h" +#include "libicpf.h" + +BEGIN_ICPF_NAMESPACE + +/** Base config class. Manages the data that can be directly + * read or written to the storage medium (xml file, ini file, + * registry, ...). + */ +class config_base +{ +public: + /// Actions used when setting value + enum actions + { + action_add, + action_replace + }; + +public: /** \name File operations */ /**@{*/ /// Reads the xml document from the specified file @@ -43,8 +43,8 @@ /// Clear values for a given property name virtual void clear(const tchar_t* pszName) = 0; /**@}*/ -}; - -END_ICPF_NAMESPACE - -#endif +}; + +END_ICPF_NAMESPACE + +#endif Index: ext/libicpf/src/libicpf/libicpf.vc90.vcproj =================================================================== diff -u -rfda6c114112990e142835c8f75ffa44cd8813733 -r86310fdf8a767b700985ebd1b255004d9eb85fb7 --- ext/libicpf/src/libicpf/libicpf.vc90.vcproj (.../libicpf.vc90.vcproj) (revision fda6c114112990e142835c8f75ffa44cd8813733) +++ ext/libicpf/src/libicpf/libicpf.vc90.vcproj (.../libicpf.vc90.vcproj) (revision 86310fdf8a767b700985ebd1b255004d9eb85fb7) @@ -676,6 +676,10 @@ > + + @@ -750,6 +754,10 @@ > + +