moved string formatting into CStringUtil from CLog and added
methods for format positional string arguments.
This commit is contained in:
parent
8334d987f5
commit
1fd8e25f7d
|
@ -1,4 +1,5 @@
|
||||||
#include "CLog.h"
|
#include "CLog.h"
|
||||||
|
#include "CString.h"
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
@ -82,8 +83,9 @@ CLog::print(const char* fmt, ...)
|
||||||
char stack[1024];
|
char stack[1024];
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
char* buffer = vsprint(pad, stack,
|
char* buffer = CStringUtil::vsprint(stack,
|
||||||
sizeof(stack) / sizeof(stack[0]), fmt, args);
|
sizeof(stack) / sizeof(stack[0]),
|
||||||
|
pad, g_newlineLength, fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
// output buffer
|
// output buffer
|
||||||
|
@ -119,8 +121,9 @@ CLog::printt(const char* file, int line, const char* fmt, ...)
|
||||||
// print to buffer, leaving space for a newline at the end
|
// print to buffer, leaving space for a newline at the end
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
char* buffer = vsprint(pad, stack,
|
char* buffer = CStringUtil::vsprint(stack,
|
||||||
sizeof(stack) / sizeof(stack[0]), fmt, args);
|
sizeof(stack) / sizeof(stack[0]),
|
||||||
|
pad, g_newlineLength, fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
// print the prefix to the buffer. leave space for priority label.
|
// print the prefix to the buffer. leave space for priority label.
|
||||||
|
@ -227,8 +230,9 @@ CLog::output(int priority, char* msg)
|
||||||
int n = -g_prioritySuffixLength;
|
int n = -g_prioritySuffixLength;
|
||||||
if (priority >= 0) {
|
if (priority >= 0) {
|
||||||
n = strlen(g_priority[priority]);
|
n = strlen(g_priority[priority]);
|
||||||
sprintf(msg + g_maxPriorityLength - n,
|
strcpy(msg + g_maxPriorityLength - n, g_priority[priority]);
|
||||||
"%s:", g_priority[priority]);
|
msg[g_maxPriorityLength + 0] = ':';
|
||||||
|
msg[g_maxPriorityLength + 1] = ' ';
|
||||||
msg[g_maxPriorityLength + 1] = ' ';
|
msg[g_maxPriorityLength + 1] = ' ';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,31 +250,6 @@ CLog::output(int priority, char* msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char*
|
|
||||||
CLog::vsprint(int pad, char* buffer, int len, const char* fmt, va_list args)
|
|
||||||
{
|
|
||||||
assert(len > 0);
|
|
||||||
|
|
||||||
// try writing to input buffer
|
|
||||||
int n;
|
|
||||||
if (len >= pad) {
|
|
||||||
n = vsnprintf(buffer + pad, len - pad, fmt, args);
|
|
||||||
if (n >= 0 && n <= len - pad + g_newlineLength)
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
// start allocating buffers until we write the whole string
|
|
||||||
buffer = NULL;
|
|
||||||
do {
|
|
||||||
delete[] buffer;
|
|
||||||
len *= 2;
|
|
||||||
buffer = new char[len + pad];
|
|
||||||
n = vsnprintf(buffer + pad, len - pad, fmt, args);
|
|
||||||
} while (n < 0 || n > len - pad + g_newlineLength);
|
|
||||||
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if WINDOWS_LIKE
|
#if WINDOWS_LIKE
|
||||||
|
|
||||||
static DWORD s_thread = 0;
|
static DWORD s_thread = 0;
|
||||||
|
|
|
@ -65,8 +65,6 @@ private:
|
||||||
static void dummyLock(bool);
|
static void dummyLock(bool);
|
||||||
static int getMaxPriority();
|
static int getMaxPriority();
|
||||||
static void output(int priority, char* msg);
|
static void output(int priority, char* msg);
|
||||||
static char* vsprint(int pad, char*, int len, const char*, va_list);
|
|
||||||
static int nprint(const char*, va_list);
|
|
||||||
#if WINDOWS_LIKE
|
#if WINDOWS_LIKE
|
||||||
static void openConsole();
|
static void openConsole();
|
||||||
#endif
|
#endif
|
||||||
|
|
156
base/CString.cpp
156
base/CString.cpp
|
@ -1,7 +1,159 @@
|
||||||
#include "CString.h"
|
#include "CString.h"
|
||||||
|
#include "stdvector.h"
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
#include <algorithm>
|
#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
|
// CStringUtil::CaselessCmp
|
||||||
//
|
//
|
||||||
|
@ -11,7 +163,7 @@ CStringUtil::CaselessCmp::cmpEqual(
|
||||||
const CString::value_type& a,
|
const CString::value_type& a,
|
||||||
const CString::value_type& b)
|
const CString::value_type& b)
|
||||||
{
|
{
|
||||||
// FIXME -- use std::tolower but not in all versions of libstdc++
|
// FIXME -- use std::tolower but not in all versions of libstdc++ have it
|
||||||
return tolower(a) == tolower(b);
|
return tolower(a) == tolower(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +172,7 @@ CStringUtil::CaselessCmp::cmpLess(
|
||||||
const CString::value_type& a,
|
const CString::value_type& a,
|
||||||
const CString::value_type& b)
|
const CString::value_type& b)
|
||||||
{
|
{
|
||||||
// FIXME -- use std::tolower but not in all versions of libstdc++
|
// FIXME -- use std::tolower but not in all versions of libstdc++ have it
|
||||||
return tolower(a) < tolower(b);
|
return tolower(a) < tolower(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,41 @@
|
||||||
#ifndef CSTRING_H
|
#ifndef CSTRING_H
|
||||||
#define CSTRING_H
|
#define CSTRING_H
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
#include "stdpre.h"
|
#include "stdpre.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "stdpost.h"
|
#include "stdpost.h"
|
||||||
|
|
||||||
// use to get appropriate type for string constants. it depends on
|
|
||||||
// the internal representation type of CString.
|
|
||||||
#define _CS(_x) _x
|
|
||||||
|
|
||||||
typedef std::string CString;
|
typedef std::string CString;
|
||||||
|
|
||||||
class CStringUtil {
|
class CStringUtil {
|
||||||
public:
|
public:
|
||||||
|
// format a string using positional arguments. fmt has literal
|
||||||
|
// characters and conversion specifications introduced by `%':
|
||||||
|
// %% literal `%'
|
||||||
|
// %{n} positional element n, n a positive integer, {} are literal
|
||||||
|
// all arguments in the variable list are const char*. positional
|
||||||
|
// elements are indexed from 1.
|
||||||
|
static CString format(const char* fmt, ...);
|
||||||
|
static CString vformat(const char* fmt, va_list);
|
||||||
|
|
||||||
|
// print a string using printf-style formatting
|
||||||
|
static CString print(const char* fmt, ...);
|
||||||
|
static CString vprint(const char* fmt, va_list);
|
||||||
|
|
||||||
|
// like print but print into a given buffer. if the resulting string
|
||||||
|
// will not fit into the buffer then a new buffer is allocated and
|
||||||
|
// returned, otherwise the input buffer is returned. the caller must
|
||||||
|
// delete[] the returned buffer if is not the passed-in buffer.
|
||||||
|
//
|
||||||
|
// prefix and suffix must be >= 0. exactly prefix characters and
|
||||||
|
// at least suffix characters are available in the buffer before
|
||||||
|
// and after the printed string, respectively. bufferLength is the
|
||||||
|
// length of buffer and should not be adjusted by the caller to
|
||||||
|
// account for prefix or suffix.
|
||||||
|
static char* vsprint(char* buffer, int bufferLength,
|
||||||
|
int prefix, int suffix, const char* fmt, va_list);
|
||||||
|
|
||||||
class CaselessCmp {
|
class CaselessCmp {
|
||||||
public:
|
public:
|
||||||
bool operator()(const CString&, const CString&) const;
|
bool operator()(const CString&, const CString&) const;
|
||||||
|
|
Loading…
Reference in New Issue