// // AUTHOR // Stef Walter // // LICENSE // This software is in the public domain. // // The software is provided "as is", without warranty of any kind, // express or implied, including but not limited to the warranties // of merchantability, fitness for a particular purpose, and // noninfringement. In no event shall the author(s) be liable for any // claim, damages, or other liability, whether in an action of // contract, tort, or otherwise, arising from, out of, or in connection // with the software or the use or other dealings in the software. // // SUPPORT // Send bug reports to: // // MyString.h // ////////////////////////////////////////////////////////////////////////////// #if !defined(_MYSTRING_H_) #define _MYSTRING_H_ ////////////////////////////////////////////////////////////////////////////// #include #include #include #include #ifndef ASSERT #ifdef ATLASSERT #define ASSERT ATLASSERT #else #include #define ASSERT assert #endif #endif #pragma warning(push) #pragma warning(disable:4786) // Disable warning for names > 256 ////////////////////////////////////////////////////////////////////////////// template class stringT : public std::basic_string // T should be either char or wchar_t { public: // Constructors stringT() : std::basic_string() { } stringT(const stringT& strInput) : std::basic_string(strInput) { } stringT(const std::basic_string& strInput) : std::basic_string(strInput) { } stringT(const std::basic_string& strInput, size_type pos, size_type n) : std::basic_string(strInput, pos, n) { } stringT(const std::basic_string::const_iterator first, const std::basic_string::const_iterator last) : std::basic_string(first, last) { } stringT(const T* strInput) : std::basic_string(strInput) { } stringT(const T* strInput, size_type n) : std::basic_string(strInput, n) { } #ifdef _INC_COMDEF stringT(_bstr_t bstr) { (*this) = (const T*)bstr; } #endif stringT(T ch, int nRepeat = 1) : std::basic_string(nRepeat, ch) { } // Other Conversions stringT& make_upper() { std::ctype c; T* p = get_buffer(); c.toupper(p, p + size()); release_buffer(); return *this; } stringT upper() const { stringT sTmp(*this); sTmp.make_upper(); return sTmp; } stringT& make_lower() { std::ctype c; T* p = get_buffer(); c.tolower(p, p + size()); release_buffer(); return *this; } stringT lower() const { stringT sTmp(*this); sTmp.make_lower(); return sTmp; } void trim_left() { // TODO: Optimize while(!empty() && _istspace(at(0))) erase(0, 1); } void trim_right() { // TODO: Optimize while(!empty() && _istspace(at(length()-1))) erase(length() - 1, 1); } void trim() { trim_left(); trim_right(); } const stringT& format(const T* pszFormat, ...) { va_list vl; va_start(vl, pszFormat); format_v(pszFormat, vl); va_end(vl); return *this; } #ifdef _WINDOWS_ const stringT& format(HINSTANCE hInst, UINT nID, ... ) { stringT sTemp; sTemp.load_string(hInst, nID); va_list vl; va_start(vl, nID); format_v(sTemp, vl); va_end(vl); return *this; } #ifdef __ATLBASE_H__ const stringT& format(UINT nID, ... ) { stringT sTemp; sTemp.load_string(nID); va_list vl; va_start(vl, nID); format_v(sTemp, vl); va_end(vl); return *this; } #endif // __ATLBASE_H__ #endif void format_v(const char* pszFormat, va_list vl) { // Copied Code.... // Doesn't have all the features of CString::Format() T* pszTemp = NULL; size_t nBufferSize = 32; int nRetVal = -1; do { // Double the buffer size for next time around nBufferSize += nBufferSize; delete [] pszTemp; pszTemp = new T [nBufferSize]; nRetVal = _vsnprintf(pszTemp, nBufferSize, pszFormat, vl); } while (nRetVal < 0); *this = pszTemp; delete [] pszTemp; return; } void format_v(const wchar_t* pszFormat, va_list vl) { // Copied Code.... // Doesn't have all the features of CString::Format() T* pszTemp = NULL; size_t nBufferSize = 32; int nRetVal = -1; do { // Double the buffer size for next time around nBufferSize += nBufferSize; delete [] pszTemp; pszTemp = new T [nBufferSize]; nRetVal = _vsnwprintf(pszTemp, nBufferSize, pszFormat, vl); } while (nRetVal < 0); *this = pszTemp; delete [] pszTemp; return; } int replace(const std::basic_string& sFind, const std::basic_string& sReplace, bool bMultiple = true, size_type nStart = 0) { stringT sTemp = *this; int nReplaced = 0; if((nStart = sTemp.find(sFind, nStart)) != npos) { sTemp.erase(nStart, sFind.length()); sTemp.insert(nStart, sReplace); nReplaced++; } while(bMultiple && (nStart = sTemp.find(sFind, nStart + 1)) != npos) { sTemp.erase(nStart, sFind.length()); sTemp.insert(nStart, sReplace); nReplaced++; } *this = sTemp; return nReplaced; } // Operators T operator[](int nIndex) const { return at(nIndex); }; #ifdef _INC_COMDEF operator _bstr_t() const { return _bstr_t(c_str()); }; #endif operator const T*() const { return c_str(); }; // Buffer Operations // Derived code from MFC CString T* get_buffer(size_t sz = npos) { if(sz == npos) sz = size(); resize(sz + 1); // Make sure we generate a write command // so we have no extra references // TODO: Does basic_string use reference counting? // (much later) A: Yes it does! Reference is in the bytes before data at(sz) = 0; return const_cast(data()); } void release_buffer() { if(!empty()) { // Make sure we generate a write command // Find the null terminated end for(string::size_type i = 0; i < capacity() && i < size(); i++) if(at(i) == 0) break; ASSERT(i != capacity()); resize(i); } } void clear() { resize(0); } #ifdef _WINDOWS_ bool load_string(HINSTANCE hInst, unsigned int nID) { string::size_type nSize = 0x80; do { release_buffer(); nSize *= 2; } while(load_string(hInst, nID, get_buffer(nSize), nSize) == nSize); release_buffer(); return nSize > 0; } #endif // WIN32 #ifdef __ATLBASE_H__ bool load_string(unsigned int nID) { string::size_type nSize = 0x80; do { release_buffer(); nSize *= 2; } while(load_string(_Module.m_hInstResource, nID, get_buffer(nSize), nSize) == nSize); release_buffer(); return nSize > 0; } #endif // __ATLBASE_H__ protected: #ifdef _WINDOWS_ static int load_string(HINSTANCE hInst, UINT nID, char* pBuff, size_t nSize) { return ::LoadStringA(hInst, nID, pBuff, nSize); } static int load_string(HINSTANCE hInst, UINT nID, wchar_t* pBuff, size_t nSize) { #ifdef _UNICODE return ::LoadStringW(hInst, nID, pBuff, nSize); #else char* pABuff = new char[nSize]; if(!pABuff) return 0; int nRet = load_string(hInst, nID, pABuff, nSize); if(nRet) { pBuff[0] = L'\0'; MultiByteToWideChar(GetACP(), 0, pABuff, -1, pBuff, nSize); } return nRet; #endif } #endif }; #ifndef _UNICODE typedef stringT string; #else typedef stringT string; #endif typedef stringT astring; typedef stringT wstring; template class cstringT { public: cstringT() { clear(); }; cstringT(const T* ptr, size_t len) { set(ptr, len); }; operator stringT() const { if(_Ptr) return stringT(_Ptr, _Len); else return stringT(); }; bool is_null() const { return _Ptr ? false : true; } // TODO: Maybe some validity checks void set(const T* ptr, size_t len) { _Ptr = ptr; _Len = len; } void clear() { _Ptr = 0; _Len = 0; } protected: const T* _Ptr; size_t _Len; }; #ifndef _UNICODE typedef cstringT cstring; #else typedef cstringT cstring; #endif typedef cstringT castring; typedef cstringT cwstring; #include #include template class string_arrayT : public std::vector { public: string_arrayT(const std::vector & x) : std::vector(x) {}; string_arrayT(string_arrayT & x) : std::vector(x) {}; string_arrayT(std::vector::const_iterator first, std::vector::const_iterator last, const std::vector::allocator_type& al = std::vector::allocator_type()) : std::vector(first, last, al) {}; explicit string_arrayT(const const std::vector::allocator_type& al = std::vector::allocator_type()) : std::vector(al) {}; explicit string_arrayT(std::vector::size_type n, const std::vector::value_type& v = std::vector::value_type(), const std::vector::allocator_type& al = std::vector::allocator_type()) : std::vector(n, v, al) {}; std::vector::size_type split(S sIn, S sDelim, bool bTrim = false) { S::size_type start = 0; S::size_type ed = 0; std::vector::size_type cnt = 0; S::size_type lenDelim = sDelim.size(); S sTemp; if(lenDelim == 0) { if(bTrim) sIn.trim(); push_back(sIn); return 1; } while(ed != string::npos) { ed = sIn.find(sDelim, start); if(ed == string::npos) sTemp = sIn.substr(start); else sTemp = sIn.substr(start, ed - start); if(bTrim) sTemp.trim(); push_back(sTemp); cnt++; start = ed + lenDelim; } return cnt; } S join(S sDelim) const { S sTemp; const_iterator it = begin(); const_iterator ed = end(); while(it != ed) { sTemp += *it; it++; } return sTemp; } class no_case { public: no_case(const S& s) : _str(s) { _str.make_lower(); } bool operator()(const S& s) { return s.lower() == _str; } protected: S _str; }; bool has(S sVal, bool bCase = true) const { return find(sVal, bCase) != end(); } const_iterator find(S sVal, bool bCase = true) const { if(bCase) return std::find(begin(), end(), sVal); else { no_case fndr(sVal); return std::find_if(begin(), end(), fndr); } } iterator find(S sVal, bool bCase = true) { if(bCase) return std::find(begin(), end(), sVal); else { no_case fndr(sVal); return std::find_if(begin(), end(), fndr); } } }; typedef string_arrayT< string > string_array; typedef string_arrayT< wstring > wstring_array; ////////////////////////////////////////////////////////////////////////////// #pragma warning( pop ) #endif // !defined(_MYSTRING_H_)