diff --git a/common/StringUtil.cpp b/common/StringUtil.cpp index bf4965965..b1269bf46 100644 --- a/common/StringUtil.cpp +++ b/common/StringUtil.cpp @@ -15,9 +15,10 @@ */ #include "StringUtil.h" + #include -#include // for strncpy #include +#include // for strncpy #include #ifdef _WINDOWS @@ -26,8 +27,10 @@ #define snprintf _snprintf #define strncasecmp _strnicmp #define strcasecmp _stricmp + #else #include + #include #endif #ifndef va_copy @@ -37,53 +40,64 @@ // original source: // https://github.com/facebook/folly/blob/master/folly/String.cpp // -void StringFormat(std::string& output, const char* format, ...) +void vStringFormat(std::string& output, const char* format, va_list args) { - va_list args; - // Tru to the space at the end of output for our output buffer. - // Find out write point then inflate its size temporarily to its - // capacity; we will later shrink it to the size needed to represent - // the formatted string. If this buffer isn't large enough, we do a - // resize and try again. + va_list tmpargs; - const auto write_point = output.size(); - auto remaining = output.capacity() - write_point; - output.resize(output.capacity()); + va_copy(tmpargs,args); + int characters_used = vsnprintf(nullptr, 0, format, tmpargs); + va_end(tmpargs); - va_start(args, format); - int bytes_used = vsnprintf(&output[write_point], remaining, format,args); - va_end(args); - if (bytes_used < 0) { - + if (characters_used < 0) { + // Looks like we have an invalid format string. + // error out. std::string errorMessage("Invalid format string; snprintf returned negative with format string: "); errorMessage.append(format); throw std::runtime_error(errorMessage); - } - else if ((unsigned int)bytes_used < remaining) { - // There was enough room, just shrink and return. - output.resize(write_point + bytes_used); + } + else if ((unsigned int)characters_used > output.capacity()) { + output.resize(characters_used+1); + va_copy(tmpargs,args); + characters_used = vsnprintf(&output[0], output.capacity(), format, tmpargs); + va_end(tmpargs); + + if (characters_used < 0) { + // We shouldn't have a format error by this point, but I can't imagine what error we + // could have by this point. Still, error out and report it. + std::string errorMessage("Invalid format string or unknown vsnprintf error; vsnprintf returned negative with format string: "); + errorMessage.append(format); + + throw std::runtime_error(errorMessage); + } } else { - output.resize(write_point + bytes_used + 1); - remaining = bytes_used + 1; + output.resize(characters_used + 1); - va_start(args, format); - bytes_used = vsnprintf(&output[write_point], remaining, format, args); - va_end(args); - - if ((unsigned int)(bytes_used + 1) != remaining) { - - std::string errorMessage("vsnprint retry did not manage to work with format string: "); + va_copy(tmpargs,args); + characters_used = vsnprintf(&output[0], output.capacity(), format, tmpargs); + va_end(tmpargs); + + if (characters_used < 0) { + // We shouldn't have a format error by this point, but I can't imagine what error we + // could have by this point. still error out and report it. + std::string errorMessage("Invalid format string or unknown vsnprintf error; vsnprintf returned negative with format string: "); errorMessage.append(format); throw std::runtime_error(errorMessage); } - output.resize(write_point + bytes_used); } } +void StringFormat(std::string& output, const char* format, ...) +{ + va_list args; + va_start(args, format); + vStringFormat(output,format,args); + va_end(args); +} + // normal strncpy doesnt put a null term on copied strings, this one does // ref: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcecrt/htm/_wcecrt_strncpy_wcsncpy.asp char* strn0cpy(char* dest, const char* source, uint32 size) { diff --git a/common/StringUtil.h b/common/StringUtil.h index b7e389e65..423201247 100644 --- a/common/StringUtil.h +++ b/common/StringUtil.h @@ -17,8 +17,11 @@ #define _STRINGUTIL_H_ #include +#include #include "types.h" + +void vStringFormat(std::string& output, const char* format, va_list args); void StringFormat(std::string& output, const char* format, ...); ////////////////////////////////////////////////////////////////////// // diff --git a/common/debug.cpp b/common/debug.cpp index e164acbd6..b59882d46 100644 --- a/common/debug.cpp +++ b/common/debug.cpp @@ -2,6 +2,7 @@ #include #include +#include #include @@ -12,10 +13,11 @@ #define vsnprintf _vsnprintf #define strncasecmp _strnicmp #define strcasecmp _stricmp + #else + #include #include - #include #endif #include "../common/StringUtil.h" @@ -150,28 +152,36 @@ bool EQEMuLog::write(LogIDs id, const char *fmt, ...) { time( &aclock ); /* Get time in seconds */ newtime = localtime( &aclock ); /* Convert time to struct */ - if (dofile) + if (dofile) { #ifndef NO_PIDLOG fprintf(fp[id], "[%02d.%02d. - %02d:%02d:%02d] ", newtime->tm_mon+1, newtime->tm_mday, newtime->tm_hour, newtime->tm_min, newtime->tm_sec); #else fprintf(fp[id], "%04i [%02d.%02d. - %02d:%02d:%02d] ", getpid(), newtime->tm_mon+1, newtime->tm_mday, newtime->tm_hour, newtime->tm_min, newtime->tm_sec); #endif + } - va_list argptr, tmpargptr; - va_start(argptr, fmt); + va_list argptr,tmpargptr; + if (dofile) { - va_copy(tmpargptr, argptr); + va_start(argptr, fmt); + va_copy(tmpargptr,argptr); vfprintf( fp[id], fmt, tmpargptr ); + va_end(tmpargptr); } if(logCallbackFmt[id]) { msgCallbackFmt p = logCallbackFmt[id]; - va_copy(tmpargptr, argptr); + va_start(argptr, fmt); + va_copy(tmpargptr,argptr); p(id, fmt, tmpargptr ); + va_end(tmpargptr); } - + std::string outputMessage; - StringFormat(outputMessage, fmt, argptr); - + va_start(argptr, fmt); + va_copy(tmpargptr,argptr); + vStringFormat(outputMessage, fmt, tmpargptr); + va_end(tmpargptr); + if (pLogStatus[id] & 2) { if (pLogStatus[id] & 8) { @@ -183,7 +193,6 @@ bool EQEMuLog::write(LogIDs id, const char *fmt, ...) { std::cout << outputMessage; } } - va_end(argptr); if (dofile) fprintf(fp[id], "\n"); if (pLogStatus[id] & 2) {