barrier/lib/base/CStringUtil.cpp

195 lines
4.2 KiB
C++

/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "CStringUtil.h"
#include "CArch.h"
#include "common.h"
#include "stdvector.h"
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
//
// 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*);
size_t len = strlen(arg);
value.push_back(arg);
length.push_back(len);
}
// 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, ...)
{
char tmp[1024];
char* buffer = tmp;
int len = (int)(sizeof(tmp) / sizeof(tmp[0]));
CString result;
while (buffer != NULL) {
// try printing into the buffer
va_list args;
va_start(args, fmt);
int n = ARCH->vsnprintf(buffer, len, fmt, args);
va_end(args);
// if the buffer wasn't big enough then make it bigger and try again
if (n < 0 || n > len) {
if (buffer != tmp) {
delete[] buffer;
}
len *= 2;
buffer = new char[len];
}
// if it was big enough then save the string and don't try again
else {
result = buffer;
if (buffer != tmp) {
delete[] buffer;
}
buffer = NULL;
}
}
return result;
}
//
// CStringUtil::CaselessCmp
//
bool
CStringUtil::CaselessCmp::cmpEqual(
const CString::value_type& a,
const CString::value_type& b)
{
// should 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)
{
// should 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);
}