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
This commit is contained in:
parent
53e9d3aa44
commit
b77dfdc9e3
6 changed files with 1063 additions and 102 deletions
|
@ -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"
|
||||||
|
|
|
@ -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 \
|
||||||
|
|
|
@ -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
Normal file
1010
src/tinyformat.h
Normal file
File diff suppressed because it is too large
Load diff
78
src/util.cpp
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
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
|
|
||||||
macro to keep similar semantics.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** 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, ...);
|
|
||||||
/** Overload strprintf for std::string, to be able to use it with _ (translation).
|
|
||||||
* This will not support GCC format type warnings (-Wformat) so be careful.
|
|
||||||
*/
|
*/
|
||||||
std::string real_strprintf(const std::string &format, int dummy, ...);
|
#define MAKE_ERROR_AND_LOG_FUNC(n) \
|
||||||
#define strprintf(format, ...) real_strprintf(format, 0, __VA_ARGS__)
|
/* Print to debug.log if -debug=category switch is given OR category is NULL. */ \
|
||||||
std::string vstrprintf(const char *format, va_list ap);
|
template<TINYFORMAT_ARGTYPES(n)> \
|
||||||
|
static inline int LogPrint(const char* category, const char* format, TINYFORMAT_VARARGS(n)) \
|
||||||
|
{ \
|
||||||
|
if(!LogAcceptCategory(category)) return 0; \
|
||||||
|
return LogPrintStr(tfm::format(format, TINYFORMAT_PASSARGS(n))); \
|
||||||
|
} \
|
||||||
|
/* 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
|
||||||
|
*/
|
||||||
|
static inline int LogPrint(const char* category, const char* format)
|
||||||
|
{
|
||||||
|
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…
Reference in a new issue