//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ // //===========================================================================// #include "vstdlib/cvar.h" #include #include "tier0/icommandline.h" #include "tier1/utlrbtree.h" #include "tier1/strtools.h" #include "tier1/KeyValues.h" #include "tier1/convar.h" #include "tier0/vprof.h" #include "tier1/tier1.h" #include "tier1/utlbuffer.h" #ifdef _X360 #include "xbox/xbox_console.h" #endif #ifdef POSIX #include #include #endif // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" //----------------------------------------------------------------------------- // Default implementation of CvarQuery //----------------------------------------------------------------------------- class CDefaultCvarQuery : public CBaseAppSystem< ICvarQuery > { public: virtual void *QueryInterface( const char *pInterfaceName ) { if ( !Q_stricmp( pInterfaceName, CVAR_QUERY_INTERFACE_VERSION ) ) return (ICvarQuery*)this; return NULL; } virtual bool AreConVarsLinkable( const ConVar *child, const ConVar *parent ) { return true; } }; static CDefaultCvarQuery s_DefaultCvarQuery; static ICvarQuery *s_pCVarQuery = NULL; //----------------------------------------------------------------------------- // Default implementation //----------------------------------------------------------------------------- class CCvar : public ICvar { public: CCvar(); // Methods of IAppSystem virtual bool Connect( CreateInterfaceFn factory ); virtual void Disconnect(); virtual void *QueryInterface( const char *pInterfaceName ); virtual InitReturnVal_t Init(); virtual void Shutdown(); // Inherited from ICVar virtual CVarDLLIdentifier_t AllocateDLLIdentifier(); virtual void RegisterConCommand( ConCommandBase *pCommandBase ); virtual void UnregisterConCommand( ConCommandBase *pCommandBase ); virtual void UnregisterConCommands( CVarDLLIdentifier_t id ); virtual const char* GetCommandLineValue( const char *pVariableName ); virtual ConCommandBase *FindCommandBase( const char *name ); virtual const ConCommandBase *FindCommandBase( const char *name ) const; virtual ConVar *FindVar ( const char *var_name ); virtual const ConVar *FindVar ( const char *var_name ) const; virtual ConCommand *FindCommand( const char *name ); virtual const ConCommand *FindCommand( const char *name ) const; virtual ConCommandBase *GetCommands( void ); virtual const ConCommandBase *GetCommands( void ) const; virtual void InstallGlobalChangeCallback( FnChangeCallback_t callback ); virtual void RemoveGlobalChangeCallback( FnChangeCallback_t callback ); virtual void CallGlobalChangeCallbacks( ConVar *var, const char *pOldString, float flOldValue ); virtual void InstallConsoleDisplayFunc( IConsoleDisplayFunc* pDisplayFunc ); virtual void RemoveConsoleDisplayFunc( IConsoleDisplayFunc* pDisplayFunc ); virtual void ConsoleColorPrintf( const Color& clr, const char *pFormat, ... ) const; virtual void ConsolePrintf( const char *pFormat, ... ) const; virtual void ConsoleDPrintf( const char *pFormat, ... ) const; virtual void RevertFlaggedConVars( int nFlag ); virtual void InstallCVarQuery( ICvarQuery *pQuery ); #if defined( _X360 ) virtual void PublishToVXConsole( ); #endif virtual bool IsMaterialThreadSetAllowed( ) const; virtual void QueueMaterialThreadSetValue( ConVar *pConVar, const char *pValue ); virtual void QueueMaterialThreadSetValue( ConVar *pConVar, int nValue ); virtual void QueueMaterialThreadSetValue( ConVar *pConVar, float flValue ); virtual bool HasQueuedMaterialThreadConVarSets() const; virtual int ProcessQueuedMaterialThreadConVarSets(); private: enum { CONSOLE_COLOR_PRINT = 0, CONSOLE_PRINT, CONSOLE_DPRINT, }; void DisplayQueuedMessages( ); CUtlVector< FnChangeCallback_t > m_GlobalChangeCallbacks; CUtlVector< IConsoleDisplayFunc* > m_DisplayFuncs; int m_nNextDLLIdentifier; ConCommandBase *m_pConCommandList; // temporary console area so we can store prints before console display funs are installed mutable CUtlBuffer m_TempConsoleBuffer; protected: // internals for ICVarIterator class CCVarIteratorInternal : public ICVarIteratorInternal { public: CCVarIteratorInternal( CCvar *outer ) : m_pOuter( outer ) //, m_pHash( &outer->m_CommandHash ), // remember my CCvar, //m_hashIter( -1, -1 ) // and invalid iterator , m_pCur( NULL ) {} virtual void SetFirst( void ); virtual void Next( void ); virtual bool IsValid( void ); virtual ConCommandBase *Get( void ); protected: CCvar * const m_pOuter; //CConCommandHash * const m_pHash; //CConCommandHash::CCommandHashIterator_t m_hashIter; ConCommandBase *m_pCur; }; virtual ICVarIteratorInternal *FactoryInternalIterator( void ); friend class CCVarIteratorInternal; enum ConVarSetType_t { CONVAR_SET_STRING = 0, CONVAR_SET_INT, CONVAR_SET_FLOAT, }; struct QueuedConVarSet_t { ConVar *m_pConVar; ConVarSetType_t m_nType; int m_nInt; float m_flFloat; CUtlString m_String; }; CUtlVector< QueuedConVarSet_t > m_QueuedConVarSets; bool m_bMaterialSystemThreadSetAllowed; private: // Standard console commands -- DO NOT PLACE ANY HIGHER THAN HERE BECAUSE THESE MUST BE THE FIRST TO DESTRUCT CON_COMMAND_MEMBER_F( CCvar, "find", Find, "Find concommands with the specified string in their name/help text.", 0 ) }; void CCvar::CCVarIteratorInternal::SetFirst( void ) RESTRICT { //m_hashIter = m_pHash->First(); m_pCur = m_pOuter->GetCommands(); } void CCvar::CCVarIteratorInternal::Next( void ) RESTRICT { //m_hashIter = m_pHash->Next( m_hashIter ); if ( m_pCur ) m_pCur = m_pCur->GetNext(); } bool CCvar::CCVarIteratorInternal::IsValid( void ) RESTRICT { //return m_pHash->IsValidIterator( m_hashIter ); return m_pCur != NULL; } ConCommandBase *CCvar::CCVarIteratorInternal::Get( void ) RESTRICT { Assert( IsValid( ) ); //return (*m_pHash)[m_hashIter]; return m_pCur; } ICvar::ICVarIteratorInternal *CCvar::FactoryInternalIterator( void ) { return new CCVarIteratorInternal( this ); } //----------------------------------------------------------------------------- // Factor for CVars //----------------------------------------------------------------------------- static CCvar s_Cvar; EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CCvar, ICvar, CVAR_INTERFACE_VERSION, s_Cvar ); //----------------------------------------------------------------------------- // Returns a CVar dictionary for tool usage //----------------------------------------------------------------------------- CreateInterfaceFn VStdLib_GetICVarFactory() { return Sys_GetFactoryThis(); } //----------------------------------------------------------------------------- // Constructor //----------------------------------------------------------------------------- CCvar::CCvar() : m_TempConsoleBuffer( 0, 1024 ) { m_nNextDLLIdentifier = 0; m_pConCommandList = NULL; m_bMaterialSystemThreadSetAllowed = false; } //----------------------------------------------------------------------------- // Methods of IAppSystem //----------------------------------------------------------------------------- bool CCvar::Connect( CreateInterfaceFn factory ) { ConnectTier1Libraries( &factory, 1 ); s_pCVarQuery = (ICvarQuery*)factory( CVAR_QUERY_INTERFACE_VERSION, NULL ); if ( !s_pCVarQuery ) { s_pCVarQuery = &s_DefaultCvarQuery; } ConVar_Register(); return true; } void CCvar::Disconnect() { ConVar_Unregister(); s_pCVarQuery = NULL; DisconnectTier1Libraries(); } InitReturnVal_t CCvar::Init() { return INIT_OK; } void CCvar::Shutdown() { } void *CCvar::QueryInterface( const char *pInterfaceName ) { // We implement the ICvar interface if ( !V_strcmp( pInterfaceName, CVAR_INTERFACE_VERSION ) ) return (ICvar*)this; return NULL; } //----------------------------------------------------------------------------- // Method allowing the engine ICvarQuery interface to take over //----------------------------------------------------------------------------- void CCvar::InstallCVarQuery( ICvarQuery *pQuery ) { Assert( s_pCVarQuery == &s_DefaultCvarQuery ); s_pCVarQuery = pQuery ? pQuery : &s_DefaultCvarQuery; } //----------------------------------------------------------------------------- // Used by DLLs to be able to unregister all their commands + convars //----------------------------------------------------------------------------- CVarDLLIdentifier_t CCvar::AllocateDLLIdentifier() { return m_nNextDLLIdentifier++; } //----------------------------------------------------------------------------- // Purpose: // Input : *variable - //----------------------------------------------------------------------------- void CCvar::RegisterConCommand( ConCommandBase *variable ) { // Already registered if ( variable->IsRegistered() ) return; variable->m_bRegistered = true; const char *pName = variable->GetName(); if ( !pName || !pName[0] ) { variable->m_pNext = NULL; return; } // If the variable is already defined, then setup the new variable as a proxy to it. const ConCommandBase *pOther = FindVar( variable->GetName() ); if ( pOther ) { if ( variable->IsCommand() || pOther->IsCommand() ) { Warning( "WARNING: unable to link %s and %s because one or more is a ConCommand.\n", variable->GetName(), pOther->GetName() ); } else { // This cast is ok because we make sure they're ConVars above. const ConVar *pChildVar = static_cast< const ConVar* >( variable ); const ConVar *pParentVar = static_cast< const ConVar* >( pOther ); // See if it's a valid linkage if ( s_pCVarQuery->AreConVarsLinkable( pChildVar, pParentVar ) ) { // Make sure the default values are the same (but only spew about this for FCVAR_REPLICATED) if( pChildVar->m_pszDefaultValue && pParentVar->m_pszDefaultValue && pChildVar->IsFlagSet( FCVAR_REPLICATED ) && pParentVar->IsFlagSet( FCVAR_REPLICATED ) ) { if( Q_stricmp( pChildVar->m_pszDefaultValue, pParentVar->m_pszDefaultValue ) != 0 ) { Warning( "Parent and child ConVars with different default values! %s child: %s parent: %s (parent wins)\n", variable->GetName(), pChildVar->m_pszDefaultValue, pParentVar->m_pszDefaultValue ); } } const_cast( pChildVar )->m_pParent = const_cast( pParentVar )->m_pParent; // Absorb material thread related convar flags const_cast( pParentVar )->m_nFlags |= pChildVar->m_nFlags & ( FCVAR_MATERIAL_THREAD_MASK | FCVAR_ACCESSIBLE_FROM_THREADS ); // check the parent's callbacks and slam if doesn't have, warn if both have callbacks if( pChildVar->m_fnChangeCallback ) { if ( !pParentVar->m_fnChangeCallback ) { const_cast( pParentVar )->m_fnChangeCallback = pChildVar->m_fnChangeCallback; } else { Warning( "Convar %s has multiple different change callbacks\n", variable->GetName() ); } } // make sure we don't have conflicting help strings. if ( pChildVar->m_pszHelpString && Q_strlen( pChildVar->m_pszHelpString ) != 0 ) { if ( pParentVar->m_pszHelpString && Q_strlen( pParentVar->m_pszHelpString ) != 0 ) { if ( Q_stricmp( pParentVar->m_pszHelpString, pChildVar->m_pszHelpString ) != 0 ) { Warning( "Convar %s has multiple help strings:\n\tparent (wins): \"%s\"\n\tchild: \"%s\"\n", variable->GetName(), pParentVar->m_pszHelpString, pChildVar->m_pszHelpString ); } } else { const_cast( pParentVar )->m_pszHelpString = pChildVar->m_pszHelpString; } } // make sure we don't have conflicting FCVAR_CHEAT flags. if ( ( pChildVar->m_nFlags & FCVAR_CHEAT ) != ( pParentVar->m_nFlags & FCVAR_CHEAT ) ) { Warning( "Convar %s has conflicting FCVAR_CHEAT flags (child: %s, parent: %s, parent wins)\n", variable->GetName(), ( pChildVar->m_nFlags & FCVAR_CHEAT ) ? "FCVAR_CHEAT" : "no FCVAR_CHEAT", ( pParentVar->m_nFlags & FCVAR_CHEAT ) ? "FCVAR_CHEAT" : "no FCVAR_CHEAT" ); } // make sure we don't have conflicting FCVAR_REPLICATED flags. if ( ( pChildVar->m_nFlags & FCVAR_REPLICATED ) != ( pParentVar->m_nFlags & FCVAR_REPLICATED ) ) { Warning( "Convar %s has conflicting FCVAR_REPLICATED flags (child: %s, parent: %s, parent wins)\n", variable->GetName(), ( pChildVar->m_nFlags & FCVAR_REPLICATED ) ? "FCVAR_REPLICATED" : "no FCVAR_REPLICATED", ( pParentVar->m_nFlags & FCVAR_REPLICATED ) ? "FCVAR_REPLICATED" : "no FCVAR_REPLICATED" ); } // make sure we don't have conflicting FCVAR_DONTRECORD flags. if ( ( pChildVar->m_nFlags & FCVAR_DONTRECORD ) != ( pParentVar->m_nFlags & FCVAR_DONTRECORD ) ) { Warning( "Convar %s has conflicting FCVAR_DONTRECORD flags (child: %s, parent: %s, parent wins)\n", variable->GetName(), ( pChildVar->m_nFlags & FCVAR_DONTRECORD ) ? "FCVAR_DONTRECORD" : "no FCVAR_DONTRECORD", ( pParentVar->m_nFlags & FCVAR_DONTRECORD ) ? "FCVAR_DONTRECORD" : "no FCVAR_DONTRECORD" ); } } } variable->m_pNext = NULL; return; } // link the variable in variable->m_pNext = m_pConCommandList; m_pConCommandList = variable; } void CCvar::UnregisterConCommand( ConCommandBase *pCommandToRemove ) { // Not registered? Don't bother if ( !pCommandToRemove->IsRegistered() ) return; pCommandToRemove->m_bRegistered = false; // FIXME: Should we make this a doubly-linked list? Would remove faster ConCommandBase *pPrev = NULL; for( ConCommandBase *pCommand = m_pConCommandList; pCommand; pCommand = pCommand->m_pNext ) { if ( pCommand != pCommandToRemove ) { pPrev = pCommand; continue; } if ( pPrev == NULL ) { m_pConCommandList = pCommand->m_pNext; } else { pPrev->m_pNext = pCommand->m_pNext; } pCommand->m_pNext = NULL; break; } } // Crash here in TF2, so I'm adding some debugging stuff. #ifdef WIN32 #pragma optimize( "", off ) #endif void CCvar::UnregisterConCommands( CVarDLLIdentifier_t id ) { ConCommandBase *pNewList; ConCommandBase *pCommand, *pNext; int iCommandsLooped = 0; pNewList = NULL; pCommand = m_pConCommandList; while ( pCommand ) { pNext = pCommand->m_pNext; if ( pCommand->GetDLLIdentifier() != id ) { pCommand->m_pNext = pNewList; pNewList = pCommand; } else { // Unlink pCommand->m_bRegistered = false; pCommand->m_pNext = NULL; } pCommand = pNext; iCommandsLooped++; } m_pConCommandList = pNewList; } #ifdef WIN32 #pragma optimize( "", on ) #endif //----------------------------------------------------------------------------- // Finds base commands //----------------------------------------------------------------------------- const ConCommandBase *CCvar::FindCommandBase( const char *name ) const { const ConCommandBase *cmd = GetCommands(); for ( ; cmd; cmd = cmd->GetNext() ) { if ( !Q_stricmp( name, cmd->GetName() ) ) return cmd; } return NULL; } ConCommandBase *CCvar::FindCommandBase( const char *name ) { ConCommandBase *cmd = GetCommands(); for ( ; cmd; cmd = cmd->GetNext() ) { if ( !Q_stricmp( name, cmd->GetName() ) ) return cmd; } return NULL; } //----------------------------------------------------------------------------- // Purpose Finds ConVars //----------------------------------------------------------------------------- const ConVar *CCvar::FindVar( const char *var_name ) const { VPROF_INCREMENT_COUNTER( "CCvar::FindVar", 1 ); VPROF( "CCvar::FindVar" ); const ConCommandBase *var = FindCommandBase( var_name ); if ( !var || var->IsCommand() ) return NULL; return static_cast(var); } ConVar *CCvar::FindVar( const char *var_name ) { VPROF_INCREMENT_COUNTER( "CCvar::FindVar", 1 ); VPROF( "CCvar::FindVar" ); ConCommandBase *var = FindCommandBase( var_name ); if ( !var || var->IsCommand() ) return NULL; return static_cast( var ); } //----------------------------------------------------------------------------- // Purpose Finds ConCommands //----------------------------------------------------------------------------- const ConCommand *CCvar::FindCommand( const char *pCommandName ) const { const ConCommandBase *var = FindCommandBase( pCommandName ); if ( !var || !var->IsCommand() ) return NULL; return static_cast(var); } ConCommand *CCvar::FindCommand( const char *pCommandName ) { ConCommandBase *var = FindCommandBase( pCommandName ); if ( !var || !var->IsCommand() ) return NULL; return static_cast( var ); } const char* CCvar::GetCommandLineValue( const char *pVariableName ) { int nLen = Q_strlen(pVariableName); char *pSearch = (char*)stackalloc( nLen + 2 ); pSearch[0] = '+'; memcpy( &pSearch[1], pVariableName, nLen + 1 ); return CommandLine()->ParmValue( pSearch ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- ConCommandBase *CCvar::GetCommands( void ) { return m_pConCommandList; } const ConCommandBase *CCvar::GetCommands( void ) const { return m_pConCommandList; } //----------------------------------------------------------------------------- // Install, remove global callbacks //----------------------------------------------------------------------------- void CCvar::InstallGlobalChangeCallback( FnChangeCallback_t callback ) { Assert( callback && m_GlobalChangeCallbacks.Find( callback ) < 0 ); m_GlobalChangeCallbacks.AddToTail( callback ); } void CCvar::RemoveGlobalChangeCallback( FnChangeCallback_t callback ) { Assert( callback ); m_GlobalChangeCallbacks.FindAndRemove( callback ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CCvar::CallGlobalChangeCallbacks( ConVar *var, const char *pOldString, float flOldValue ) { int nCallbackCount = m_GlobalChangeCallbacks.Count(); for ( int i = 0; i < nCallbackCount; ++i ) { (*m_GlobalChangeCallbacks[i])( var, pOldString, flOldValue ); } } //----------------------------------------------------------------------------- // Sets convars containing the flags to their default value //----------------------------------------------------------------------------- void CCvar::RevertFlaggedConVars( int nFlag ) { for (const ConCommandBase *var= GetCommands() ; var ; var=var->GetNext()) { if ( var->IsCommand() ) continue; ConVar *pCvar = ( ConVar * )var; if ( !pCvar->IsFlagSet( nFlag ) ) continue; // It's == to the default value, don't count if ( !Q_stricmp( pCvar->GetDefault(), pCvar->GetString() ) ) continue; pCvar->Revert(); // DevMsg( "%s = \"%s\" (reverted)\n", cvar->GetName(), cvar->GetString() ); } } //----------------------------------------------------------------------------- // Deal with queued material system convars //----------------------------------------------------------------------------- bool CCvar::IsMaterialThreadSetAllowed( ) const { Assert( ThreadInMainThread() ); return m_bMaterialSystemThreadSetAllowed; } void CCvar::QueueMaterialThreadSetValue( ConVar *pConVar, const char *pValue ) { Assert( ThreadInMainThread() ); int j = m_QueuedConVarSets.AddToTail(); m_QueuedConVarSets[j].m_pConVar = pConVar; m_QueuedConVarSets[j].m_nType = CONVAR_SET_STRING; m_QueuedConVarSets[j].m_String = pValue; } void CCvar::QueueMaterialThreadSetValue( ConVar *pConVar, int nValue ) { Assert( ThreadInMainThread() ); int j = m_QueuedConVarSets.AddToTail(); m_QueuedConVarSets[j].m_pConVar = pConVar; m_QueuedConVarSets[j].m_nType = CONVAR_SET_INT; m_QueuedConVarSets[j].m_nInt = nValue; } void CCvar::QueueMaterialThreadSetValue( ConVar *pConVar, float flValue ) { Assert( ThreadInMainThread() ); int j = m_QueuedConVarSets.AddToTail(); m_QueuedConVarSets[j].m_pConVar = pConVar; m_QueuedConVarSets[j].m_nType = CONVAR_SET_FLOAT; m_QueuedConVarSets[j].m_flFloat = flValue; } bool CCvar::HasQueuedMaterialThreadConVarSets() const { Assert( ThreadInMainThread() ); return m_QueuedConVarSets.Count() > 0; } int CCvar::ProcessQueuedMaterialThreadConVarSets() { Assert( ThreadInMainThread() ); m_bMaterialSystemThreadSetAllowed = true; int nUpdateFlags = 0; int nCount = m_QueuedConVarSets.Count(); for ( int i = 0; i < nCount; ++i ) { const QueuedConVarSet_t& set = m_QueuedConVarSets[i]; switch( set.m_nType ) { case CONVAR_SET_FLOAT: set.m_pConVar->SetValue( set.m_flFloat ); break; case CONVAR_SET_INT: set.m_pConVar->SetValue( set.m_nInt ); break; case CONVAR_SET_STRING: set.m_pConVar->SetValue( set.m_String ); break; } nUpdateFlags |= set.m_pConVar->GetFlags() & FCVAR_MATERIAL_THREAD_MASK; } m_QueuedConVarSets.RemoveAll(); m_bMaterialSystemThreadSetAllowed = false; return nUpdateFlags; } //----------------------------------------------------------------------------- // Display queued messages //----------------------------------------------------------------------------- void CCvar::DisplayQueuedMessages( ) { // Display any queued up messages if ( m_TempConsoleBuffer.TellPut() == 0 ) return; Color clr; int nStringLength; while( m_TempConsoleBuffer.IsValid() ) { int nType = m_TempConsoleBuffer.GetChar(); if ( nType == CONSOLE_COLOR_PRINT ) { clr.SetRawColor( m_TempConsoleBuffer.GetInt() ); } nStringLength = m_TempConsoleBuffer.PeekStringLength(); char* pTemp = (char*)stackalloc( nStringLength + 1 ); m_TempConsoleBuffer.GetStringManualCharCount( pTemp, nStringLength + 1 ); switch( nType ) { case CONSOLE_COLOR_PRINT: ConsoleColorPrintf( clr, pTemp ); break; case CONSOLE_PRINT: ConsolePrintf( pTemp ); break; case CONSOLE_DPRINT: ConsoleDPrintf( pTemp ); break; } } m_TempConsoleBuffer.Purge(); } //----------------------------------------------------------------------------- // Install a console printer //----------------------------------------------------------------------------- void CCvar::InstallConsoleDisplayFunc( IConsoleDisplayFunc* pDisplayFunc ) { Assert( m_DisplayFuncs.Find( pDisplayFunc ) < 0 ); m_DisplayFuncs.AddToTail( pDisplayFunc ); DisplayQueuedMessages(); } void CCvar::RemoveConsoleDisplayFunc( IConsoleDisplayFunc* pDisplayFunc ) { m_DisplayFuncs.FindAndRemove( pDisplayFunc ); } void CCvar::ConsoleColorPrintf( const Color& clr, const char *pFormat, ... ) const { char temp[ 8192 ]; va_list argptr; va_start( argptr, pFormat ); _vsnprintf( temp, sizeof( temp ) - 1, pFormat, argptr ); va_end( argptr ); temp[ sizeof( temp ) - 1 ] = 0; int c = m_DisplayFuncs.Count(); if ( c == 0 ) { m_TempConsoleBuffer.PutChar( CONSOLE_COLOR_PRINT ); m_TempConsoleBuffer.PutInt( clr.GetRawColor() ); m_TempConsoleBuffer.PutString( temp ); return; } for ( int i = 0 ; i < c; ++i ) { m_DisplayFuncs[ i ]->ColorPrint( clr, temp ); } } void CCvar::ConsolePrintf( const char *pFormat, ... ) const { char temp[ 8192 ]; va_list argptr; va_start( argptr, pFormat ); _vsnprintf( temp, sizeof( temp ) - 1, pFormat, argptr ); va_end( argptr ); temp[ sizeof( temp ) - 1 ] = 0; int c = m_DisplayFuncs.Count(); if ( c == 0 ) { m_TempConsoleBuffer.PutChar( CONSOLE_PRINT ); m_TempConsoleBuffer.PutString( temp ); return; } for ( int i = 0 ; i < c; ++i ) { m_DisplayFuncs[ i ]->Print( temp ); } } void CCvar::ConsoleDPrintf( const char *pFormat, ... ) const { char temp[ 8192 ]; va_list argptr; va_start( argptr, pFormat ); _vsnprintf( temp, sizeof( temp ) - 1, pFormat, argptr ); va_end( argptr ); temp[ sizeof( temp ) - 1 ] = 0; int c = m_DisplayFuncs.Count(); if ( c == 0 ) { m_TempConsoleBuffer.PutChar( CONSOLE_DPRINT ); m_TempConsoleBuffer.PutString( temp ); return; } for ( int i = 0 ; i < c; ++i ) { m_DisplayFuncs[ i ]->DPrint( temp ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- #if defined( _X360 ) void CCvar::PublishToVXConsole() { const char *commands[4096]; const char *helptext[4096]; const ConCommandBase *pCur; int numCommands = 0; // iterate and publish commands to the remote console for ( pCur = m_pConCommandList; pCur; pCur=pCur->GetNext() ) { // add unregistered commands to list if ( numCommands < sizeof(commands)/sizeof(commands[0]) ) { commands[numCommands] = pCur->GetName(); helptext[numCommands] = pCur->GetHelpText(); numCommands++; } } if ( numCommands ) { XBX_rAddCommands( numCommands, commands, helptext ); } } #endif //----------------------------------------------------------------------------- // Console commands //----------------------------------------------------------------------------- void CCvar::Find( const CCommand &args ) { const char *search; const ConCommandBase *var; if ( args.ArgC() != 2 ) { ConMsg( "Usage: find \n" ); return; } // Get substring to find search = args[1]; // Loop through vars and print out findings for ( var = GetCommands(); var; var=var->GetNext() ) { if ( var->IsFlagSet(FCVAR_DEVELOPMENTONLY) || var->IsFlagSet(FCVAR_HIDDEN) ) continue; if ( !Q_stristr( var->GetName(), search ) && !Q_stristr( var->GetHelpText(), search ) ) continue; ConVar_PrintDescription( var ); } }