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/math/Vector.h"
|
||||||
#include "idlib/Heap.h"
|
#include "idlib/Heap.h"
|
||||||
#include "framework/Common.h"
|
#include "framework/Common.h"
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
#include "idlib/Str.h"
|
#include "idlib/Str.h"
|
||||||
|
|
||||||
|
@ -1513,21 +1514,25 @@ idStr::snPrintf
|
||||||
================
|
================
|
||||||
*/
|
*/
|
||||||
int idStr::snPrintf( char *dest, int size, const char *fmt, ...) {
|
int idStr::snPrintf( char *dest, int size, const char *fmt, ...) {
|
||||||
int len;
|
|
||||||
va_list argptr;
|
va_list argptr;
|
||||||
char buffer[32000]; // big, but small enough to fit in PPC stack
|
int len;
|
||||||
|
|
||||||
va_start( argptr, fmt );
|
va_start( argptr, fmt );
|
||||||
len = vsprintf( buffer, fmt, argptr );
|
len = D3_vsnprintfC99(dest, size, fmt, argptr);
|
||||||
va_end( 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" );
|
idLib::common->Error( "idStr::snPrintf: overflowed buffer" );
|
||||||
}
|
}
|
||||||
if ( len >= size ) {
|
if ( len >= size ) {
|
||||||
idLib::common->Warning( "idStr::snPrintf: overflow of %i in %i\n", len, size );
|
idLib::common->Warning( "idStr::snPrintf: overflow of %i in %i\n", len, size );
|
||||||
len = size;
|
len = size;
|
||||||
}
|
}
|
||||||
idStr::Copynz( dest, buffer, size );
|
|
||||||
return len;
|
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 idStr::vsnPrintf( char *dest, int size, const char *fmt, va_list argptr ) {
|
||||||
int ret;
|
int ret = D3_vsnprintfC99(dest, size, fmt, argptr);
|
||||||
|
|
||||||
#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';
|
|
||||||
if ( ret < 0 || ret >= size ) {
|
if ( ret < 0 || ret >= size ) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -1790,3 +1784,57 @@ idStr idStr::FormatNumber( int number ) {
|
||||||
|
|
||||||
return string;
|
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;
|
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__ */
|
#endif /* !__STR_H__ */
|
||||||
|
|
Loading…
Reference in a new issue