barrier/lib/base/CString.cpp
crs fee4095624 Reorganized source tree. Moved client.cpp into cmd/synergy as
synergy.cpp and server.cpp into cmd/synergyd as synergyd.cpp.
Moved and renamed related files.  Moved remaining source files
into lib/....  Modified and added makefiles as appropriate.
Result is that library files are under lib with each library
in its own directory and program files are under cmd with each
command in its own directory.
2002-07-30 16:52:46 +00:00

200 lines
4.1 KiB
C++

#include "CString.h"
#include "common.h"
#include "stdvector.h"
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#if WINDOWS_LIKE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#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<size_t> pos;
std::vector<size_t> width;
std::vector<int> 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<int>(scan - 1 - fmt));
width.push_back(2);
}
else if (*scan == '{') {
// get argument index
char* end;
int i = static_cast<int>(strtol(scan + 1, &end, 10));
if (*end != '}') {
// invalid index -- ignore
scan = end - 1;
}
else {
index.push_back(i);
pos.push_back(static_cast<int>(scan - 1 - fmt));
width.push_back(static_cast<int>(end - scan + 2));
if (i > maxIndex) {
maxIndex = i;
}
scan = end;
}
}
else {
// improper escape -- ignore
}
}
}
// get args
std::vector<const char*> value;
std::vector<size_t> 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<int>(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);
}