Browse Source

Typesafe strprintf/error/LogPrint functions

Switch to tinyformat-based formatting.

Tinyformat is a typesafe drop-in replacement for C99 printf functions:
https://github.com/c42f/tinyformat
pull/145/head
Wladimir J. van der Laan 11 years ago
parent
commit
b77dfdc9e3
  1. 2
      configure.ac
  2. 1
      src/Makefile.am
  3. 2
      src/main.cpp
  4. 1010
      src/tinyformat.h
  5. 78
      src/util.cpp
  6. 72
      src/util.h

2
configure.ac

@ -189,7 +189,7 @@ case $host in
AC_MSG_ERROR("windres not found") AC_MSG_ERROR("windres not found")
fi fi
CPPFLAGS="$CPPFLAGS -D_MT -DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB -D__USE_MINGW_ANSI_STDIO" CPPFLAGS="$CPPFLAGS -D_MT -DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB"
LEVELDB_TARGET_FLAGS="TARGET_OS=OS_WINDOWS_CROSSCOMPILE" LEVELDB_TARGET_FLAGS="TARGET_OS=OS_WINDOWS_CROSSCOMPILE"
if test "x$CXXFLAGS_overridden" = "xno"; then if test "x$CXXFLAGS_overridden" = "xno"; then
CXXFLAGS="$CXXFLAGS -w" CXXFLAGS="$CXXFLAGS -w"

1
src/Makefile.am

@ -60,6 +60,7 @@ BITCOIN_CORE_H = \
serialize.h \ serialize.h \
sync.h \ sync.h \
threadsafety.h \ threadsafety.h \
tinyformat.h \
txdb.h \ txdb.h \
txmempool.h \ txmempool.h \
ui_interface.h \ ui_interface.h \

2
src/main.cpp

@ -1884,7 +1884,7 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
pindex = pindex->pprev; pindex = pindex->pprev;
} }
if (nUpgraded > 0) if (nUpgraded > 0)
LogPrintf("SetBestChain: %d of last 100 blocks above version %d\n", nUpgraded, CBlock::CURRENT_VERSION); LogPrintf("SetBestChain: %d of last 100 blocks above version %d\n", nUpgraded, (int)CBlock::CURRENT_VERSION);
if (nUpgraded > 100/2) if (nUpgraded > 100/2)
// strMiscWarning is read by GetWarnings(), called by Qt and the JSON-RPC code to warn the user: // strMiscWarning is read by GetWarnings(), called by Qt and the JSON-RPC code to warn the user:
strMiscWarning = _("Warning: This version is obsolete, upgrade required!"); strMiscWarning = _("Warning: This version is obsolete, upgrade required!");

1010
src/tinyformat.h

File diff suppressed because it is too large

78
src/util.cpp

@ -235,12 +235,12 @@ static void DebugPrintInit()
mutexDebugLog = new boost::mutex(); mutexDebugLog = new boost::mutex();
} }
int LogPrint(const char* category, const char* pszFormat, ...) bool LogAcceptCategory(const char* category)
{ {
if (category != NULL) if (category != NULL)
{ {
if (!fDebug) if (!fDebug)
return 0; return false;
// Give each thread quick access to -debug settings. // Give each thread quick access to -debug settings.
// This helps prevent issues debugging global destructors, // This helps prevent issues debugging global destructors,
@ -258,17 +258,18 @@ int LogPrint(const char* category, const char* pszFormat, ...)
// if not debugging everything and not debugging specific category, LogPrint does nothing. // if not debugging everything and not debugging specific category, LogPrint does nothing.
if (setCategories.count(string("")) == 0 && if (setCategories.count(string("")) == 0 &&
setCategories.count(string(category)) == 0) setCategories.count(string(category)) == 0)
return 0; return false;
} }
return true;
}
int LogPrintStr(const std::string &str)
{
int ret = 0; // Returns total number of characters written int ret = 0; // Returns total number of characters written
if (fPrintToConsole) if (fPrintToConsole)
{ {
// print to console // print to console
va_list arg_ptr; ret = fwrite(str.data(), 1, str.size(), stdout);
va_start(arg_ptr, pszFormat);
ret += vprintf(pszFormat, arg_ptr);
va_end(arg_ptr);
} }
else if (fPrintToDebugLog) else if (fPrintToDebugLog)
{ {
@ -291,76 +292,17 @@ int LogPrint(const char* category, const char* pszFormat, ...)
// Debug print useful for profiling // Debug print useful for profiling
if (fLogTimestamps && fStartedNewLine) if (fLogTimestamps && fStartedNewLine)
ret += fprintf(fileout, "%s ", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()).c_str()); ret += fprintf(fileout, "%s ", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()).c_str());
if (pszFormat[strlen(pszFormat) - 1] == '\n') if (!str.empty() && str[str.size()-1] == '\n')
fStartedNewLine = true; fStartedNewLine = true;
else else
fStartedNewLine = false; fStartedNewLine = false;
va_list arg_ptr; ret = fwrite(str.data(), 1, str.size(), fileout);
va_start(arg_ptr, pszFormat);
ret += vfprintf(fileout, pszFormat, arg_ptr);
va_end(arg_ptr);
} }
return ret; return ret;
} }
string vstrprintf(const char *format, va_list ap)
{
char buffer[50000];
char* p = buffer;
int limit = sizeof(buffer);
int ret;
while (true)
{
va_list arg_ptr;
va_copy(arg_ptr, ap);
ret = vsnprintf(p, limit, format, arg_ptr);
va_end(arg_ptr);
if (ret >= 0 && ret < limit)
break;
if (p != buffer)
delete[] p;
limit *= 2;
p = new char[limit];
if (p == NULL)
throw std::bad_alloc();
}
string str(p, p+ret);
if (p != buffer)
delete[] p;
return str;
}
string real_strprintf(const char *format, int dummy, ...)
{
va_list arg_ptr;
va_start(arg_ptr, dummy);
string str = vstrprintf(format, arg_ptr);
va_end(arg_ptr);
return str;
}
string real_strprintf(const std::string &format, int dummy, ...)
{
va_list arg_ptr;
va_start(arg_ptr, dummy);
string str = vstrprintf(format.c_str(), arg_ptr);
va_end(arg_ptr);
return str;
}
bool error(const char *format, ...)
{
va_list arg_ptr;
va_start(arg_ptr, format);
std::string str = vstrprintf(format, arg_ptr);
va_end(arg_ptr);
LogPrintf("ERROR: %s\n", str.c_str());
return false;
}
void ParseString(const string& str, char c, vector<string>& v) void ParseString(const string& str, char c, vector<string>& v)
{ {
if (str.empty()) if (str.empty())

72
src/util.h

@ -12,6 +12,7 @@
#include "compat.h" #include "compat.h"
#include "serialize.h" #include "serialize.h"
#include "tinyformat.h"
#include <cstdio> #include <cstdio>
#include <exception> #include <exception>
@ -99,21 +100,6 @@ inline void MilliSleep(int64_t n)
#endif #endif
} }
/* This GNU C extension enables the compiler to check the format string against the parameters provided.
* X is the number of the "format string" parameter, and Y is the number of the first variadic parameter.
* Parameters count from 1.
*/
#ifdef __GNUC__
#define ATTR_WARN_PRINTF(X,Y) __attribute__((format(gnu_printf,X,Y)))
#else
#define ATTR_WARN_PRINTF(X,Y)
#endif
extern std::map<std::string, std::string> mapArgs; extern std::map<std::string, std::string> mapArgs;
@ -130,27 +116,49 @@ extern volatile bool fReopenDebugLog;
void RandAddSeed(); void RandAddSeed();
void RandAddSeedPerfmon(); void RandAddSeedPerfmon();
// Print to debug.log if -debug=category switch is given OR category is NULL. /* Return true if log accepts specified category */
int ATTR_WARN_PRINTF(2,3) LogPrint(const char* category, const char* pszFormat, ...); bool LogAcceptCategory(const char* category);
/* Send a string to the log output */
int LogPrintStr(const std::string &str);
#define strprintf tfm::format
#define LogPrintf(...) LogPrint(NULL, __VA_ARGS__) #define LogPrintf(...) LogPrint(NULL, __VA_ARGS__)
/* /* When we switch to C++11, this can be switched to variadic templates instead
Rationale for the real_strprintf / strprintf construction: * of this macro-based construction (see tinyformat.h).
It is not allowed to use va_start with a pass-by-reference argument. */
(C++ standard, 18.7, paragraph 3). Use a dummy argument to work around this, and use a #define MAKE_ERROR_AND_LOG_FUNC(n) \
macro to keep similar semantics. /* Print to debug.log if -debug=category switch is given OR category is NULL. */ \
*/ template<TINYFORMAT_ARGTYPES(n)> \
static inline int LogPrint(const char* category, const char* format, TINYFORMAT_VARARGS(n)) \
/** Overload strprintf for char*, so that GCC format type warnings can be given */ { \
std::string ATTR_WARN_PRINTF(1,3) real_strprintf(const char *format, int dummy, ...); if(!LogAcceptCategory(category)) return 0; \
/** Overload strprintf for std::string, to be able to use it with _ (translation). return LogPrintStr(tfm::format(format, TINYFORMAT_PASSARGS(n))); \
* This will not support GCC format type warnings (-Wformat) so be careful. } \
/* Log error and return false */ \
template<TINYFORMAT_ARGTYPES(n)> \
static inline bool error(const char* format, TINYFORMAT_VARARGS(n)) \
{ \
LogPrintStr("ERROR: " + tfm::format(format, TINYFORMAT_PASSARGS(n))); \
return false; \
}
TINYFORMAT_FOREACH_ARGNUM(MAKE_ERROR_AND_LOG_FUNC)
/* Zero-arg versions of logging and error, these are not covered by
* TINYFORMAT_FOREACH_ARGNUM
*/ */
std::string real_strprintf(const std::string &format, int dummy, ...); static inline int LogPrint(const char* category, const char* format)
#define strprintf(format, ...) real_strprintf(format, 0, __VA_ARGS__) {
std::string vstrprintf(const char *format, va_list ap); if(!LogAcceptCategory(category)) return 0;
return LogPrintStr(format);
}
static inline bool error(const char* format)
{
LogPrintStr(std::string("ERROR: ") + format);
return false;
}
bool ATTR_WARN_PRINTF(1,2) error(const char *format, ...);
void LogException(std::exception* pex, const char* pszThread); void LogException(std::exception* pex, const char* pszThread);
void PrintException(std::exception* pex, const char* pszThread); void PrintException(std::exception* pex, const char* pszThread);

Loading…
Cancel
Save