Team Fortress 2 Source Code as on 22/4/2020
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.

948 lines
24 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //===========================================================================//
  8. #include "pch_tier0.h"
  9. #include "tier0/minidump.h"
  10. #if defined( _WIN32 ) && !defined( _X360 )
  11. #include "tier0/valve_off.h"
  12. #define WIN_32_LEAN_AND_MEAN
  13. #include <windows.h> // Currently needed for IsBadReadPtr and IsBadWritePtr
  14. #pragma comment(lib,"user32.lib") // For MessageBox
  15. #endif
  16. #include <assert.h>
  17. #include <malloc.h>
  18. #include <stdio.h>
  19. #include <string.h>
  20. #include <stdarg.h>
  21. #include <stdlib.h>
  22. #include "Color.h"
  23. #include "tier0/dbg.h"
  24. #include "tier0/threadtools.h"
  25. #include "tier0/icommandline.h"
  26. #include <math.h>
  27. #if defined( _X360 )
  28. #include "xbox/xbox_console.h"
  29. #endif
  30. #include "tier0/etwprof.h"
  31. #ifndef STEAM
  32. #define PvRealloc realloc
  33. #define PvAlloc malloc
  34. #endif
  35. // memdbgon must be the last include file in a .cpp file!!!
  36. #include "tier0/memdbgon.h"
  37. //-----------------------------------------------------------------------------
  38. // internal structures
  39. //-----------------------------------------------------------------------------
  40. enum
  41. {
  42. MAX_GROUP_NAME_LENGTH = 48
  43. };
  44. struct SpewGroup_t
  45. {
  46. tchar m_GroupName[MAX_GROUP_NAME_LENGTH];
  47. int m_Level;
  48. };
  49. // Skip forward past the directory
  50. static const char *SkipToFname( const tchar* pFile )
  51. {
  52. if ( pFile == NULL )
  53. return "unknown";
  54. const tchar* pSlash = _tcsrchr( pFile, '\\' );
  55. const tchar* pSlash2 = _tcsrchr( pFile, '/' );
  56. if (pSlash < pSlash2) pSlash = pSlash2;
  57. return pSlash ? pSlash + 1: pFile;
  58. }
  59. //-----------------------------------------------------------------------------
  60. DBG_INTERFACE SpewRetval_t DefaultSpewFunc( SpewType_t type, const tchar *pMsg )
  61. {
  62. #ifdef _X360
  63. if ( XBX_IsConsoleConnected() )
  64. {
  65. // send to console
  66. XBX_DebugString( XMAKECOLOR( 0,0,0 ), pMsg );
  67. }
  68. else
  69. #endif
  70. {
  71. _tprintf( _T("%s"), pMsg );
  72. #ifdef _WIN32
  73. Plat_DebugString( pMsg );
  74. #endif
  75. }
  76. if ( type == SPEW_ASSERT )
  77. {
  78. #ifndef WIN32
  79. // Non-win32
  80. bool bRaiseOnAssert = getenv( "RAISE_ON_ASSERT" ) || !!CommandLine()->FindParm( "-raiseonassert" );
  81. #elif defined( _DEBUG )
  82. // Win32 debug
  83. bool bRaiseOnAssert = true;
  84. #else
  85. // Win32 release
  86. bool bRaiseOnAssert = !!CommandLine()->FindParm( "-raiseonassert" );
  87. #endif
  88. return bRaiseOnAssert ? SPEW_DEBUGGER : SPEW_CONTINUE;
  89. }
  90. else if ( type == SPEW_ERROR )
  91. return SPEW_ABORT;
  92. else
  93. return SPEW_CONTINUE;
  94. }
  95. //-----------------------------------------------------------------------------
  96. DBG_INTERFACE SpewRetval_t DefaultSpewFuncAbortOnAsserts( SpewType_t type, const tchar *pMsg )
  97. {
  98. SpewRetval_t r = DefaultSpewFunc( type, pMsg );
  99. if ( type == SPEW_ASSERT )
  100. r = SPEW_ABORT;
  101. return r;
  102. }
  103. //-----------------------------------------------------------------------------
  104. // Globals
  105. //-----------------------------------------------------------------------------
  106. static SpewOutputFunc_t s_SpewOutputFunc = DefaultSpewFunc;
  107. static AssertFailedNotifyFunc_t s_AssertFailedNotifyFunc = NULL;
  108. static const tchar* s_pFileName;
  109. static int s_Line;
  110. static SpewType_t s_SpewType;
  111. static SpewGroup_t* s_pSpewGroups = 0;
  112. static int s_GroupCount = 0;
  113. static int s_DefaultLevel = 0;
  114. #if !defined( _X360 )
  115. static Color s_DefaultOutputColor( 255, 255, 255, 255 );
  116. #else
  117. static Color s_DefaultOutputColor( 0, 0, 0, 255 );
  118. #endif
  119. // Only useable from within a spew function
  120. struct SpewInfo_t
  121. {
  122. const Color* m_pSpewOutputColor;
  123. const tchar* m_pSpewOutputGroup;
  124. int m_nSpewOutputLevel;
  125. };
  126. CThreadLocalPtr<SpewInfo_t> g_pSpewInfo;
  127. // Standard groups
  128. static const tchar* s_pDeveloper = _T("developer");
  129. static const tchar* s_pConsole = _T("console");
  130. static const tchar* s_pNetwork = _T("network");
  131. enum StandardSpewGroup_t
  132. {
  133. GROUP_DEVELOPER = 0,
  134. GROUP_CONSOLE,
  135. GROUP_NETWORK,
  136. GROUP_COUNT,
  137. };
  138. static int s_pGroupIndices[GROUP_COUNT] = { -1, -1, -1 };
  139. static const char *s_pGroupNames[GROUP_COUNT] = { s_pDeveloper, s_pConsole, s_pNetwork };
  140. //-----------------------------------------------------------------------------
  141. // Spew output management.
  142. //-----------------------------------------------------------------------------
  143. void SpewOutputFunc( SpewOutputFunc_t func )
  144. {
  145. s_SpewOutputFunc = func ? func : DefaultSpewFunc;
  146. }
  147. SpewOutputFunc_t GetSpewOutputFunc( void )
  148. {
  149. if( s_SpewOutputFunc )
  150. return s_SpewOutputFunc;
  151. return DefaultSpewFunc;
  152. }
  153. void _ExitOnFatalAssert( const tchar* pFile, int line )
  154. {
  155. _SpewMessage( _T("Fatal assert failed: %s, line %d. Application exiting.\n"), pFile, line );
  156. // only write out minidumps if we're not in the debugger
  157. if ( !Plat_IsInDebugSession() )
  158. {
  159. char rgchSuffix[512];
  160. _snprintf( rgchSuffix, sizeof(rgchSuffix), "fatalassert_%s_%d", SkipToFname( pFile ), line );
  161. WriteMiniDump( rgchSuffix );
  162. }
  163. DevMsg( 1, _T("_ExitOnFatalAssert\n") );
  164. exit( EXIT_FAILURE );
  165. }
  166. //-----------------------------------------------------------------------------
  167. // Templates to assist in validating pointers:
  168. //-----------------------------------------------------------------------------
  169. DBG_INTERFACE void _AssertValidReadPtr( void* ptr, int count/* = 1*/ )
  170. {
  171. Assert( !count || ptr );
  172. }
  173. DBG_INTERFACE void _AssertValidWritePtr( void* ptr, int count/* = 1*/ )
  174. {
  175. Assert( !count || ptr );
  176. }
  177. DBG_INTERFACE void _AssertValidReadWritePtr( void* ptr, int count/* = 1*/ )
  178. {
  179. Assert( !count || ptr );
  180. }
  181. #undef AssertValidStringPtr
  182. DBG_INTERFACE void AssertValidStringPtr( const tchar* ptr, int maxchar/* = 0xFFFFFF */ )
  183. {
  184. Assert( ptr );
  185. }
  186. //-----------------------------------------------------------------------------
  187. // Should be called only inside a SpewOutputFunc_t, returns groupname, level, color
  188. //-----------------------------------------------------------------------------
  189. const tchar* GetSpewOutputGroup( void )
  190. {
  191. SpewInfo_t *pSpewInfo = g_pSpewInfo;
  192. assert( pSpewInfo );
  193. if ( pSpewInfo )
  194. return pSpewInfo->m_pSpewOutputGroup;
  195. return NULL;
  196. }
  197. int GetSpewOutputLevel( void )
  198. {
  199. SpewInfo_t *pSpewInfo = g_pSpewInfo;
  200. assert( pSpewInfo );
  201. if ( pSpewInfo )
  202. return pSpewInfo->m_nSpewOutputLevel;
  203. return -1;
  204. }
  205. const Color* GetSpewOutputColor( void )
  206. {
  207. SpewInfo_t *pSpewInfo = g_pSpewInfo;
  208. assert( pSpewInfo );
  209. if ( pSpewInfo )
  210. return pSpewInfo->m_pSpewOutputColor;
  211. return &s_DefaultOutputColor;
  212. }
  213. //-----------------------------------------------------------------------------
  214. // Spew functions
  215. //-----------------------------------------------------------------------------
  216. DBG_INTERFACE void _SpewInfo( SpewType_t type, const tchar* pFile, int line )
  217. {
  218. // Only grab the file name. Ignore the path.
  219. s_pFileName = SkipToFname( pFile );
  220. s_Line = line;
  221. s_SpewType = type;
  222. }
  223. static SpewRetval_t _SpewMessage( SpewType_t spewType, const char *pGroupName, int nLevel, const Color *pColor, const tchar* pMsgFormat, va_list args )
  224. {
  225. tchar pTempBuffer[5020];
  226. assert( _tcslen( pMsgFormat ) < sizeof( pTempBuffer) ); // check that we won't artifically truncate the string
  227. /* Printf the file and line for warning + assert only... */
  228. int len = 0;
  229. if ( spewType == SPEW_ASSERT )
  230. {
  231. len = _sntprintf( pTempBuffer, sizeof( pTempBuffer ) - 1, _T("%s (%d) : "), s_pFileName, s_Line );
  232. }
  233. if ( len == -1 )
  234. return SPEW_ABORT;
  235. /* Create the message.... */
  236. int val= _vsntprintf( &pTempBuffer[len], sizeof( pTempBuffer ) - len - 1, pMsgFormat, args );
  237. if ( val == -1 )
  238. return SPEW_ABORT;
  239. len += val;
  240. assert( len * sizeof(*pMsgFormat) < sizeof(pTempBuffer) ); /* use normal assert here; to avoid recursion. */
  241. // Add \n for warning and assert
  242. if ( spewType == SPEW_ASSERT )
  243. {
  244. len += _stprintf( &pTempBuffer[len], _T("\n") );
  245. }
  246. assert( len < sizeof(pTempBuffer)/sizeof(pTempBuffer[0]) - 1 ); /* use normal assert here; to avoid recursion. */
  247. assert( s_SpewOutputFunc );
  248. /* direct it to the appropriate target(s) */
  249. SpewRetval_t ret;
  250. assert( g_pSpewInfo == NULL );
  251. SpewInfo_t spewInfo =
  252. {
  253. pColor,
  254. pGroupName,
  255. nLevel
  256. };
  257. g_pSpewInfo = &spewInfo;
  258. ret = s_SpewOutputFunc( spewType, pTempBuffer );
  259. g_pSpewInfo = (int)NULL;
  260. switch (ret)
  261. {
  262. // Asserts put the break into the macro so it occurs in the right place
  263. case SPEW_DEBUGGER:
  264. if ( spewType != SPEW_ASSERT )
  265. {
  266. DebuggerBreak();
  267. }
  268. break;
  269. case SPEW_ABORT:
  270. {
  271. // MessageBox(NULL,"Error in _SpewMessage","Error",MB_OK);
  272. // ConMsg( _T("Exiting on SPEW_ABORT\n") );
  273. exit(1);
  274. }
  275. }
  276. return ret;
  277. }
  278. #include "tier0/valve_off.h"
  279. FORCEINLINE SpewRetval_t _SpewMessage( SpewType_t spewType, const tchar* pMsgFormat, va_list args )
  280. {
  281. return _SpewMessage( spewType, "", 0, &s_DefaultOutputColor, pMsgFormat, args );
  282. }
  283. //-----------------------------------------------------------------------------
  284. // Find a group, return true if found, false if not. Return in ind the
  285. // index of the found group, or the index of the group right before where the
  286. // group should be inserted into the list to maintain sorted order.
  287. //-----------------------------------------------------------------------------
  288. bool FindSpewGroup( const tchar* pGroupName, int* pInd )
  289. {
  290. int s = 0;
  291. if (s_GroupCount)
  292. {
  293. int e = (int)(s_GroupCount - 1);
  294. while ( s <= e )
  295. {
  296. int m = (s+e) >> 1;
  297. int cmp = _tcsicmp( pGroupName, s_pSpewGroups[m].m_GroupName );
  298. if ( !cmp )
  299. {
  300. *pInd = m;
  301. return true;
  302. }
  303. if ( cmp < 0 )
  304. e = m - 1;
  305. else
  306. s = m + 1;
  307. }
  308. }
  309. *pInd = s;
  310. return false;
  311. }
  312. //-----------------------------------------------------------------------------
  313. // True if -hushasserts was passed on command line.
  314. //-----------------------------------------------------------------------------
  315. bool HushAsserts()
  316. {
  317. #ifdef DBGFLAG_ASSERT
  318. static bool s_bHushAsserts = !!CommandLine()->FindParm( "-hushasserts" );
  319. return s_bHushAsserts;
  320. #else
  321. return true;
  322. #endif
  323. }
  324. //-----------------------------------------------------------------------------
  325. // Tests to see if a particular spew is active
  326. //-----------------------------------------------------------------------------
  327. bool IsSpewActive( const tchar* pGroupName, int level )
  328. {
  329. // If we don't find the spew group, use the default level.
  330. int ind;
  331. if ( FindSpewGroup( pGroupName, &ind ) )
  332. return s_pSpewGroups[ind].m_Level >= level;
  333. else
  334. return s_DefaultLevel >= level;
  335. }
  336. inline bool IsSpewActive( StandardSpewGroup_t group, int level )
  337. {
  338. // If we don't find the spew group, use the default level.
  339. if ( s_pGroupIndices[group] >= 0 )
  340. return s_pSpewGroups[ s_pGroupIndices[group] ].m_Level >= level;
  341. return s_DefaultLevel >= level;
  342. }
  343. SpewRetval_t _SpewMessage( const tchar* pMsgFormat, ... )
  344. {
  345. va_list args;
  346. va_start( args, pMsgFormat );
  347. SpewRetval_t ret = _SpewMessage( s_SpewType, pMsgFormat, args );
  348. va_end(args);
  349. return ret;
  350. }
  351. SpewRetval_t _DSpewMessage( const tchar *pGroupName, int level, const tchar* pMsgFormat, ... )
  352. {
  353. if( !IsSpewActive( pGroupName, level ) )
  354. return SPEW_CONTINUE;
  355. va_list args;
  356. va_start( args, pMsgFormat );
  357. SpewRetval_t ret = _SpewMessage( s_SpewType, pGroupName, level, &s_DefaultOutputColor, pMsgFormat, args );
  358. va_end(args);
  359. return ret;
  360. }
  361. DBG_INTERFACE SpewRetval_t ColorSpewMessage( SpewType_t type, const Color *pColor, const tchar* pMsgFormat, ... )
  362. {
  363. va_list args;
  364. va_start( args, pMsgFormat );
  365. SpewRetval_t ret = _SpewMessage( type, "", 0, pColor, pMsgFormat, args );
  366. va_end(args);
  367. return ret;
  368. }
  369. void Msg( const tchar* pMsgFormat, ... )
  370. {
  371. va_list args;
  372. va_start( args, pMsgFormat );
  373. _SpewMessage( SPEW_MESSAGE, pMsgFormat, args );
  374. va_end(args);
  375. }
  376. void DMsg( const tchar *pGroupName, int level, const tchar *pMsgFormat, ... )
  377. {
  378. if( !IsSpewActive( pGroupName, level ) )
  379. return;
  380. va_list args;
  381. va_start( args, pMsgFormat );
  382. _SpewMessage( SPEW_MESSAGE, pGroupName, level, &s_DefaultOutputColor, pMsgFormat, args );
  383. va_end(args);
  384. }
  385. void MsgV( PRINTF_FORMAT_STRING const tchar *pMsg, va_list arglist )
  386. {
  387. _SpewMessage( SPEW_MESSAGE, pMsg, arglist );
  388. }
  389. void Warning( const tchar *pMsgFormat, ... )
  390. {
  391. va_list args;
  392. va_start( args, pMsgFormat );
  393. _SpewMessage( SPEW_WARNING, pMsgFormat, args );
  394. va_end(args);
  395. }
  396. void DWarning( const tchar *pGroupName, int level, const tchar *pMsgFormat, ... )
  397. {
  398. if( !IsSpewActive( pGroupName, level ) )
  399. return;
  400. va_list args;
  401. va_start( args, pMsgFormat );
  402. _SpewMessage( SPEW_WARNING, pGroupName, level, &s_DefaultOutputColor, pMsgFormat, args );
  403. va_end(args);
  404. }
  405. void WarningV( PRINTF_FORMAT_STRING const tchar *pMsg, va_list arglist )
  406. {
  407. _SpewMessage( SPEW_WARNING, pMsg, arglist );
  408. }
  409. void Log( const tchar *pMsgFormat, ... )
  410. {
  411. va_list args;
  412. va_start( args, pMsgFormat );
  413. _SpewMessage( SPEW_LOG, pMsgFormat, args );
  414. va_end(args);
  415. }
  416. void DLog( const tchar *pGroupName, int level, const tchar *pMsgFormat, ... )
  417. {
  418. if( !IsSpewActive( pGroupName, level ) )
  419. return;
  420. va_list args;
  421. va_start( args, pMsgFormat );
  422. _SpewMessage( SPEW_LOG, pGroupName, level, &s_DefaultOutputColor, pMsgFormat, args );
  423. va_end(args);
  424. }
  425. void LogV( PRINTF_FORMAT_STRING const tchar *pMsg, va_list arglist )
  426. {
  427. _SpewMessage( SPEW_LOG, pMsg, arglist );
  428. }
  429. void Error( const tchar *pMsgFormat, ... )
  430. {
  431. va_list args;
  432. va_start( args, pMsgFormat );
  433. _SpewMessage( SPEW_ERROR, pMsgFormat, args );
  434. va_end(args);
  435. }
  436. void ErrorV( PRINTF_FORMAT_STRING const tchar *pMsg, va_list arglist )
  437. {
  438. _SpewMessage( SPEW_ERROR, pMsg, arglist );
  439. }
  440. //-----------------------------------------------------------------------------
  441. // A couple of super-common dynamic spew messages, here for convenience
  442. // These looked at the "developer" group, print if it's level 1 or higher
  443. //-----------------------------------------------------------------------------
  444. void DevMsg( int level, const tchar* pMsgFormat, ... )
  445. {
  446. if( !IsSpewActive( GROUP_DEVELOPER, level ) )
  447. return;
  448. va_list args;
  449. va_start( args, pMsgFormat );
  450. _SpewMessage( SPEW_MESSAGE, s_pDeveloper, level, &s_DefaultOutputColor, pMsgFormat, args );
  451. va_end(args);
  452. }
  453. void DevWarning( int level, const tchar *pMsgFormat, ... )
  454. {
  455. if( !IsSpewActive( GROUP_DEVELOPER, level ) )
  456. return;
  457. va_list args;
  458. va_start( args, pMsgFormat );
  459. _SpewMessage( SPEW_WARNING, s_pDeveloper, level, &s_DefaultOutputColor, pMsgFormat, args );
  460. va_end(args);
  461. }
  462. void DevLog( int level, const tchar *pMsgFormat, ... )
  463. {
  464. if( !IsSpewActive( GROUP_DEVELOPER, level ) )
  465. return;
  466. va_list args;
  467. va_start( args, pMsgFormat );
  468. _SpewMessage( SPEW_LOG, s_pDeveloper, level, &s_DefaultOutputColor, pMsgFormat, args );
  469. va_end(args);
  470. }
  471. void DevMsg( const tchar *pMsgFormat, ... )
  472. {
  473. if( !IsSpewActive( GROUP_DEVELOPER, 1 ) )
  474. return;
  475. va_list args;
  476. va_start( args, pMsgFormat );
  477. _SpewMessage( SPEW_MESSAGE, s_pDeveloper, 1, &s_DefaultOutputColor, pMsgFormat, args );
  478. va_end(args);
  479. }
  480. void DevWarning( const tchar *pMsgFormat, ... )
  481. {
  482. if( !IsSpewActive( GROUP_DEVELOPER, 1 ) )
  483. return;
  484. va_list args;
  485. va_start( args, pMsgFormat );
  486. _SpewMessage( SPEW_WARNING, s_pDeveloper, 1, &s_DefaultOutputColor, pMsgFormat, args );
  487. va_end(args);
  488. }
  489. void DevLog( const tchar *pMsgFormat, ... )
  490. {
  491. if( !IsSpewActive( GROUP_DEVELOPER, 1 ) )
  492. return;
  493. va_list args;
  494. va_start( args, pMsgFormat );
  495. _SpewMessage( SPEW_LOG, s_pDeveloper, 1, &s_DefaultOutputColor, pMsgFormat, args );
  496. va_end(args);
  497. }
  498. //-----------------------------------------------------------------------------
  499. // A couple of super-common dynamic spew messages, here for convenience
  500. // These looked at the "console" group, print if it's level 1 or higher
  501. //-----------------------------------------------------------------------------
  502. void ConColorMsg( int level, const Color& clr, const tchar* pMsgFormat, ... )
  503. {
  504. if( !IsSpewActive( GROUP_CONSOLE, level ) )
  505. return;
  506. va_list args;
  507. va_start( args, pMsgFormat );
  508. _SpewMessage( SPEW_MESSAGE, s_pConsole, level, &clr, pMsgFormat, args );
  509. va_end(args);
  510. }
  511. void ConMsg( int level, const tchar* pMsgFormat, ... )
  512. {
  513. if( !IsSpewActive( GROUP_CONSOLE, level ) )
  514. return;
  515. va_list args;
  516. va_start( args, pMsgFormat );
  517. _SpewMessage( SPEW_MESSAGE, s_pConsole, level, &s_DefaultOutputColor, pMsgFormat, args );
  518. va_end(args);
  519. }
  520. void ConWarning( int level, const tchar *pMsgFormat, ... )
  521. {
  522. if( !IsSpewActive( GROUP_CONSOLE, level ) )
  523. return;
  524. va_list args;
  525. va_start( args, pMsgFormat );
  526. _SpewMessage( SPEW_WARNING, s_pConsole, level, &s_DefaultOutputColor, pMsgFormat, args );
  527. va_end(args);
  528. }
  529. void ConLog( int level, const tchar *pMsgFormat, ... )
  530. {
  531. if( !IsSpewActive( GROUP_CONSOLE, level ) )
  532. return;
  533. va_list args;
  534. va_start( args, pMsgFormat );
  535. _SpewMessage( SPEW_LOG, s_pConsole, level, &s_DefaultOutputColor, pMsgFormat, args );
  536. va_end(args);
  537. }
  538. void ConColorMsg( const Color& clr, const tchar* pMsgFormat, ... )
  539. {
  540. if( !IsSpewActive( GROUP_CONSOLE, 1 ) )
  541. return;
  542. va_list args;
  543. va_start( args, pMsgFormat );
  544. _SpewMessage( SPEW_MESSAGE, s_pConsole, 1, &clr, pMsgFormat, args );
  545. va_end(args);
  546. }
  547. void ConMsg( const tchar *pMsgFormat, ... )
  548. {
  549. if( !IsSpewActive( GROUP_CONSOLE, 1 ) )
  550. return;
  551. va_list args;
  552. va_start( args, pMsgFormat );
  553. _SpewMessage( SPEW_MESSAGE, s_pConsole, 1, &s_DefaultOutputColor, pMsgFormat, args );
  554. va_end(args);
  555. }
  556. void ConWarning( const tchar *pMsgFormat, ... )
  557. {
  558. if( !IsSpewActive( GROUP_CONSOLE, 1 ) )
  559. return;
  560. va_list args;
  561. va_start( args, pMsgFormat );
  562. _SpewMessage( SPEW_WARNING, s_pConsole, 1, &s_DefaultOutputColor, pMsgFormat, args );
  563. va_end(args);
  564. }
  565. void ConLog( const tchar *pMsgFormat, ... )
  566. {
  567. if( !IsSpewActive( GROUP_CONSOLE, 1 ) )
  568. return;
  569. va_list args;
  570. va_start( args, pMsgFormat );
  571. _SpewMessage( SPEW_LOG, s_pConsole, 1, &s_DefaultOutputColor, pMsgFormat, args );
  572. va_end(args);
  573. }
  574. void ConDColorMsg( const Color& clr, const tchar* pMsgFormat, ... )
  575. {
  576. if( !IsSpewActive( GROUP_CONSOLE, 2 ) )
  577. return;
  578. va_list args;
  579. va_start( args, pMsgFormat );
  580. _SpewMessage( SPEW_MESSAGE, s_pConsole, 2, &clr, pMsgFormat, args );
  581. va_end(args);
  582. }
  583. void ConDMsg( const tchar *pMsgFormat, ... )
  584. {
  585. if( !IsSpewActive( GROUP_CONSOLE, 2 ) )
  586. return;
  587. va_list args;
  588. va_start( args, pMsgFormat );
  589. _SpewMessage( SPEW_MESSAGE, s_pConsole, 2, &s_DefaultOutputColor, pMsgFormat, args );
  590. va_end(args);
  591. }
  592. void ConDWarning( const tchar *pMsgFormat, ... )
  593. {
  594. if( !IsSpewActive( GROUP_CONSOLE, 2 ) )
  595. return;
  596. va_list args;
  597. va_start( args, pMsgFormat );
  598. _SpewMessage( SPEW_WARNING, s_pConsole, 2, &s_DefaultOutputColor, pMsgFormat, args );
  599. va_end(args);
  600. }
  601. void ConDLog( const tchar *pMsgFormat, ... )
  602. {
  603. if( !IsSpewActive( GROUP_CONSOLE, 2 ) )
  604. return;
  605. va_list args;
  606. va_start( args, pMsgFormat );
  607. _SpewMessage( SPEW_LOG, s_pConsole, 2, &s_DefaultOutputColor, pMsgFormat, args );
  608. va_end(args);
  609. }
  610. //-----------------------------------------------------------------------------
  611. // A couple of super-common dynamic spew messages, here for convenience
  612. // These looked at the "network" group, print if it's level 1 or higher
  613. //-----------------------------------------------------------------------------
  614. void NetMsg( int level, const tchar* pMsgFormat, ... )
  615. {
  616. if( !IsSpewActive( GROUP_NETWORK, level ) )
  617. return;
  618. va_list args;
  619. va_start( args, pMsgFormat );
  620. _SpewMessage( SPEW_MESSAGE, s_pNetwork, level, &s_DefaultOutputColor, pMsgFormat, args );
  621. va_end(args);
  622. }
  623. void NetWarning( int level, const tchar *pMsgFormat, ... )
  624. {
  625. if( !IsSpewActive( GROUP_NETWORK, level ) )
  626. return;
  627. va_list args;
  628. va_start( args, pMsgFormat );
  629. _SpewMessage( SPEW_WARNING, s_pNetwork, level, &s_DefaultOutputColor, pMsgFormat, args );
  630. va_end(args);
  631. }
  632. void NetLog( int level, const tchar *pMsgFormat, ... )
  633. {
  634. if( !IsSpewActive( GROUP_NETWORK, level ) )
  635. return;
  636. va_list args;
  637. va_start( args, pMsgFormat );
  638. _SpewMessage( SPEW_LOG, s_pNetwork, level, &s_DefaultOutputColor, pMsgFormat, args );
  639. va_end(args);
  640. }
  641. #include "tier0/valve_on.h"
  642. //-----------------------------------------------------------------------------
  643. // Sets the priority level for a spew group
  644. //-----------------------------------------------------------------------------
  645. void SpewActivate( const tchar* pGroupName, int level )
  646. {
  647. Assert( pGroupName );
  648. // check for the default group first...
  649. if ((pGroupName[0] == '*') && (pGroupName[1] == '\0'))
  650. {
  651. s_DefaultLevel = level;
  652. return;
  653. }
  654. // Normal case, search in group list using binary search.
  655. // If not found, grow the list of groups and insert it into the
  656. // right place to maintain sorted order. Then set the level.
  657. int ind;
  658. if ( !FindSpewGroup( pGroupName, &ind ) )
  659. {
  660. // not defined yet, insert an entry.
  661. ++s_GroupCount;
  662. if ( s_pSpewGroups )
  663. {
  664. s_pSpewGroups = (SpewGroup_t*)PvRealloc( s_pSpewGroups,
  665. s_GroupCount * sizeof(SpewGroup_t) );
  666. // shift elements down to preserve order
  667. int numToMove = s_GroupCount - ind - 1;
  668. memmove( &s_pSpewGroups[ind+1], &s_pSpewGroups[ind],
  669. numToMove * sizeof(SpewGroup_t) );
  670. // Update standard groups
  671. for ( int i = 0; i < GROUP_COUNT; ++i )
  672. {
  673. if ( ( ind <= s_pGroupIndices[i] ) && ( s_pGroupIndices[i] >= 0 ) )
  674. {
  675. ++s_pGroupIndices[i];
  676. }
  677. }
  678. }
  679. else
  680. {
  681. s_pSpewGroups = (SpewGroup_t*)PvAlloc( s_GroupCount * sizeof(SpewGroup_t) );
  682. }
  683. Assert( _tcslen( pGroupName ) < MAX_GROUP_NAME_LENGTH );
  684. _tcscpy( s_pSpewGroups[ind].m_GroupName, pGroupName );
  685. // Update standard groups
  686. for ( int i = 0; i < GROUP_COUNT; ++i )
  687. {
  688. if ( ( s_pGroupIndices[i] < 0 ) && !_tcsicmp( s_pGroupNames[i], pGroupName ) )
  689. {
  690. s_pGroupIndices[i] = ind;
  691. break;
  692. }
  693. }
  694. }
  695. s_pSpewGroups[ind].m_Level = level;
  696. }
  697. // If we don't have a function from math.h, then it doesn't link certain floating-point
  698. // functions in and printfs with %f cause runtime errors in the C libraries.
  699. DBG_INTERFACE float CrackSmokingCompiler( float a )
  700. {
  701. return (float)fabs( a );
  702. }
  703. void* Plat_SimpleLog( const tchar* file, int line )
  704. {
  705. FILE* f = _tfopen( _T("simple.log"), _T("at+") );
  706. _ftprintf( f, _T("%s:%i\n"), file, line );
  707. fclose( f );
  708. return NULL;
  709. }
  710. #ifdef DBGFLAG_VALIDATE
  711. void ValidateSpew( CValidator &validator )
  712. {
  713. validator.Push( _T("Spew globals"), NULL, _T("Global") );
  714. validator.ClaimMemory( s_pSpewGroups );
  715. validator.Pop( );
  716. }
  717. #endif // DBGFLAG_VALIDATE
  718. //-----------------------------------------------------------------------------
  719. // Purpose: For debugging startup times, etc.
  720. // Input : *fmt -
  721. // ... -
  722. //-----------------------------------------------------------------------------
  723. void COM_TimestampedLog( char const *fmt, ... )
  724. {
  725. static float s_LastStamp = 0.0;
  726. static bool s_bShouldLog = false;
  727. static bool s_bShouldLogToETW = false;
  728. static bool s_bChecked = false;
  729. static bool s_bFirstWrite = false;
  730. if ( !s_bChecked )
  731. {
  732. s_bShouldLog = ( IsX360() || CommandLine()->CheckParm( "-profile" ) ) ? true : false;
  733. s_bShouldLogToETW = ( CommandLine()->CheckParm( "-etwprofile" ) ) ? true : false;
  734. if ( s_bShouldLogToETW )
  735. {
  736. s_bShouldLog = true;
  737. }
  738. s_bChecked = true;
  739. }
  740. if ( !s_bShouldLog )
  741. {
  742. return;
  743. }
  744. char string[1024];
  745. va_list argptr;
  746. va_start( argptr, fmt );
  747. _vsnprintf( string, sizeof( string ), fmt, argptr );
  748. va_end( argptr );
  749. float curStamp = Plat_FloatTime();
  750. #if defined( _X360 )
  751. XBX_rTimeStampLog( curStamp, string );
  752. #endif
  753. if ( IsPC() )
  754. {
  755. // If ETW profiling is enabled then do it only.
  756. if ( s_bShouldLogToETW )
  757. {
  758. ETWMark( string );
  759. }
  760. else
  761. {
  762. if ( !s_bFirstWrite )
  763. {
  764. unlink( "timestamped.log" );
  765. s_bFirstWrite = true;
  766. }
  767. FILE* fp = fopen( "timestamped.log", "at+" );
  768. fprintf( fp, "%8.4f / %8.4f: %s\n", curStamp, curStamp - s_LastStamp, string );
  769. fclose( fp );
  770. }
  771. }
  772. s_LastStamp = curStamp;
  773. }
  774. //-----------------------------------------------------------------------------
  775. // Sets an assert failed notify handler
  776. //-----------------------------------------------------------------------------
  777. void SetAssertFailedNotifyFunc( AssertFailedNotifyFunc_t func )
  778. {
  779. s_AssertFailedNotifyFunc = func;
  780. }
  781. //-----------------------------------------------------------------------------
  782. // Calls the assert failed notify handler if one has been set
  783. //-----------------------------------------------------------------------------
  784. void CallAssertFailedNotifyFunc( const char *pchFile, int nLine, const char *pchMessage )
  785. {
  786. if ( s_AssertFailedNotifyFunc )
  787. s_AssertFailedNotifyFunc( pchFile, nLine, pchMessage );
  788. }