diff options
Diffstat (limited to 'dep/g3dlite/format.cpp')
-rw-r--r-- | dep/g3dlite/format.cpp | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/dep/g3dlite/format.cpp b/dep/g3dlite/format.cpp new file mode 100644 index 00000000000..d9d1b516393 --- /dev/null +++ b/dep/g3dlite/format.cpp @@ -0,0 +1,164 @@ +/** + @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 |