165 lines
4.3 KiB
C++
165 lines
4.3 KiB
C++
|
/**
|
||
|
@file format.cpp
|
||
|
|
||
|
@author Morgan McGuire, graphics3d.com
|
||
|
|
||
|
@created 2000-09-09
|
||
|
@edited 2006-08-14
|
||
|
*/
|
||
|
|
||
|
#include "G3D/format.h"
|
||
|
#include "G3D/platform.h"
|
||
|
#include "G3D/System.h"
|
||
|
|
||
|
#ifdef _MSC_VER
|
||
|
// disable: "C++ exception handler used"
|
||
|
# pragma warning (push)
|
||
|
# pragma warning (disable : 4530)
|
||
|
#endif // _MSC_VER
|
||
|
|
||
|
// If your platform does not have vsnprintf, you can find a
|
||
|
// implementation at http://www.ijs.si/software/snprintf/
|
||
|
|
||
|
namespace G3D {
|
||
|
|
||
|
std::string __cdecl format(const char* fmt,...) {
|
||
|
va_list argList;
|
||
|
va_start(argList,fmt);
|
||
|
std::string result = vformat(fmt, argList);
|
||
|
va_end(argList);
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
#if defined(_MSC_VER) && (_MSC_VER >= 1300)
|
||
|
// Both MSVC seems to use the non-standard vsnprintf
|
||
|
// so we are using vscprintf to determine buffer size, however
|
||
|
// only MSVC7 and up headers include vscprintf for some reason.
|
||
|
std::string vformat(const char *fmt, va_list argPtr) {
|
||
|
// We draw the line at a 1MB string.
|
||
|
const int maxSize = 1000000;
|
||
|
|
||
|
// If the string is less than 161 characters,
|
||
|
// allocate it on the stack because this saves
|
||
|
// the malloc/free time.
|
||
|
const int bufSize = 161;
|
||
|
char stackBuffer[bufSize];
|
||
|
|
||
|
// MSVC does not support va_copy
|
||
|
int actualSize = _vscprintf(fmt, argPtr) + 1;
|
||
|
|
||
|
if (actualSize > bufSize) {
|
||
|
|
||
|
// Now use the heap.
|
||
|
char* heapBuffer = NULL;
|
||
|
|
||
|
if (actualSize < maxSize) {
|
||
|
|
||
|
heapBuffer = (char*)System::malloc(maxSize + 1);
|
||
|
_vsnprintf(heapBuffer, maxSize, fmt, argPtr);
|
||
|
heapBuffer[maxSize] = '\0';
|
||
|
} else {
|
||
|
heapBuffer = (char*)System::malloc(actualSize);
|
||
|
vsprintf(heapBuffer, fmt, argPtr);
|
||
|
}
|
||
|
|
||
|
std::string formattedString(heapBuffer);
|
||
|
System::free(heapBuffer);
|
||
|
return formattedString;
|
||
|
} else {
|
||
|
|
||
|
vsprintf(stackBuffer, fmt, argPtr);
|
||
|
return std::string(stackBuffer);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#elif defined(_MSC_VER) && (_MSC_VER < 1300)
|
||
|
|
||
|
std::string vformat(const char *fmt, va_list argPtr) {
|
||
|
// We draw the line at a 1MB string.
|
||
|
const int maxSize = 1000000;
|
||
|
|
||
|
// If the string is less than 161 characters,
|
||
|
// allocate it on the stack because this saves
|
||
|
// the malloc/free time.
|
||
|
const int bufSize = 161;
|
||
|
char stackBuffer[bufSize];
|
||
|
|
||
|
// MSVC6 doesn't support va_copy, however it also seems to compile
|
||
|
// correctly if we just pass our argument list along. Note that
|
||
|
// this whole code block is only compiled if we're on MSVC6 anyway
|
||
|
int actualWritten = _vsnprintf(stackBuffer, bufSize, fmt, argPtr);
|
||
|
|
||
|
// Not a big enough buffer, bufSize characters written
|
||
|
if (actualWritten == -1) {
|
||
|
|
||
|
int heapSize = 512;
|
||
|
double powSize = 1.0;
|
||
|
char* heapBuffer = (char*)System::malloc(heapSize);
|
||
|
|
||
|
while ((_vsnprintf(heapBuffer, heapSize, fmt, argPtr) == -1) &&
|
||
|
(heapSize < maxSize)) {
|
||
|
|
||
|
heapSize = iCeil(heapSize * ::pow((double)2.0, powSize++));
|
||
|
heapBuffer = (char*)System::realloc(heapBuffer, heapSize);
|
||
|
}
|
||
|
|
||
|
heapBuffer[heapSize-1] = '\0';
|
||
|
|
||
|
std::string heapString(heapBuffer);
|
||
|
System::free(heapBuffer);
|
||
|
|
||
|
return heapString;
|
||
|
} else {
|
||
|
|
||
|
return std::string(stackBuffer);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#else
|
||
|
|
||
|
// glibc 2.1 has been updated to the C99 standard
|
||
|
std::string vformat(const char* fmt, va_list argPtr) {
|
||
|
// If the string is less than 161 characters,
|
||
|
// allocate it on the stack because this saves
|
||
|
// the malloc/free time. The number 161 is chosen
|
||
|
// to support two lines of text on an 80 character
|
||
|
// console (plus the null terminator).
|
||
|
const int bufSize = 161;
|
||
|
char stackBuffer[bufSize];
|
||
|
|
||
|
va_list argPtrCopy;
|
||
|
va_copy(argPtrCopy, argPtr);
|
||
|
int numChars = vsnprintf(stackBuffer, bufSize, fmt, argPtrCopy);
|
||
|
va_end(argPtrCopy);
|
||
|
|
||
|
if (numChars >= bufSize) {
|
||
|
// We didn't allocate a big enough string.
|
||
|
char* heapBuffer = (char*)System::malloc((numChars + 1) * sizeof(char));
|
||
|
|
||
|
debugAssert(heapBuffer);
|
||
|
int numChars2 = vsnprintf(heapBuffer, numChars + 1, fmt, argPtr);
|
||
|
debugAssert(numChars2 == numChars);
|
||
|
(void)numChars2;
|
||
|
|
||
|
std::string result(heapBuffer);
|
||
|
|
||
|
System::free(heapBuffer);
|
||
|
|
||
|
return result;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
return std::string(stackBuffer);
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
} // namespace
|
||
|
|
||
|
#ifdef _MSC_VER
|
||
|
# pragma warning (pop)
|
||
|
#endif
|