moved string formatting into CStringUtil from CLog and added

methods for format positional string arguments.
This commit is contained in:
crs 2002-07-25 17:23:35 +00:00
parent 8334d987f5
commit 1fd8e25f7d
4 changed files with 191 additions and 39 deletions

View File

@ -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;

View File

@ -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

View File

@ -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);
} }

View File

@ -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;