2015-07-09 13:07:26 -04:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
|
2012-05-21 02:48:36 -05:00
|
|
|
//
|
|
|
|
// Purpose:
|
|
|
|
//
|
|
|
|
// $NoKeywords: $
|
|
|
|
//
|
|
|
|
//===========================================================================//
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include "basetypes.h"
|
|
|
|
#include "tier1/convar.h"
|
|
|
|
#include "tier1/strtools.h"
|
|
|
|
#include "tier1/characterset.h"
|
2023-05-14 10:25:40 -04:00
|
|
|
#include "tier1/utlvector.h"
|
2012-05-21 02:48:36 -05:00
|
|
|
#include "tier1/utlbuffer.h"
|
|
|
|
#include "tier1/tier1.h"
|
|
|
|
#include "icvar.h"
|
|
|
|
#include "tier0/dbg.h"
|
|
|
|
#include "Color.h"
|
|
|
|
#if defined( _X360 )
|
|
|
|
#include "xbox/xbox_console.h"
|
|
|
|
#endif
|
|
|
|
#include "tier0/memdbgon.h"
|
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
// AMNOTE: Define this if you need cvars/concommands to respect flags sanitization rules
|
|
|
|
// #define SANITIZE_CVAR_FLAGS 1
|
2012-05-21 02:48:36 -05:00
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2025-02-15 17:26:37 +01:00
|
|
|
// Statically constructed list of ConVars/ConCommands,
|
2012-05-21 02:48:36 -05:00
|
|
|
// used for registering them with the ICVar interface
|
|
|
|
//-----------------------------------------------------------------------------
|
2025-02-15 17:26:37 +01:00
|
|
|
static FnConVarRegisterCallback s_ConVarRegCB = nullptr;
|
|
|
|
static FnConCommandRegisterCallback s_ConCommandRegCB = nullptr;
|
|
|
|
static uint64 s_nCVarFlag = 0;
|
2012-05-21 02:48:36 -05:00
|
|
|
static bool s_bRegistered = false;
|
2023-05-16 14:28:31 -04:00
|
|
|
|
2023-05-14 10:25:40 -04:00
|
|
|
class ConCommandRegList
|
2012-05-21 02:48:36 -05:00
|
|
|
{
|
|
|
|
public:
|
2025-02-15 17:26:37 +01:00
|
|
|
struct Entry_t
|
2012-05-21 02:48:36 -05:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
ConCommandCreation_t m_Info;
|
|
|
|
ConCommandRef *m_Command = nullptr;
|
|
|
|
};
|
2023-05-18 23:18:34 -04:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
static void RegisterConCommand( const Entry_t &cmd )
|
|
|
|
{
|
|
|
|
*cmd.m_Command = g_pCVar->RegisterConCommand( cmd.m_Info, s_nCVarFlag );
|
|
|
|
if(!cmd.m_Command->IsValidRef())
|
2023-05-14 10:25:40 -04:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
Plat_FatalErrorFunc( "RegisterConCommand: Unknown error registering con command \"%s\"!\n", cmd.m_Info.m_pszName );
|
|
|
|
DebuggerBreakIfDebugging();
|
2023-05-14 10:25:40 -04:00
|
|
|
}
|
2025-02-15 17:26:37 +01:00
|
|
|
else if(s_ConCommandRegCB)
|
|
|
|
s_ConCommandRegCB( cmd.m_Command );
|
2023-05-14 10:25:40 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void RegisterAll()
|
|
|
|
{
|
2023-05-16 14:21:12 -04:00
|
|
|
if (!s_bConCommandsRegistered && g_pCVar)
|
2023-05-14 10:25:40 -04:00
|
|
|
{
|
2023-05-16 14:21:12 -04:00
|
|
|
s_bConCommandsRegistered = true;
|
2023-05-14 10:25:40 -04:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
ConCommandRegList *prev = nullptr;
|
|
|
|
for(auto list = s_pRoot; list; list = prev)
|
2023-05-14 10:25:40 -04:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
for(size_t i = 0; i < list->m_nSize; i++)
|
2023-05-14 10:25:40 -04:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
RegisterConCommand( list->m_Entries[i] );
|
2023-05-14 10:25:40 -04:00
|
|
|
}
|
2025-02-15 17:26:37 +01:00
|
|
|
|
|
|
|
prev = list->m_pPrev;
|
|
|
|
delete list;
|
|
|
|
};
|
2023-05-14 10:25:40 -04:00
|
|
|
}
|
|
|
|
}
|
2023-09-09 22:09:29 +03:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
static void AddToList( const Entry_t &cmd )
|
2023-09-09 22:09:29 +03:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
if(s_bConCommandsRegistered)
|
|
|
|
{
|
|
|
|
RegisterConCommand( cmd );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto list = s_pRoot;
|
|
|
|
|
|
|
|
if(!list || list->m_nSize >= (sizeof( m_Entries ) / sizeof( m_Entries[0] )))
|
|
|
|
{
|
|
|
|
list = new ConCommandRegList;
|
|
|
|
list->m_nSize = 0;
|
|
|
|
list->m_pPrev = s_pRoot;
|
|
|
|
|
|
|
|
s_pRoot = list;
|
|
|
|
}
|
|
|
|
|
|
|
|
list->m_Entries[list->m_nSize++] = cmd;
|
2023-09-09 22:09:29 +03:00
|
|
|
}
|
2023-05-14 10:25:40 -04:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
private:
|
|
|
|
uint32 m_nSize;
|
|
|
|
Entry_t m_Entries[100];
|
|
|
|
ConCommandRegList *m_pPrev;
|
|
|
|
|
|
|
|
public:
|
2023-05-16 14:28:31 -04:00
|
|
|
static bool s_bConCommandsRegistered;
|
2025-02-15 17:26:37 +01:00
|
|
|
static ConCommandRegList *s_pRoot;
|
2023-05-14 10:25:40 -04:00
|
|
|
};
|
|
|
|
|
2023-05-16 14:28:31 -04:00
|
|
|
bool ConCommandRegList::s_bConCommandsRegistered = false;
|
2025-02-15 17:26:37 +01:00
|
|
|
ConCommandRegList *ConCommandRegList::s_pRoot = nullptr;
|
2023-05-16 14:28:31 -04:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
void SetupConCommand( ConCommand *cmd, const ConCommandCreation_t& info )
|
|
|
|
{
|
|
|
|
ConCommandRegList::Entry_t entry;
|
|
|
|
entry.m_Info = info;
|
|
|
|
entry.m_Command = cmd;
|
2012-05-21 02:48:36 -05:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
ConCommandRegList::AddToList( entry );
|
|
|
|
}
|
|
|
|
|
|
|
|
void UnRegisterConCommand( ConCommand *cmd )
|
|
|
|
{
|
|
|
|
if(cmd->IsValidRef())
|
|
|
|
{
|
|
|
|
if(g_pCVar)
|
|
|
|
g_pCVar->UnregisterConCommandCallbacks( *cmd );
|
|
|
|
|
|
|
|
cmd->InvalidateRef();
|
|
|
|
}
|
|
|
|
}
|
2023-05-16 14:28:31 -04:00
|
|
|
|
2023-05-14 10:25:40 -04:00
|
|
|
class ConVarRegList
|
|
|
|
{
|
|
|
|
public:
|
2025-02-15 17:26:37 +01:00
|
|
|
struct Entry_t
|
2023-05-14 10:25:40 -04:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
ConVarCreation_t m_Info;
|
2023-05-14 10:25:40 -04:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
ConVarRefAbstract *m_pConVar = nullptr;
|
|
|
|
ConVarData **m_pConVarData = nullptr;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void RegisterConVar( const Entry_t &cvar )
|
2023-05-14 10:25:40 -04:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
g_pCVar->RegisterConVar( cvar.m_Info, s_nCVarFlag, cvar.m_pConVar, cvar.m_pConVarData );
|
|
|
|
if(!cvar.m_pConVar->IsValidRef())
|
|
|
|
{
|
|
|
|
Plat_FatalErrorFunc( "RegisterConVar: Unknown error registering convar \"%s\"!\n", cvar.m_Info.m_pszName );
|
|
|
|
DebuggerBreakIfDebugging();
|
|
|
|
}
|
|
|
|
// Don't let references pass as a newly registered cvar
|
|
|
|
else if(s_ConVarRegCB && (cvar.m_Info.m_nFlags & FCVAR_REFERENCE) == 0)
|
|
|
|
s_ConVarRegCB( cvar.m_pConVar );
|
2023-05-14 10:25:40 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void RegisterAll()
|
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
if(!s_bConVarsRegistered && g_pCVar)
|
2023-05-14 10:25:40 -04:00
|
|
|
{
|
2023-05-16 14:21:12 -04:00
|
|
|
s_bConVarsRegistered = true;
|
2023-05-14 10:25:40 -04:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
ConVarRegList *prev = nullptr;
|
|
|
|
for(auto list = s_pRoot; list; list = prev)
|
2023-05-14 10:25:40 -04:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
for(size_t i = 0; i < list->m_nSize; i++)
|
2023-05-14 10:25:40 -04:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
RegisterConVar( list->m_Entries[i] );
|
2023-05-14 10:25:40 -04:00
|
|
|
}
|
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
prev = list->m_pPrev;
|
|
|
|
delete list;
|
|
|
|
};
|
2023-05-14 10:25:40 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
static void AddToList( const Entry_t &cvar )
|
|
|
|
{
|
|
|
|
if(s_bConVarsRegistered)
|
|
|
|
{
|
|
|
|
RegisterConVar( cvar );
|
|
|
|
return;
|
|
|
|
}
|
2023-05-14 10:25:40 -04:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
auto list = s_pRoot;
|
2012-05-21 02:48:36 -05:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
if(!list || list->m_nSize >= (sizeof( m_Entries ) / sizeof( m_Entries[0] )))
|
|
|
|
{
|
|
|
|
list = new ConVarRegList;
|
|
|
|
list->m_nSize = 0;
|
|
|
|
list->m_pPrev = s_pRoot;
|
2012-05-21 02:48:36 -05:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
s_pRoot = list;
|
|
|
|
}
|
2012-05-21 02:48:36 -05:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
list->m_Entries[list->m_nSize++] = cvar;
|
|
|
|
}
|
2012-05-21 02:48:36 -05:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
private:
|
|
|
|
uint32 m_nSize;
|
|
|
|
Entry_t m_Entries[100];
|
|
|
|
ConVarRegList *m_pPrev;
|
2012-05-21 02:48:36 -05:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
public:
|
|
|
|
static bool s_bConVarsRegistered;
|
|
|
|
static ConVarRegList *s_pRoot;
|
|
|
|
};
|
2012-05-21 02:48:36 -05:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
bool ConVarRegList::s_bConVarsRegistered = false;
|
|
|
|
ConVarRegList *ConVarRegList::s_pRoot = nullptr;
|
2012-05-21 02:48:36 -05:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
void SetupConVar( ConVarRefAbstract *cvar, ConVarData **cvar_data, ConVarCreation_t &info )
|
2012-05-21 02:48:36 -05:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
ConVarRegList::Entry_t entry;
|
|
|
|
entry.m_Info = info;
|
|
|
|
entry.m_pConVar = cvar;
|
|
|
|
entry.m_pConVarData = cvar_data;
|
2012-05-21 02:48:36 -05:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
ConVarRegList::AddToList( entry );
|
2012-05-21 02:48:36 -05:00
|
|
|
}
|
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
void UnRegisterConVar( ConVarRef *cvar )
|
2012-05-21 02:48:36 -05:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
if(cvar->IsValidRef())
|
|
|
|
{
|
|
|
|
if(g_pCVar)
|
|
|
|
g_pCVar->UnregisterConVarCallbacks( *cvar );
|
2012-05-21 02:48:36 -05:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
cvar->InvalidateRef();
|
|
|
|
}
|
2012-05-21 02:48:36 -05:00
|
|
|
}
|
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
uint64 SanitiseConVarFlags( uint64 flags )
|
2012-05-21 02:48:36 -05:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
#ifdef SANITIZE_CVAR_FLAGS
|
|
|
|
if(!CommandLine()->HasParm( "-tools" )
|
|
|
|
&& (flags & (FCVAR_DEVELOPMENTONLY
|
|
|
|
| FCVAR_ARCHIVE
|
|
|
|
| FCVAR_USERINFO
|
|
|
|
| FCVAR_CHEAT
|
|
|
|
| FCVAR_RELEASE
|
|
|
|
| FCVAR_SERVER_CAN_EXECUTE
|
|
|
|
| FCVAR_CLIENT_CAN_EXECUTE
|
|
|
|
| FCVAR_CLIENTCMD_CAN_EXECUTE)) == 0)
|
|
|
|
{
|
|
|
|
flags |= FCVAR_DEFENSIVE | FCVAR_DEVELOPMENTONLY;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return flags;
|
2012-05-21 02:48:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2025-02-15 17:26:37 +01:00
|
|
|
// Called by the framework to register ConCommandBases with the ICVar
|
2012-05-21 02:48:36 -05:00
|
|
|
//-----------------------------------------------------------------------------
|
2025-02-15 17:26:37 +01:00
|
|
|
void ConVar_Register( uint64 nCVarFlag, FnConVarRegisterCallback cvar_reg_cb, FnConCommandRegisterCallback cmd_reg_cb )
|
2012-05-21 02:48:36 -05:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
if ( !g_pCVar || s_bRegistered )
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2012-05-21 02:48:36 -05:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
s_bRegistered = true;
|
|
|
|
s_nCVarFlag = nCVarFlag;
|
|
|
|
s_ConVarRegCB = cvar_reg_cb;
|
|
|
|
s_ConCommandRegCB = cmd_reg_cb;
|
2012-05-21 02:48:36 -05:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
ConCommandRegList::RegisterAll();
|
|
|
|
ConVarRegList::RegisterAll();
|
2012-05-21 02:48:36 -05:00
|
|
|
}
|
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
void ConVar_Unregister( )
|
2012-05-21 02:48:36 -05:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
if ( !g_pCVar || !s_bRegistered )
|
|
|
|
return;
|
2012-05-21 02:48:36 -05:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
s_bRegistered = false;
|
2012-05-21 02:48:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Tokenizer class
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
CCommand::CCommand()
|
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
EnsureBuffers();
|
2012-05-21 02:48:36 -05:00
|
|
|
Reset();
|
|
|
|
}
|
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
CCommand::CCommand( int nArgC, const char **ppArgV ) : CCommand()
|
2012-05-21 02:48:36 -05:00
|
|
|
{
|
|
|
|
Assert( nArgC > 0 );
|
|
|
|
|
2023-05-14 10:25:40 -04:00
|
|
|
char *pBuf = m_ArgvBuffer.Base();
|
|
|
|
char *pSBuf = m_ArgSBuffer.Base();
|
2012-05-21 02:48:36 -05:00
|
|
|
for ( int i = 0; i < nArgC; ++i )
|
|
|
|
{
|
2023-05-14 10:25:40 -04:00
|
|
|
m_Args.AddToTail( pBuf );
|
|
|
|
int nLen = V_strlen( ppArgV[i] );
|
2012-05-21 02:48:36 -05:00
|
|
|
memcpy( pBuf, ppArgV[i], nLen+1 );
|
|
|
|
if ( i == 0 )
|
|
|
|
{
|
|
|
|
m_nArgv0Size = nLen;
|
|
|
|
}
|
|
|
|
pBuf += nLen+1;
|
|
|
|
|
|
|
|
bool bContainsSpace = strchr( ppArgV[i], ' ' ) != NULL;
|
|
|
|
if ( bContainsSpace )
|
|
|
|
{
|
|
|
|
*pSBuf++ = '\"';
|
|
|
|
}
|
|
|
|
memcpy( pSBuf, ppArgV[i], nLen );
|
|
|
|
pSBuf += nLen;
|
|
|
|
if ( bContainsSpace )
|
|
|
|
{
|
|
|
|
*pSBuf++ = '\"';
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( i != nArgC - 1 )
|
|
|
|
{
|
|
|
|
*pSBuf++ = ' ';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
void CCommand::EnsureBuffers()
|
|
|
|
{
|
|
|
|
m_ArgSBuffer.SetSize( MaxCommandLength() );
|
|
|
|
m_ArgvBuffer.SetSize( MaxCommandLength() );
|
|
|
|
}
|
|
|
|
|
2012-05-21 02:48:36 -05:00
|
|
|
void CCommand::Reset()
|
|
|
|
{
|
|
|
|
m_nArgv0Size = 0;
|
2025-02-15 17:26:37 +01:00
|
|
|
m_ArgSBuffer.Base()[0] = '\0';
|
2023-05-14 10:25:40 -04:00
|
|
|
m_Args.RemoveAll();
|
2012-05-21 02:48:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
characterset_t* CCommand::DefaultBreakSet()
|
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
return g_pCVar->GetCharacterSet();
|
2012-05-21 02:48:36 -05:00
|
|
|
}
|
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
bool CCommand::Tokenize( CUtlString pCommand, characterset_t *pBreakSet )
|
2012-05-21 02:48:36 -05:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
if(m_ArgSBuffer.Count() == 0)
|
|
|
|
EnsureBuffers();
|
|
|
|
|
2012-05-21 02:48:36 -05:00
|
|
|
Reset();
|
2025-02-15 17:26:37 +01:00
|
|
|
|
|
|
|
if ( pCommand.IsEmpty() )
|
2012-05-21 02:48:36 -05:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// Use default break set
|
|
|
|
if ( !pBreakSet )
|
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
pBreakSet = DefaultBreakSet();
|
2012-05-21 02:48:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Copy the current command into a temp buffer
|
|
|
|
// NOTE: This is here to avoid the pointers returned by DequeueNextCommand
|
|
|
|
// to become invalid by calling AddText. Is there a way we can avoid the memcpy?
|
2025-02-15 17:26:37 +01:00
|
|
|
int nLen = pCommand.Length();
|
|
|
|
if ( nLen >= m_ArgSBuffer.Count() - 1 )
|
2012-05-21 02:48:36 -05:00
|
|
|
{
|
|
|
|
Warning( "CCommand::Tokenize: Encountered command which overflows the tokenizer buffer.. Skipping!\n" );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
memmove( m_ArgSBuffer.Base(), pCommand, nLen + 1 );
|
2012-05-21 02:48:36 -05:00
|
|
|
|
|
|
|
// Parse the current command into the current command buffer
|
2023-05-14 10:25:40 -04:00
|
|
|
CUtlBuffer bufParse( m_ArgSBuffer.Base(), nLen, CUtlBuffer::TEXT_BUFFER | CUtlBuffer::READ_ONLY);
|
2012-05-21 02:48:36 -05:00
|
|
|
int nArgvBufferSize = 0;
|
2025-02-15 17:26:37 +01:00
|
|
|
while ( bufParse.IsValid() )
|
2012-05-21 02:48:36 -05:00
|
|
|
{
|
2023-05-14 10:25:40 -04:00
|
|
|
char *pArgvBuf = &m_ArgvBuffer[nArgvBufferSize];
|
2025-02-15 17:26:37 +01:00
|
|
|
int nMaxLen = m_ArgvBuffer.Count() - nArgvBufferSize;
|
2012-05-21 02:48:36 -05:00
|
|
|
int nStartGet = bufParse.TellGet();
|
|
|
|
int nSize = bufParse.ParseToken( pBreakSet, pArgvBuf, nMaxLen );
|
|
|
|
if ( nSize < 0 )
|
|
|
|
break;
|
|
|
|
|
|
|
|
// Check for overflow condition
|
|
|
|
if ( nMaxLen == nSize )
|
|
|
|
{
|
|
|
|
Reset();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-05-14 10:25:40 -04:00
|
|
|
if ( m_Args.Count() == 1 )
|
2012-05-21 02:48:36 -05:00
|
|
|
{
|
|
|
|
// Deal with the case where the arguments were quoted
|
|
|
|
m_nArgv0Size = bufParse.TellGet();
|
2023-05-14 10:25:40 -04:00
|
|
|
bool bFoundEndQuote = m_ArgSBuffer[m_nArgv0Size-1] == '\"';
|
2012-05-21 02:48:36 -05:00
|
|
|
if ( bFoundEndQuote )
|
|
|
|
{
|
|
|
|
--m_nArgv0Size;
|
|
|
|
}
|
|
|
|
m_nArgv0Size -= nSize;
|
|
|
|
Assert( m_nArgv0Size != 0 );
|
|
|
|
|
|
|
|
// The StartGet check is to handle this case: "foo"bar
|
|
|
|
// which will parse into 2 different args. ArgS should point to bar.
|
2023-05-14 10:25:40 -04:00
|
|
|
bool bFoundStartQuote = ( m_nArgv0Size > nStartGet ) && ( m_ArgSBuffer[m_nArgv0Size-1] == '\"' );
|
2012-05-21 02:48:36 -05:00
|
|
|
Assert( bFoundEndQuote == bFoundStartQuote );
|
|
|
|
if ( bFoundStartQuote )
|
|
|
|
{
|
|
|
|
--m_nArgv0Size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-14 10:25:40 -04:00
|
|
|
m_Args.AddToTail( pArgvBuf );
|
2012-05-21 02:48:36 -05:00
|
|
|
nArgvBufferSize += nSize + 1;
|
2025-02-15 17:26:37 +01:00
|
|
|
|
|
|
|
if(nArgvBufferSize >= m_ArgvBuffer.Count())
|
|
|
|
break;
|
2012-05-21 02:48:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Helper function to parse arguments to commands.
|
|
|
|
//-----------------------------------------------------------------------------
|
2023-05-14 10:25:40 -04:00
|
|
|
int CCommand::FindArg( const char *pName ) const
|
2012-05-21 02:48:36 -05:00
|
|
|
{
|
|
|
|
int nArgC = ArgC();
|
|
|
|
for ( int i = 1; i < nArgC; i++ )
|
|
|
|
{
|
2023-05-14 10:25:40 -04:00
|
|
|
if ( !V_stricmp_fast( Arg(i), pName ) )
|
|
|
|
return (i+1) < nArgC ? i+1 : -1;
|
2012-05-21 02:48:36 -05:00
|
|
|
}
|
2023-05-14 10:25:40 -04:00
|
|
|
return -1;
|
2012-05-21 02:48:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
int CCommand::FindArgInt( const char *pName, int nDefaultVal ) const
|
|
|
|
{
|
2023-05-14 10:25:40 -04:00
|
|
|
int idx = FindArg( pName );
|
|
|
|
if ( idx != -1 )
|
|
|
|
return V_atoi( m_Args[idx] );
|
2012-05-21 02:48:36 -05:00
|
|
|
else
|
|
|
|
return nDefaultVal;
|
|
|
|
}
|
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
ConCommandRef::ConCommandRef( const char *name, bool allow_developer )
|
2012-05-21 02:48:36 -05:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
*this = g_pCVar->FindConCommand( name, allow_developer );
|
2012-05-21 02:48:36 -05:00
|
|
|
}
|
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
ConCommandData *ConCommandRef::GetRawData()
|
2012-05-21 02:48:36 -05:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
return g_pCVar->GetConCommandData( *this );
|
2012-05-21 02:48:36 -05:00
|
|
|
}
|
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
void ConCommandRef::Dispatch( const CCommandContext &context, const CCommand &command )
|
2016-08-29 19:16:45 -04:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
g_pCVar->DispatchConCommand( *this, context, command );
|
2016-08-29 19:16:45 -04:00
|
|
|
}
|
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
void ConCommand::Create( const char* pName, const ConCommandCallbackInfo_t &cb, const char* pHelpString, uint64 flags, const ConCommandCompletionCallbackInfo_t &completion_cb )
|
2016-08-29 19:16:45 -04:00
|
|
|
{
|
2023-05-14 10:25:40 -04:00
|
|
|
// Name should be static data
|
|
|
|
Assert(pName);
|
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
ConCommandCreation_t info;
|
|
|
|
info.m_pszName = pName;
|
|
|
|
info.m_pszHelpString = pHelpString;
|
|
|
|
info.m_nFlags = SanitiseConVarFlags( flags );
|
|
|
|
info.m_CBInfo = cb;
|
|
|
|
info.m_CompletionCBInfo = completion_cb;
|
2023-05-14 10:25:40 -04:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
SetupConCommand( this, info );
|
2023-05-14 10:25:40 -04:00
|
|
|
}
|
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
void ConCommand::Destroy()
|
2023-05-14 10:25:40 -04:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
UnRegisterConCommand( this );
|
2023-05-14 10:25:40 -04:00
|
|
|
}
|
2012-05-21 02:48:36 -05:00
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// Console Variables
|
|
|
|
//
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
int ConVarData::GetMaxSplitScreenSlots() const
|
2012-05-21 02:48:36 -05:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
if((m_nFlags & FCVAR_PER_USER) != 0)
|
|
|
|
return g_pCVar->GetMaxSplitScreenSlots();
|
2012-05-21 02:48:36 -05:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
return 1;
|
2012-05-21 02:48:36 -05:00
|
|
|
}
|
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
CVValue_t *ConVarData::Value( CSplitScreenSlot slot ) const
|
2012-05-21 02:48:36 -05:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
if(slot.Get() == -1)
|
|
|
|
slot = CSplitScreenSlot( 0 );
|
2012-05-21 02:48:36 -05:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
if(!IsSlotInRange( slot ))
|
|
|
|
return nullptr;
|
2012-05-21 02:48:36 -05:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
return (CVValue_t *)&m_Values[GetDataByteSize() * slot.Get()];
|
2012-05-21 02:48:36 -05:00
|
|
|
}
|
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
CVValue_t *ConVarData::ValueOrDefault( CSplitScreenSlot slot ) const
|
2012-05-21 02:48:36 -05:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
CVValue_t *value = Value( slot );
|
|
|
|
return value ? value : m_defaultValue;
|
2012-05-21 02:48:36 -05:00
|
|
|
}
|
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
bool ConVarData::IsAllSetToDefault() const
|
2012-05-21 02:48:36 -05:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
for(int i = 0; i < GetMaxSplitScreenSlots(); i++)
|
2012-05-21 02:49:35 -05:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
if(!IsSetToDefault( i ))
|
|
|
|
return false;
|
2012-05-21 02:48:36 -05:00
|
|
|
}
|
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
return true;
|
2012-05-21 02:48:36 -05:00
|
|
|
}
|
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
void ConVarData::MinValueToString( CBufferString &buf ) const
|
2012-05-21 02:48:36 -05:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
if(HasMinValue())
|
|
|
|
TypeTraits()->ValueToString( m_minValue, buf );
|
|
|
|
else
|
|
|
|
buf.Insert( 0, "" );
|
2012-05-21 02:48:36 -05:00
|
|
|
}
|
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
void ConVarData::MaxValueToString( CBufferString &buf ) const
|
2012-05-21 02:48:36 -05:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
if(HasMaxValue())
|
|
|
|
TypeTraits()->ValueToString( m_maxValue, buf );
|
|
|
|
else
|
|
|
|
buf.Insert( 0, "" );
|
2012-05-21 02:48:36 -05:00
|
|
|
}
|
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
ConVarRef::ConVarRef( const char *name, bool allow_developer )
|
2012-05-21 02:48:36 -05:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
*this = g_pCVar->FindConVar( name, allow_developer );
|
2012-05-21 02:48:36 -05:00
|
|
|
}
|
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
void ConVarRefAbstract::Init( ConVarRef ref, EConVarType type )
|
2012-05-21 02:48:36 -05:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
m_ConVarData = nullptr;
|
2012-05-21 02:48:36 -05:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
if(g_pCVar)
|
|
|
|
m_ConVarData = g_pCVar->GetConVarData( ref );
|
2012-05-21 02:48:36 -05:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
if(!m_ConVarData)
|
|
|
|
InvalidateConVarData( type );
|
2012-05-21 02:48:36 -05:00
|
|
|
}
|
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
void ConVarRefAbstract::InvalidateConVarData( EConVarType type )
|
2012-05-21 02:48:36 -05:00
|
|
|
{
|
2025-02-16 00:16:12 +03:00
|
|
|
InvalidateRef();
|
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
if(type == EConVarType_Invalid)
|
|
|
|
m_ConVarData = GetInvalidConVarData( EConVarType_Invalid );
|
|
|
|
else
|
|
|
|
m_ConVarData = GetCvarTypeTraits( type )->m_InvalidCvarData;
|
2012-05-21 02:48:36 -05:00
|
|
|
}
|
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
void ConVarRefAbstract::CallChangeCallbacks( CSplitScreenSlot slot, CVValue_t *new_value, CVValue_t *prev_value, const char *new_str, const char *prev_str )
|
2012-05-21 02:48:36 -05:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
if(slot.Get() == -1)
|
|
|
|
slot = CSplitScreenSlot( 0 );
|
2012-05-21 02:48:36 -05:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
g_pCVar->CallChangeCallback( *this, slot, new_value, prev_value );
|
|
|
|
g_pCVar->CallGlobalChangeCallbacks( this, slot, new_str, prev_str );
|
2012-05-21 02:48:36 -05:00
|
|
|
}
|
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
void ConVarRefAbstract::SetOrQueueValueInternal( CSplitScreenSlot slot, CVValue_t *value )
|
2012-05-21 02:48:36 -05:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
if(m_ConVarData->IsFlagSet( FCVAR_PERFORMING_CALLBACKS ))
|
|
|
|
QueueSetValueInternal( slot, value );
|
2012-05-21 02:48:36 -05:00
|
|
|
else
|
2025-02-15 17:26:37 +01:00
|
|
|
SetValueInternal( slot, value );
|
2012-05-21 02:48:36 -05:00
|
|
|
}
|
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
void ConVarRefAbstract::QueueSetValueInternal( CSplitScreenSlot slot, CVValue_t *value )
|
2012-05-21 02:48:36 -05:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
if(slot.Get() == -1)
|
|
|
|
slot = CSplitScreenSlot( 0 );
|
2012-05-21 02:48:36 -05:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
TypeTraits()->Clamp( value, m_ConVarData->MinValue(), m_ConVarData->MaxValue() );
|
2012-05-21 02:48:36 -05:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
if(!m_ConVarData->IsEqual( slot, value ))
|
|
|
|
g_pCVar->QueueThreadSetValue( this, slot, value );
|
2012-05-21 02:48:36 -05:00
|
|
|
}
|
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
void ConVarRefAbstract::SetValueInternal( CSplitScreenSlot slot, CVValue_t *value )
|
2012-05-21 02:48:36 -05:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
CVValue_t *curr_value = m_ConVarData->ValueOrDefault( slot );
|
2012-05-21 02:48:36 -05:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
CVValue_t prev;
|
|
|
|
TypeTraits()->Construct( &prev );
|
2012-05-21 02:48:36 -05:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
TypeTraits()->Copy( &prev, *curr_value );
|
|
|
|
TypeTraits()->Destruct( curr_value );
|
2012-05-21 02:48:36 -05:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
TypeTraits()->Copy( curr_value, *value );
|
|
|
|
m_ConVarData->Clamp( slot );
|
2012-05-21 02:48:36 -05:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
if(!m_ConVarData->IsEqual( slot, &prev ))
|
2012-05-21 02:48:36 -05:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
CBufferString prev_str, new_str;
|
2012-05-21 02:48:36 -05:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
TypeTraits()->ValueToString( &prev, prev_str );
|
|
|
|
TypeTraits()->ValueToString( curr_value, new_str );
|
2012-05-21 02:48:36 -05:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
m_ConVarData->IncrementTimesChanged();
|
2012-05-21 02:48:36 -05:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
CallChangeCallbacks( slot, curr_value, &prev, new_str.Get(), prev_str.Get() );
|
|
|
|
}
|
2012-05-21 02:48:36 -05:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
TypeTraits()->Destruct( &prev );
|
2012-05-21 02:48:36 -05:00
|
|
|
}
|
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
bool ConVarRefAbstract::SetString( CUtlString string, CSplitScreenSlot slot )
|
2012-05-21 02:48:36 -05:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
CVValue_t *value = m_ConVarData->Value( slot );
|
2012-05-21 02:48:36 -05:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
if(!value)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if(GetType() != EConVarType_String)
|
|
|
|
string.Trim( "\t\n\v\f\r " );
|
2012-05-21 02:48:36 -05:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
CVValue_t new_value;
|
|
|
|
TypeTraits()->Construct( &new_value );
|
2012-05-21 02:48:36 -05:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
bool success = false;
|
|
|
|
if(TypeTraits()->StringToValue( string.Get(), &new_value ))
|
2012-05-21 02:48:36 -05:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
SetOrQueueValueInternal( slot, &new_value );
|
|
|
|
success = true;
|
2012-05-21 02:48:36 -05:00
|
|
|
}
|
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
TypeTraits()->Destruct( &new_value );
|
|
|
|
return success;
|
2012-05-21 02:48:36 -05:00
|
|
|
}
|
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
void ConVarRefAbstract::Revert( CSplitScreenSlot slot )
|
2012-05-21 02:48:36 -05:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
CBufferString buf;
|
|
|
|
GetDefaultAsString( buf );
|
|
|
|
SetString( buf.Get(), slot );
|
2012-05-21 02:48:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose:
|
|
|
|
//-----------------------------------------------------------------------------
|
2025-02-15 17:26:37 +01:00
|
|
|
void ConVar_PrintDescription( const ConVarRefAbstract *ref )
|
2012-05-21 02:48:36 -05:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
Assert( ref );
|
2012-05-21 02:48:36 -05:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
static struct
|
2012-05-21 02:48:36 -05:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
uint64 m_Flag;
|
|
|
|
const char *m_Name;
|
|
|
|
} s_FlagsMap[] = {
|
|
|
|
{ FCVAR_GAMEDLL, "game" },
|
|
|
|
{ FCVAR_CLIENTDLL, "client" },
|
|
|
|
{ FCVAR_ARCHIVE, "archive" },
|
|
|
|
{ FCVAR_NOTIFY, "notify" },
|
|
|
|
{ FCVAR_SPONLY, "singleplayer" },
|
|
|
|
{ FCVAR_NOT_CONNECTED, "notconnected" },
|
|
|
|
{ FCVAR_CHEAT, "cheat" },
|
|
|
|
{ FCVAR_REPLICATED, "replicated" },
|
|
|
|
{ FCVAR_SERVER_CAN_EXECUTE, "server_can_execute" },
|
|
|
|
{ FCVAR_CLIENTCMD_CAN_EXECUTE, "clientcmd_can_execute" },
|
|
|
|
{ FCVAR_USERINFO, "userinfo" },
|
|
|
|
{ FCVAR_PER_USER, "per_user" }
|
|
|
|
};
|
2012-05-21 02:48:36 -05:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
CBufferStringN<4096> desc;
|
|
|
|
CBufferString buf;
|
2012-05-21 02:48:36 -05:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
ref->GetValueAsString( buf );
|
|
|
|
desc.AppendFormat( "\"%s\" = \"%s\"", ref->GetName(), buf.Get() );
|
2012-05-21 02:48:36 -05:00
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
if(!ref->IsSetToDefault())
|
2012-05-21 02:48:36 -05:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
ref->GetDefaultAsString( buf );
|
|
|
|
desc.AppendFormat( " ( def. \"%s\" )", buf.Get() );
|
2012-05-21 02:48:36 -05:00
|
|
|
}
|
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
if(ref->HasMin())
|
2012-05-21 02:48:36 -05:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
ref->GetMinAsString( buf );
|
|
|
|
desc.AppendFormat( " min. %s", buf.Get() );
|
2012-05-21 02:48:36 -05:00
|
|
|
}
|
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
if(ref->HasMax())
|
2012-05-21 02:48:36 -05:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
ref->GetMaxAsString( buf );
|
|
|
|
desc.AppendFormat( " max. %s", buf.Get() );
|
2012-05-21 02:48:36 -05:00
|
|
|
}
|
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
for(size_t i = 0; i < (sizeof( s_FlagsMap ) / sizeof( s_FlagsMap[0] )); i++)
|
2012-05-21 02:48:36 -05:00
|
|
|
{
|
2025-02-15 17:26:37 +01:00
|
|
|
if(ref->IsFlagSet( s_FlagsMap[i].m_Flag ))
|
|
|
|
desc.AppendFormat( " %s", s_FlagsMap[i].m_Name );
|
2012-05-21 02:48:36 -05:00
|
|
|
}
|
|
|
|
|
2025-02-15 17:26:37 +01:00
|
|
|
if(ref->HasHelpText())
|
|
|
|
ConMsg( "%-120s - %s\n", desc.Get(), ref->GetHelpText() );
|
2012-05-21 02:48:36 -05:00
|
|
|
else
|
2025-02-15 17:26:37 +01:00
|
|
|
ConMsg( "%-120s\n", desc.Get() );
|
2012-05-21 02:48:36 -05:00
|
|
|
}
|