mirror of
https://github.com/dhewm/dhewm3-sdk.git
synced 2024-11-21 12:11:07 +00:00
Add D3_(v)snprintfC99() for C99-compatible implementations
These are now used by idStr::(v)snPrintf(), and in the future can be used if a (v)snprintf() that's guaranteed not to call common->Warning() or similar is needed (e.g. used during early startup)
This commit is contained in:
parent
ef1002e44f
commit
d3d735c04f
2 changed files with 77 additions and 18 deletions
|
@ -30,6 +30,7 @@ If you have questions concerning this license or the applicable additional terms
|
|||
#include "idlib/math/Vector.h"
|
||||
#include "idlib/Heap.h"
|
||||
#include "framework/Common.h"
|
||||
#include <limits.h>
|
||||
|
||||
#include "idlib/Str.h"
|
||||
|
||||
|
@ -1513,21 +1514,25 @@ idStr::snPrintf
|
|||
================
|
||||
*/
|
||||
int idStr::snPrintf( char *dest, int size, const char *fmt, ...) {
|
||||
int len;
|
||||
va_list argptr;
|
||||
char buffer[32000]; // big, but small enough to fit in PPC stack
|
||||
|
||||
int len;
|
||||
va_start( argptr, fmt );
|
||||
len = vsprintf( buffer, fmt, argptr );
|
||||
len = D3_vsnprintfC99(dest, size, fmt, argptr);
|
||||
va_end( argptr );
|
||||
if ( len >= sizeof( buffer ) ) {
|
||||
if ( len >= 32000 ) {
|
||||
// TODO: Previously this function used a 32000 byte buffer to write into
|
||||
// with vsprintf(), and raised this error if that was overflowed
|
||||
// (more likely that'd have lead to a crash..).
|
||||
// Technically we don't have that restriction anymore, so I'm unsure
|
||||
// if this error should really still be raised to preserve
|
||||
// the old intended behavior, maybe for compat with mod DLLs using
|
||||
// the old version of the function or something?
|
||||
idLib::common->Error( "idStr::snPrintf: overflowed buffer" );
|
||||
}
|
||||
if ( len >= size ) {
|
||||
idLib::common->Warning( "idStr::snPrintf: overflow of %i in %i\n", len, size );
|
||||
len = size;
|
||||
}
|
||||
idStr::Copynz( dest, buffer, size );
|
||||
return len;
|
||||
}
|
||||
|
||||
|
@ -1550,18 +1555,7 @@ or returns -1 on failure or if the buffer would be overflowed.
|
|||
============
|
||||
*/
|
||||
int idStr::vsnPrintf( char *dest, int size, const char *fmt, va_list argptr ) {
|
||||
int ret;
|
||||
|
||||
#ifdef _WIN32
|
||||
#undef _vsnprintf
|
||||
ret = _vsnprintf( dest, size-1, fmt, argptr );
|
||||
#define _vsnprintf use_idStr_vsnPrintf
|
||||
#else
|
||||
#undef vsnprintf
|
||||
ret = vsnprintf( dest, size, fmt, argptr );
|
||||
#define vsnprintf use_idStr_vsnPrintf
|
||||
#endif
|
||||
dest[size-1] = '\0';
|
||||
int ret = D3_vsnprintfC99(dest, size, fmt, argptr);
|
||||
if ( ret < 0 || ret >= size ) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -1790,3 +1784,57 @@ idStr idStr::FormatNumber( int number ) {
|
|||
|
||||
return string;
|
||||
}
|
||||
|
||||
// behaves like C99's vsnprintf() by returning the amount of bytes that
|
||||
// *would* have been written into a big enough buffer, even if that's > size
|
||||
// unlike idStr::vsnPrintf() which returns -1 in that case
|
||||
int D3_vsnprintfC99(char *dst, size_t size, const char *format, va_list ap)
|
||||
{
|
||||
// before VS2015, it didn't have a standards-conforming (v)snprintf()-implementation
|
||||
// same might be true for other windows compilers if they use old CRT versions, like MinGW does
|
||||
#if defined(_WIN32) && (!defined(_MSC_VER) || _MSC_VER < 1900)
|
||||
#undef _vsnprintf
|
||||
// based on DG_vsnprintf() from https://github.com/DanielGibson/Snippets/blob/master/DG_misc.h
|
||||
int ret = -1;
|
||||
if(dst != NULL && size > 0)
|
||||
{
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1400
|
||||
// I think MSVC2005 introduced _vsnprintf_s().
|
||||
// this shuts up _vsnprintf() security/deprecation warnings.
|
||||
ret = _vsnprintf_s(dst, size, _TRUNCATE, format, ap);
|
||||
#else
|
||||
ret = _vsnprintf(dst, size, format, ap);
|
||||
dst[size-1] = '\0'; // ensure '\0'-termination
|
||||
#endif
|
||||
}
|
||||
|
||||
if(ret == -1)
|
||||
{
|
||||
// _vsnprintf() returns -1 if the output is truncated
|
||||
// it's also -1 if dst or size were NULL/0, so the user didn't want to write
|
||||
// we want to return the number of characters that would've been
|
||||
// needed, though.. fortunately _vscprintf() calculates that.
|
||||
ret = _vscprintf(format, ap);
|
||||
}
|
||||
return ret;
|
||||
#define _vsnprintf use_idStr_vsnPrintf
|
||||
#else // other operating systems and VisualC++ >= 2015 should have a proper vsnprintf()
|
||||
#undef vsnprintf
|
||||
return vsnprintf(dst, size, format, ap);
|
||||
#define vsnprintf use_idStr_vsnPrintf
|
||||
#endif
|
||||
}
|
||||
|
||||
// behaves like C99's snprintf() by returning the amount of bytes that
|
||||
// *would* have been written into a big enough buffer, even if that's > size
|
||||
// unlike idStr::snPrintf() which returns the written bytes in that case
|
||||
// and also calls common->Warning() in case of overflows
|
||||
int D3_snprintfC99(char *dst, size_t size, const char *format, ...)
|
||||
{
|
||||
int ret = 0;
|
||||
va_list argptr;
|
||||
va_start( argptr, format );
|
||||
ret = D3_vsnprintfC99(dst, size, format, argptr);
|
||||
va_end( argptr );
|
||||
return ret;
|
||||
}
|
||||
|
|
11
idlib/Str.h
11
idlib/Str.h
|
@ -1068,4 +1068,15 @@ ID_INLINE int idStr::DynamicMemoryUsed() const {
|
|||
return ( data == baseBuffer ) ? 0 : alloced;
|
||||
}
|
||||
|
||||
// behaves like C99's snprintf() by returning the amount of bytes that
|
||||
// *would* have been written into a big enough buffer, even if that's > size
|
||||
// unlike idStr::snPrintf() which returns the written bytes in that case
|
||||
// and also calls common->Warning() in case of overflows
|
||||
int D3_snprintfC99(char *dst, size_t size, const char *format, ...) id_attribute((format(printf,3,4)));
|
||||
|
||||
// behaves like C99's vsnprintf() by returning the amount of bytes that
|
||||
// *would* have been written into a big enough buffer, even if that's > size
|
||||
// unlike idStr::vsnPrintf() which returns -1 in that case
|
||||
int D3_vsnprintfC99(char *dst, size_t size, const char *format, va_list ap);
|
||||
|
||||
#endif /* !__STR_H__ */
|
||||
|
|
Loading…
Reference in a new issue