#include "CString.h" #include "common.h" #include "stdvector.h" #include #include #include #include #if WINDOWS_LIKE #define WIN32_LEAN_AND_MEAN #include #define vsnprintf _vsnprintf #endif // // CStringUtil // CString CStringUtil::format(const char* fmt, ...) { va_list args; va_start(args, fmt); CString result = vformat(fmt, args); va_end(args); return result; } CString CStringUtil::vformat(const char* fmt, va_list args) { // find highest indexed substitution and the locations of substitutions std::vector pos; std::vector width; std::vector index; int maxIndex = 0; for (const char* scan = fmt; *scan != '\0'; ++scan) { if (*scan == '%') { ++scan; if (*scan == '\0') { break; } else if (*scan == '%') { // literal index.push_back(0); pos.push_back(static_cast(scan - 1 - fmt)); width.push_back(2); } else if (*scan == '{') { // get argument index char* end; int i = static_cast(strtol(scan + 1, &end, 10)); if (*end != '}') { // invalid index -- ignore scan = end - 1; } else { index.push_back(i); pos.push_back(static_cast(scan - 1 - fmt)); width.push_back(static_cast(end - scan + 2)); if (i > maxIndex) { maxIndex = i; } scan = end; } } else { // improper escape -- ignore } } } // get args std::vector value; std::vector length; value.push_back("%"); length.push_back(1); for (int i = 0; i < maxIndex; ++i) { const char* arg = va_arg(args, const char*); value.push_back(arg); length.push_back(strlen(arg)); } // compute final length size_t resultLength = strlen(fmt); const int n = static_cast(pos.size()); for (int i = 0; i < n; ++i) { resultLength -= width[i]; resultLength += length[index[i]]; } // substitute CString result; result.reserve(resultLength); size_t src = 0; for (int i = 0; i < n; ++i) { result.append(fmt + src, pos[i] - src); result.append(value[index[i]]); src = pos[i] + width[i]; } result.append(fmt + src); return result; } CString CStringUtil::print(const char* fmt, ...) { va_list args; va_start(args, fmt); CString result = vprint(fmt, args); va_end(args); return result; } CString CStringUtil::vprint(const char* fmt, va_list args) { char tmp[1024]; char* buffer = vsprint(tmp, sizeof(tmp) / sizeof(tmp[0]), 0, 0, fmt, args); if (buffer == tmp) { return buffer; } else { CString result(buffer); delete[] buffer; return result; } } char* CStringUtil::vsprint(char* buffer, int len, int prefix, int suffix, const char* fmt, va_list args) { assert(len > 0); // try writing to input buffer int n; if (buffer != NULL && len >= prefix + suffix) { n = vsnprintf(buffer + prefix, len - (prefix + suffix), fmt, args); if (n >= 0 && n <= len - (prefix + suffix)) return buffer; } // start allocating buffers until we write the whole string buffer = NULL; do { delete[] buffer; len *= 2; buffer = new char[len + (prefix + suffix)]; n = vsnprintf(buffer + prefix, len - (prefix + suffix), fmt, args); } while (n < 0 || n > len - (prefix + suffix)); return buffer; } // // CStringUtil::CaselessCmp // bool CStringUtil::CaselessCmp::cmpEqual( const CString::value_type& a, const CString::value_type& b) { // FIXME -- use std::tolower but not in all versions of libstdc++ have it return tolower(a) == tolower(b); } bool CStringUtil::CaselessCmp::cmpLess( const CString::value_type& a, const CString::value_type& b) { // FIXME -- use std::tolower but not in all versions of libstdc++ have it return tolower(a) < tolower(b); } bool CStringUtil::CaselessCmp::less(const CString& a, const CString& b) { return std::lexicographical_compare( a.begin(), a.end(), b.begin(), b.end(), &CStringUtil::CaselessCmp::cmpLess); } bool CStringUtil::CaselessCmp::equal(const CString& a, const CString& b) { return !(less(a, b) || less(b, a)); } bool CStringUtil::CaselessCmp::operator()(const CString& a, const CString& b) const { return less(a, b); }