Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

368 lines
12 KiB

  1. //========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: A simple class for performing safe and in-expression sprintf-style
  4. // string formatting
  5. //
  6. // $NoKeywords: $
  7. //=============================================================================//
  8. #ifndef FMTSTR_H
  9. #define FMTSTR_H
  10. #include <stdarg.h>
  11. #include <stdio.h>
  12. #include "tier0/platform.h"
  13. #include "tier0/dbg.h"
  14. #include "tier1/strtools.h"
  15. #if defined( _WIN32 )
  16. #pragma once
  17. #endif
  18. //=============================================================================
  19. // using macro to be compatable with GCC
  20. #define FmtStrVSNPrintf( szBuf, nBufSize, bQuietTruncation, ppszFormat, nPrevLen, lastArg ) \
  21. do \
  22. { \
  23. int result; \
  24. va_list arg_ptr; \
  25. bool bTruncated = false; \
  26. static int scAsserted = 0; \
  27. \
  28. va_start(arg_ptr, lastArg); \
  29. result = V_vsnprintfRet( (szBuf), (nBufSize)-1, (*(ppszFormat)), arg_ptr, &bTruncated ); \
  30. va_end(arg_ptr); \
  31. \
  32. (szBuf)[(nBufSize)-1] = 0; \
  33. if ( bTruncated && !(bQuietTruncation) && scAsserted < 5 ) \
  34. { \
  35. Warning( "FmtStrVSNPrintf truncated to %d without QUIET_TRUNCATION specified!\n", ( int )( nBufSize ) ); \
  36. AssertMsg( 0, "FmtStrVSNPrintf truncated without QUIET_TRUNCATION specified!\n" ); \
  37. scAsserted++; \
  38. } \
  39. m_nLength = nPrevLen + result; \
  40. } \
  41. while (0)
  42. // using macro to be compatable with GCC
  43. #define FmtStrVSNPrintfNoLengthFixup( szBuf, nBufSize, bQuietTruncation, ppszFormat, nPrevLen, lastArg ) \
  44. do \
  45. { \
  46. int result; \
  47. va_list arg_ptr; \
  48. bool bTruncated = false; \
  49. static int scAsserted = 0; \
  50. \
  51. va_start(arg_ptr, lastArg); \
  52. result = V_vsnprintfRet( (szBuf), (nBufSize)-1, (*(ppszFormat)), arg_ptr, &bTruncated ); \
  53. va_end(arg_ptr); \
  54. \
  55. (szBuf)[(nBufSize)-1] = 0; \
  56. if ( bTruncated && !(bQuietTruncation) && scAsserted < 5 ) \
  57. { \
  58. Warning( "FmtStrVSNPrintf truncated to %d without QUIET_TRUNCATION specified!\n", ( int )( nBufSize ) ); \
  59. AssertMsg( 0, "FmtStrVSNPrintf truncated without QUIET_TRUNCATION specified!\n" ); \
  60. scAsserted++; \
  61. } \
  62. } \
  63. while (0)
  64. //-----------------------------------------------------------------------------
  65. //
  66. // Purpose: String formatter with specified size
  67. //
  68. template <int SIZE_BUF, bool QUIET_TRUNCATION = false >
  69. class CFmtStrN
  70. {
  71. public:
  72. CFmtStrN()
  73. {
  74. InitQuietTruncation();
  75. m_szBuf[0] = 0;
  76. m_nLength = 0;
  77. }
  78. // Standard C formatting
  79. CFmtStrN(PRINTF_FORMAT_STRING const char *pszFormat, ...) FMTFUNCTION( 2, 3 )
  80. {
  81. InitQuietTruncation();
  82. FmtStrVSNPrintf( m_szBuf, SIZE_BUF, m_bQuietTruncation, &pszFormat, 0, pszFormat );
  83. }
  84. // Use this for pass-through formatting
  85. CFmtStrN(const char ** ppszFormat, ...)
  86. {
  87. InitQuietTruncation();
  88. FmtStrVSNPrintf( m_szBuf, SIZE_BUF, m_bQuietTruncation, ppszFormat, 0, ppszFormat );
  89. }
  90. // Explicit reformat
  91. const char *sprintf(PRINTF_FORMAT_STRING const char *pszFormat, ...) FMTFUNCTION( 2, 3 )
  92. {
  93. InitQuietTruncation();
  94. FmtStrVSNPrintf(m_szBuf, SIZE_BUF, m_bQuietTruncation, &pszFormat, 0, pszFormat );
  95. return m_szBuf;
  96. }
  97. // Same as sprintf above, but for compatibility with Steam interface
  98. const char *Format( PRINTF_FORMAT_STRING const char *pszFormat, ... ) FMTFUNCTION( 2, 3 )
  99. {
  100. InitQuietTruncation();
  101. FmtStrVSNPrintf( m_szBuf, SIZE_BUF, m_bQuietTruncation, &pszFormat, 0, pszFormat );
  102. return m_szBuf;
  103. }
  104. // Use this for va_list formatting
  105. const char *sprintf_argv(const char *pszFormat, va_list arg_ptr)
  106. {
  107. int result;
  108. bool bTruncated = false;
  109. static int s_nWarned = 0;
  110. InitQuietTruncation();
  111. result = V_vsnprintfRet( m_szBuf, SIZE_BUF - 1, pszFormat, arg_ptr, &bTruncated );
  112. m_szBuf[SIZE_BUF - 1] = 0;
  113. if ( bTruncated && !m_bQuietTruncation && ( s_nWarned < 5 ) )
  114. {
  115. Warning( "CFmtStr truncated to %d without QUIET_TRUNCATION specified!\n", SIZE_BUF );
  116. AssertMsg( 0, "CFmtStr truncated without QUIET_TRUNCATION specified!\n" );
  117. s_nWarned++;
  118. }
  119. m_nLength = V_strlen( m_szBuf );
  120. return m_szBuf;
  121. }
  122. // Use this for pass-through formatting
  123. void VSprintf(const char **ppszFormat, ...)
  124. {
  125. InitQuietTruncation();
  126. FmtStrVSNPrintf( m_szBuf, SIZE_BUF, m_bQuietTruncation, ppszFormat, 0, ppszFormat );
  127. }
  128. // Compatible API with CUtlString for converting to const char*
  129. const char *Get( ) const { return m_szBuf; }
  130. const char *String( ) const { return m_szBuf; }
  131. // Use for access
  132. operator const char *() const { return m_szBuf; }
  133. char *Access() { return m_szBuf; }
  134. // Access template argument
  135. static inline int GetMaxLength() { return SIZE_BUF-1; }
  136. CFmtStrN<SIZE_BUF,QUIET_TRUNCATION> & operator=( const char *pchValue )
  137. {
  138. V_strncpy( m_szBuf, pchValue, SIZE_BUF );
  139. m_nLength = V_strlen( m_szBuf );
  140. return *this;
  141. }
  142. CFmtStrN<SIZE_BUF,QUIET_TRUNCATION> & operator+=( const char *pchValue )
  143. {
  144. Append( pchValue );
  145. return *this;
  146. }
  147. int Length() const { return m_nLength; }
  148. void SetLength( int nLength )
  149. {
  150. m_nLength = Min( nLength, SIZE_BUF - 1 );
  151. m_szBuf[m_nLength] = '\0';
  152. }
  153. void Clear()
  154. {
  155. m_szBuf[0] = 0;
  156. m_nLength = 0;
  157. }
  158. void AppendFormat( PRINTF_FORMAT_STRING const char *pchFormat, ... ) FMTFUNCTION( 2, 3 )
  159. {
  160. char *pchEnd = m_szBuf + m_nLength;
  161. FmtStrVSNPrintf( pchEnd, SIZE_BUF - m_nLength, m_bQuietTruncation, &pchFormat, m_nLength, pchFormat );
  162. }
  163. void AppendFormatV( const char *pchFormat, va_list args );
  164. void Append( const char *pchValue )
  165. {
  166. // This function is close to the metal to cut down on the CPU cost
  167. // of the previous incantation of Append which was implemented as
  168. // AppendFormat( "%s", pchValue ). This implementation, though not
  169. // as easy to read, instead does a strcpy from the existing end
  170. // point of the CFmtStrN. This brings something like a 10-20x speedup
  171. // in my rudimentary tests. It isn't using V_strncpy because that
  172. // function doesn't return the number of characters copied, which
  173. // we need to adjust m_nLength. Doing the V_strncpy with a V_strlen
  174. // afterwards took twice as long as this implementations in tests,
  175. // so V_strncpy's implementation was used to write this method.
  176. char *pDest = m_szBuf + m_nLength;
  177. const int maxLen = SIZE_BUF - m_nLength;
  178. char *pLast = pDest + maxLen - 1;
  179. while ( (pDest < pLast) && (*pchValue != 0) )
  180. {
  181. *pDest = *pchValue;
  182. ++pDest; ++pchValue;
  183. }
  184. *pDest = 0;
  185. m_nLength = pDest - m_szBuf;
  186. }
  187. //optimized version of append for just adding a single character
  188. void Append( char ch )
  189. {
  190. if( m_nLength < SIZE_BUF - 1 )
  191. {
  192. m_szBuf[ m_nLength ] = ch;
  193. m_nLength++;
  194. m_szBuf[ m_nLength ] = '\0';
  195. }
  196. }
  197. void AppendIndent( uint32 unCount, char chIndent = '\t' );
  198. void SetQuietTruncation( bool bQuiet ) { m_bQuietTruncation = bQuiet; }
  199. protected:
  200. virtual void InitQuietTruncation()
  201. {
  202. m_bQuietTruncation = QUIET_TRUNCATION;
  203. }
  204. bool m_bQuietTruncation;
  205. private:
  206. char m_szBuf[SIZE_BUF];
  207. int m_nLength;
  208. };
  209. // Version which will not assert if strings are truncated
  210. template < int SIZE_BUF >
  211. class CFmtStrQuietTruncationN : public CFmtStrN<SIZE_BUF, true >
  212. {
  213. };
  214. template< int SIZE_BUF, bool QUIET_TRUNCATION >
  215. void CFmtStrN< SIZE_BUF, QUIET_TRUNCATION >::AppendIndent( uint32 unCount, char chIndent )
  216. {
  217. Assert( Length() + unCount < SIZE_BUF );
  218. if( Length() + unCount >= SIZE_BUF )
  219. unCount = SIZE_BUF - (1+Length());
  220. for ( uint32 x = 0; x < unCount; x++ )
  221. {
  222. m_szBuf[ m_nLength++ ] = chIndent;
  223. }
  224. m_szBuf[ m_nLength ] = '\0';
  225. }
  226. template< int SIZE_BUF, bool QUIET_TRUNCATION >
  227. void CFmtStrN< SIZE_BUF, QUIET_TRUNCATION >::AppendFormatV( const char *pchFormat, va_list args )
  228. {
  229. int cubPrinted = V_vsnprintf( m_szBuf+Length(), SIZE_BUF - Length(), pchFormat, args );
  230. m_nLength += cubPrinted;
  231. }
  232. //-----------------------------------------------------------------------------
  233. //
  234. // Purpose: Default-sized string formatter
  235. //
  236. #define FMTSTR_STD_LEN 256
  237. typedef CFmtStrN<FMTSTR_STD_LEN> CFmtStr;
  238. typedef CFmtStrQuietTruncationN<FMTSTR_STD_LEN> CFmtStrQuietTruncation;
  239. typedef CFmtStrN<32> CFmtStr32;
  240. typedef CFmtStrN<1024> CFmtStr1024;
  241. typedef CFmtStrN<8192> CFmtStrMax;
  242. //-----------------------------------------------------------------------------
  243. // Purpose: Fast-path number-to-string helper (with optional quoting)
  244. // Derived off of the Steam CNumStr but with a few tweaks, such as
  245. // trimming off the in-our-cases-unnecessary strlen calls (by not
  246. // storing the length in the class).
  247. //-----------------------------------------------------------------------------
  248. class CNumStr
  249. {
  250. public:
  251. CNumStr() { m_szBuf[0] = 0; }
  252. explicit CNumStr( bool b ) { SetBool( b ); }
  253. explicit CNumStr( int8 n8 ) { SetInt8( n8 ); }
  254. explicit CNumStr( uint8 un8 ) { SetUint8( un8 ); }
  255. explicit CNumStr( int16 n16 ) { SetInt16( n16 ); }
  256. explicit CNumStr( uint16 un16 ) { SetUint16( un16 ); }
  257. explicit CNumStr( int32 n32 ) { SetInt32( n32 ); }
  258. explicit CNumStr( uint32 un32 ) { SetUint32( un32 ); }
  259. explicit CNumStr( int64 n64 ) { SetInt64( n64 ); }
  260. explicit CNumStr( uint64 un64 ) { SetUint64( un64 ); }
  261. #if defined(COMPILER_GCC) && defined(PLATFORM_64BITS)
  262. explicit CNumStr( lint64 n64 ) { SetInt64( (int64)n64 ); }
  263. explicit CNumStr( ulint64 un64 ) { SetUint64( (uint64)un64 ); }
  264. #endif
  265. explicit CNumStr( double f ) { SetDouble( f ); }
  266. explicit CNumStr( float f ) { SetFloat( f ); }
  267. inline void SetBool( bool b ) { Q_memcpy( m_szBuf, b ? "1" : "0", 2 ); }
  268. #ifdef _WIN32
  269. inline void SetInt8( int8 n8 ) { _itoa( (int32)n8, m_szBuf, 10 ); }
  270. inline void SetUint8( uint8 un8 ) { _itoa( (int32)un8, m_szBuf, 10 ); }
  271. inline void SetInt16( int16 n16 ) { _itoa( (int32)n16, m_szBuf, 10 ); }
  272. inline void SetUint16( uint16 un16 ) { _itoa( (int32)un16, m_szBuf, 10 ); }
  273. inline void SetInt32( int32 n32 ) { _itoa( n32, m_szBuf, 10 ); }
  274. inline void SetUint32( uint32 un32 ) { _i64toa( (int64)un32, m_szBuf, 10 ); }
  275. inline void SetInt64( int64 n64 ) { _i64toa( n64, m_szBuf, 10 ); }
  276. inline void SetUint64( uint64 un64 ) { _ui64toa( un64, m_szBuf, 10 ); }
  277. #else
  278. inline void SetInt8( int8 n8 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%d", (int32)n8 ); }
  279. inline void SetUint8( uint8 un8 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%d", (int32)un8 ); }
  280. inline void SetInt16( int16 n16 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%d", (int32)n16 ); }
  281. inline void SetUint16( uint16 un16 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%d", (int32)un16 ); }
  282. inline void SetInt32( int32 n32 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%d", n32 ); }
  283. inline void SetUint32( uint32 un32 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%u", un32 ); }
  284. inline void SetInt64( int64 n64 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%lld", n64 ); }
  285. inline void SetUint64( uint64 un64 ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%llu", un64 ); }
  286. #endif
  287. inline void SetDouble( double f ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%.18g", f ); }
  288. inline void SetFloat( float f ) { Q_snprintf( m_szBuf, sizeof(m_szBuf), "%.18g", f ); }
  289. inline void SetHexUint64( uint64 un64 ) { Q_binarytohex( (byte *)&un64, sizeof( un64 ), m_szBuf, sizeof( m_szBuf ) ); }
  290. operator const char *() const { return m_szBuf; }
  291. const char* String() const { return m_szBuf; }
  292. void AddQuotes()
  293. {
  294. Assert( m_szBuf[0] != '"' );
  295. const int nLength = Q_strlen( m_szBuf );
  296. Q_memmove( m_szBuf + 1, m_szBuf, nLength );
  297. m_szBuf[0] = '"';
  298. m_szBuf[nLength + 1] = '"';
  299. m_szBuf[nLength + 2] = 0;
  300. }
  301. protected:
  302. char m_szBuf[28]; // long enough to hold 18 digits of precision, a decimal, a - sign, e+### suffix, and quotes
  303. };
  304. //=============================================================================
  305. const int k_cchFormattedDate = 64;
  306. const int k_cchFormattedTime = 32;
  307. bool BGetLocalFormattedTime( time_t timeVal, char *pchDate, int cubDate, char *pchTime, int cubTime );
  308. #endif // FMTSTR_H