summaryrefslogtreecommitdiff
path: root/public/tier1/fmtstr.h
diff options
context:
space:
mode:
Diffstat (limited to 'public/tier1/fmtstr.h')
-rw-r--r--public/tier1/fmtstr.h366
1 files changed, 366 insertions, 0 deletions
diff --git a/public/tier1/fmtstr.h b/public/tier1/fmtstr.h
new file mode 100644
index 0000000..66ea88f
--- /dev/null
+++ b/public/tier1/fmtstr.h
@@ -0,0 +1,366 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: A simple class for performing safe and in-expression sprintf-style
+// string formatting
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef FMTSTR_H
+#define FMTSTR_H
+
+#include <stdarg.h>
+#include <stdio.h>
+#include "tier0/platform.h"
+#include "tier0/dbg.h"
+#include "tier1/strtools.h"
+
+#if defined( _WIN32 )
+#pragma once
+#endif
+#if defined(POSIX)
+#pragma GCC visibility push(hidden)
+#endif
+
+//=============================================================================
+
+// using macro to be compatable with GCC
+#define FmtStrVSNPrintf( szBuf, nBufSize, bQuietTruncation, ppszFormat, nPrevLen, lastArg ) \
+ do \
+ { \
+ int result; \
+ va_list arg_ptr; \
+ bool bTruncated = false; \
+ static int scAsserted = 0; \
+ \
+ va_start(arg_ptr, lastArg); \
+ result = V_vsnprintfRet( (szBuf), (nBufSize)-1, (*(ppszFormat)), arg_ptr, &bTruncated ); \
+ va_end(arg_ptr); \
+ \
+ (szBuf)[(nBufSize)-1] = 0; \
+ if ( bTruncated && !(bQuietTruncation) && scAsserted < 5 ) \
+ { \
+ Warning( "FmtStrVSNPrintf truncated to %d without QUIET_TRUNCATION specified!\n", ( int )( nBufSize ) ); \
+ AssertMsg( 0, "FmtStrVSNPrintf truncated without QUIET_TRUNCATION specified!\n" ); \
+ scAsserted++; \
+ } \
+ m_nLength = nPrevLen + result; \
+ } \
+ while (0)
+
+// using macro to be compatable with GCC
+#define FmtStrVSNPrintfNoLengthFixup( szBuf, nBufSize, bQuietTruncation, ppszFormat, nPrevLen, lastArg ) \
+ do \
+ { \
+ int result; \
+ va_list arg_ptr; \
+ bool bTruncated = false; \
+ static int scAsserted = 0; \
+ \
+ va_start(arg_ptr, lastArg); \
+ result = V_vsnprintfRet( (szBuf), (nBufSize)-1, (*(ppszFormat)), arg_ptr, &bTruncated ); \
+ va_end(arg_ptr); \
+ \
+ (szBuf)[(nBufSize)-1] = 0; \
+ if ( bTruncated && !(bQuietTruncation) && scAsserted < 5 ) \
+ { \
+ Warning( "FmtStrVSNPrintf truncated to %d without QUIET_TRUNCATION specified!\n", ( int )( nBufSize ) ); \
+ AssertMsg( 0, "FmtStrVSNPrintf truncated without QUIET_TRUNCATION specified!\n" ); \
+ scAsserted++; \
+ } \
+ } \
+ while (0)
+
+//-----------------------------------------------------------------------------
+//
+// Purpose: String formatter with specified size
+//
+
+template <int SIZE_BUF, bool QUIET_TRUNCATION = false >
+class CFmtStrN
+{
+public:
+ CFmtStrN()
+ {
+ InitQuietTruncation();
+ m_szBuf[0] = 0;
+ m_nLength = 0;
+ }
+
+ // Standard C formatting
+ CFmtStrN(PRINTF_FORMAT_STRING const char *pszFormat, ...) FMTFUNCTION( 2, 3 )
+ {
+ InitQuietTruncation();
+ FmtStrVSNPrintf( m_szBuf, SIZE_BUF, m_bQuietTruncation, &pszFormat, 0, pszFormat );
+ }
+
+ // Use this for pass-through formatting
+ CFmtStrN(const char ** ppszFormat, ...)
+ {
+ InitQuietTruncation();
+ FmtStrVSNPrintf( m_szBuf, SIZE_BUF, m_bQuietTruncation, ppszFormat, 0, ppszFormat );
+ }
+
+ // Explicit reformat
+ const char *sprintf(PRINTF_FORMAT_STRING const char *pszFormat, ...) FMTFUNCTION( 2, 3 )
+ {
+ InitQuietTruncation();
+ FmtStrVSNPrintf(m_szBuf, SIZE_BUF, m_bQuietTruncation, &pszFormat, 0, pszFormat );
+ return m_szBuf;
+ }
+
+ // Use this for va_list formatting
+ const char *sprintf_argv(const char *pszFormat, va_list arg_ptr)
+ {
+ int result;
+ bool bTruncated = false;
+ static int s_nWarned = 0;
+
+ InitQuietTruncation();
+ result = V_vsnprintfRet( m_szBuf, SIZE_BUF - 1, pszFormat, arg_ptr, &bTruncated );
+ m_szBuf[SIZE_BUF - 1] = 0;
+ if ( bTruncated && !m_bQuietTruncation && ( s_nWarned < 5 ) )
+ {
+ Warning( "CFmtStr truncated to %d without QUIET_TRUNCATION specified!\n", SIZE_BUF );
+ AssertMsg( 0, "CFmtStr truncated without QUIET_TRUNCATION specified!\n" );
+ s_nWarned++;
+ }
+ m_nLength = V_strlen( m_szBuf );
+ return m_szBuf;
+ }
+
+ // Use this for pass-through formatting
+ void VSprintf(const char **ppszFormat, ...)
+ {
+ InitQuietTruncation();
+ FmtStrVSNPrintf( m_szBuf, SIZE_BUF, m_bQuietTruncation, ppszFormat, 0, ppszFormat );
+ }
+
+ // Compatible API with CUtlString for converting to const char*
+ const char *Get( ) const { return m_szBuf; }
+ const char *String( ) const { return m_szBuf; }
+ // Use for access
+ operator const char *() const { return m_szBuf; }
+ char *Access() { return m_szBuf; }
+
+ // Access template argument
+ static inline int GetMaxLength() { return SIZE_BUF-1; }
+
+ CFmtStrN<SIZE_BUF,QUIET_TRUNCATION> & operator=( const char *pchValue )
+ {
+ V_strncpy( m_szBuf, pchValue, SIZE_BUF );
+ m_nLength = V_strlen( m_szBuf );
+ return *this;
+ }
+
+ CFmtStrN<SIZE_BUF,QUIET_TRUNCATION> & operator+=( const char *pchValue )
+ {
+ Append( pchValue );
+ return *this;
+ }
+
+ int Length() const { return m_nLength; }
+
+ void SetLength( int nLength )
+ {
+ m_nLength = Min( nLength, SIZE_BUF - 1 );
+ m_szBuf[m_nLength] = '\0';
+ }
+
+ void Clear()
+ {
+ m_szBuf[0] = 0;
+ m_nLength = 0;
+ }
+
+ void AppendFormat( PRINTF_FORMAT_STRING const char *pchFormat, ... ) FMTFUNCTION( 2, 3 )
+ {
+ char *pchEnd = m_szBuf + m_nLength;
+ FmtStrVSNPrintf( pchEnd, SIZE_BUF - m_nLength, m_bQuietTruncation, &pchFormat, m_nLength, pchFormat );
+ }
+
+ void AppendFormatV( const char *pchFormat, va_list args );
+
+ void Append( const char *pchValue )
+ {
+ // This function is close to the metal to cut down on the CPU cost
+ // of the previous incantation of Append which was implemented as
+ // AppendFormat( "%s", pchValue ). This implementation, though not
+ // as easy to read, instead does a strcpy from the existing end
+ // point of the CFmtStrN. This brings something like a 10-20x speedup
+ // in my rudimentary tests. It isn't using V_strncpy because that
+ // function doesn't return the number of characters copied, which
+ // we need to adjust m_nLength. Doing the V_strncpy with a V_strlen
+ // afterwards took twice as long as this implementations in tests,
+ // so V_strncpy's implementation was used to write this method.
+ char *pDest = m_szBuf + m_nLength;
+ const int maxLen = SIZE_BUF - m_nLength;
+ char *pLast = pDest + maxLen - 1;
+ while ( (pDest < pLast) && (*pchValue != 0) )
+ {
+ *pDest = *pchValue;
+ ++pDest; ++pchValue;
+ }
+ *pDest = 0;
+ m_nLength = pDest - m_szBuf;
+ }
+
+ //optimized version of append for just adding a single character
+ void Append( char ch )
+ {
+ if( m_nLength < SIZE_BUF - 1 )
+ {
+ m_szBuf[ m_nLength ] = ch;
+ m_nLength++;
+ m_szBuf[ m_nLength ] = '\0';
+ }
+ }
+
+ void AppendIndent( uint32 unCount, char chIndent = '\t' );
+
+ void SetQuietTruncation( bool bQuiet ) { m_bQuietTruncation = bQuiet; }
+
+protected:
+ virtual void InitQuietTruncation()
+ {
+ m_bQuietTruncation = QUIET_TRUNCATION;
+ }
+
+ bool m_bQuietTruncation;
+
+private:
+ char m_szBuf[SIZE_BUF];
+ int m_nLength;
+};
+
+
+// Version which will not assert if strings are truncated
+
+template < int SIZE_BUF >
+class CFmtStrQuietTruncationN : public CFmtStrN<SIZE_BUF, true >
+{
+};
+
+
+template< int SIZE_BUF, bool QUIET_TRUNCATION >
+void CFmtStrN< SIZE_BUF, QUIET_TRUNCATION >::AppendIndent( uint32 unCount, char chIndent )
+{
+ Assert( Length() + unCount < SIZE_BUF );
+ if( Length() + unCount >= SIZE_BUF )
+ unCount = SIZE_BUF - (1+Length());
+ for ( uint32 x = 0; x < unCount; x++ )
+ {
+ m_szBuf[ m_nLength++ ] = chIndent;
+ }
+ m_szBuf[ m_nLength ] = '\0';
+}
+
+template< int SIZE_BUF, bool QUIET_TRUNCATION >
+void CFmtStrN< SIZE_BUF, QUIET_TRUNCATION >::AppendFormatV( const char *pchFormat, va_list args )
+{
+ int cubPrinted = V_vsnprintf( m_szBuf+Length(), SIZE_BUF - Length(), pchFormat, args );
+ m_nLength += cubPrinted;
+}
+
+
+#if defined(POSIX)
+#pragma GCC visibility pop
+#endif
+
+//-----------------------------------------------------------------------------
+//
+// Purpose: Default-sized string formatter
+//
+
+#define FMTSTR_STD_LEN 256
+
+typedef CFmtStrN<FMTSTR_STD_LEN> CFmtStr;
+typedef CFmtStrQuietTruncationN<FMTSTR_STD_LEN> CFmtStrQuietTruncation;
+typedef CFmtStrN<1024> CFmtStr1024;
+typedef CFmtStrN<8192> CFmtStrMax;
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Fast-path number-to-string helper (with optional quoting)
+// Derived off of the Steam CNumStr but with a few tweaks, such as
+// trimming off the in-our-cases-unnecessary strlen calls (by not
+// storing the length in the class).
+//-----------------------------------------------------------------------------
+
+class CNumStr
+{
+public:
+ CNumStr() { m_szBuf[0] = 0; }
+
+ explicit CNumStr( bool b ) { SetBool( b ); }
+
+ explicit CNumStr( int8 n8 ) { SetInt8( n8 ); }
+ explicit CNumStr( uint8 un8 ) { SetUint8( un8 ); }
+ explicit CNumStr( int16 n16 ) { SetInt16( n16 ); }
+ explicit CNumStr( uint16 un16 ) { SetUint16( un16 ); }
+ explicit CNumStr( int32 n32 ) { SetInt32( n32 ); }
+ explicit CNumStr( uint32 un32 ) { SetUint32( un32 ); }
+ explicit CNumStr( int64 n64 ) { SetInt64( n64 ); }
+ explicit CNumStr( uint64 un64 ) { SetUint64( un64 ); }
+
+#if defined(COMPILER_GCC) && defined(PLATFORM_64BITS)
+ explicit CNumStr( lint64 n64 ) { SetInt64( (int64)n64 ); }
+ explicit CNumStr( ulint64 un64 ) { SetUint64( (uint64)un64 ); }
+#endif
+
+ explicit CNumStr( double f ) { SetDouble( f ); }
+ explicit CNumStr( float f ) { SetFloat( f ); }
+
+ inline void SetBool( bool b ) { Q_memcpy( m_szBuf, b ? "1" : "0", 2 ); }
+
+#ifdef _WIN32
+ inline void SetInt8( int8 n8 ) { _itoa( (int32)n8, m_szBuf, 10 ); }
+ inline void SetUint8( uint8 un8 ) { _itoa( (int32)un8, m_szBuf, 10 ); }
+ inline void SetInt16( int16 n16 ) { _itoa( (int32)n16, m_szBuf, 10 ); }
+ inline void SetUint16( uint16 un16 ) { _itoa( (int32)un16, m_szBuf, 10 ); }
+ inline void SetInt32( int32 n32 ) { _itoa( n32, m_szBuf, 10 ); }
+ inline void SetUint32( uint32 un32 ) { _i64toa( (int64)un32, m_szBuf, 10 ); }
+ inline void SetInt64( int64 n64 ) { _i64toa( n64, m_szBuf, 10 ); }
+ inline void SetUint64( uint64 un64 ) { _ui64toa( un64, m_szBuf, 10 ); }
+#else
+ inline void SetInt8( int8 n8 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%d", (int32)n8 ); }
+ inline void SetUint8( uint8 un8 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%d", (int32)un8 ); }
+ inline void SetInt16( int16 n16 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%d", (int32)n16 ); }
+ inline void SetUint16( uint16 un16 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%d", (int32)un16 ); }
+ inline void SetInt32( int32 n32 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%d", n32 ); }
+ inline void SetUint32( uint32 un32 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%u", un32 ); }
+ inline void SetInt64( int64 n64 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%lld", n64 ); }
+ inline void SetUint64( uint64 un64 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%llu", un64 ); }
+#endif
+
+ inline void SetDouble( double f ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%.18g", f ); }
+ inline void SetFloat( float f ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%.18g", f ); }
+
+ inline void SetHexUint64( uint64 un64 ) { Q_binarytohex( (byte *)&un64, sizeof( un64 ), m_szBuf, sizeof( m_szBuf ) ); }
+
+ operator const char *() const { return m_szBuf; }
+ const char* String() const { return m_szBuf; }
+
+ void AddQuotes()
+ {
+ Assert( m_szBuf[0] != '"' );
+ const int nLength = Q_strlen( m_szBuf );
+ Q_memmove( m_szBuf + 1, m_szBuf, nLength );
+ m_szBuf[0] = '"';
+ m_szBuf[nLength + 1] = '"';
+ m_szBuf[nLength + 2] = 0;
+ }
+
+protected:
+ char m_szBuf[28]; // long enough to hold 18 digits of precision, a decimal, a - sign, e+### suffix, and quotes
+
+};
+
+
+//=============================================================================
+
+bool BGetLocalFormattedDateAndTime( time_t timeVal, char *pchDate, int cubDate, char *pchTime, int cubTime );
+bool BGetLocalFormattedDate( time_t timeVal, char *pchDate, int cubDate );
+bool BGetLocalFormattedTime( time_t timeVal, char *pchTime, int cubTime );
+
+#endif // FMTSTR_H