mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
CCommand: use 'V_isdigit()' since that is faster, we don't need it to be locale aware. CMemoryStack: move 'highest' var to string format directly to avoid compile warnings (unused loval variables) on more recent visual studio compilers when compiling the DLL in cert mode.
217 lines
5.2 KiB
C++
217 lines
5.2 KiB
C++
//=============================================================================//
|
|
//
|
|
// Purpose: Console Commands
|
|
//
|
|
//=============================================================================//
|
|
|
|
#include "tier0/tslist.h"
|
|
#include "tier0/memstd.h"
|
|
#include "tier0/commandline.h"
|
|
#include "tier1/cmd.h"
|
|
#include "tier1/cvar.h"
|
|
#include "tier1/characterset.h"
|
|
#include "tier1/utlstring.h"
|
|
#include "tier1/utlbuffer.h"
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Global methods
|
|
//-----------------------------------------------------------------------------
|
|
static characterset_t s_BreakSet;
|
|
static bool s_bBuiltBreakSet = false;
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Tokenizer class
|
|
//-----------------------------------------------------------------------------
|
|
CCommand::CCommand()
|
|
{
|
|
if (!s_bBuiltBreakSet)
|
|
{
|
|
s_bBuiltBreakSet = true;
|
|
CharacterSetBuild(&s_BreakSet, "{}()':");
|
|
}
|
|
|
|
Reset();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: constructor
|
|
// Input : nArgC -
|
|
// **ppArgV -
|
|
// source -
|
|
//-----------------------------------------------------------------------------
|
|
CCommand::CCommand(int nArgC, const char** ppArgV, cmd_source_t source)
|
|
{
|
|
Assert(nArgC > 0);
|
|
|
|
if (!s_bBuiltBreakSet)
|
|
{
|
|
s_bBuiltBreakSet = true;
|
|
CharacterSetBuild(&s_BreakSet, "{}()':");
|
|
}
|
|
|
|
Reset();
|
|
|
|
char* pBuf = m_pArgvBuffer;
|
|
char* pSBuf = m_pArgSBuffer;
|
|
m_nArgc = nArgC;
|
|
for (int i = 0; i < nArgC; ++i)
|
|
{
|
|
m_ppArgv[i] = pBuf;
|
|
ssize_t nLen = strlen(ppArgV[i]);
|
|
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++ = ' ';
|
|
}
|
|
}
|
|
|
|
m_nQueuedVal = source;
|
|
}
|
|
|
|
characterset_t* CCommand::DefaultBreakSet()
|
|
{
|
|
return &s_BreakSet;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: tokenizer
|
|
// Input : *pCommand -
|
|
// source -
|
|
// *pBreakSet -
|
|
// Output : true on success, false on failure
|
|
//-----------------------------------------------------------------------------
|
|
bool CCommand::Tokenize(const char* pCommand, cmd_source_t source, characterset_t* pBreakSet)
|
|
{
|
|
Reset();
|
|
m_nQueuedVal = source;
|
|
|
|
if (!pCommand)
|
|
return false;
|
|
|
|
// Use default break set
|
|
if (!pBreakSet)
|
|
{
|
|
pBreakSet = &s_BreakSet;
|
|
}
|
|
|
|
// 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?
|
|
size_t nLen = Q_strlen(pCommand);
|
|
if (nLen >= COMMAND_MAX_LENGTH - 1)
|
|
{
|
|
Warning(eDLL_T::COMMON, "%s: Encountered command which overflows the tokenizer buffer... Skipped!\n", __FUNCTION__);
|
|
return false;
|
|
}
|
|
|
|
memcpy(m_pArgSBuffer, pCommand, nLen + 1);
|
|
|
|
// Parse the current command into the current command buffer
|
|
CUtlBuffer bufParse(m_pArgSBuffer, nLen, CUtlBuffer::TEXT_BUFFER | CUtlBuffer::READ_ONLY);
|
|
ssize_t nArgvBufferSize = 0;
|
|
|
|
while (bufParse.IsValid() && (m_nArgc < COMMAND_MAX_ARGC))
|
|
{
|
|
char* pArgvBuf = &m_pArgvBuffer[nArgvBufferSize];
|
|
ssize_t nMaxLen = COMMAND_MAX_LENGTH - nArgvBufferSize;
|
|
ssize_t nStartGet = bufParse.TellGet();
|
|
ssize_t nSize = bufParse.ParseToken(pBreakSet, pArgvBuf, nMaxLen);
|
|
|
|
if (nSize < 0)
|
|
break;
|
|
|
|
// Check for overflow condition
|
|
if (nMaxLen == nSize)
|
|
{
|
|
Reset();
|
|
return false;
|
|
}
|
|
|
|
if (m_nArgc == 1)
|
|
{
|
|
// Deal with the case where the arguments were quoted
|
|
m_nArgv0Size = bufParse.TellGet();
|
|
bool bFoundEndQuote = m_pArgSBuffer[m_nArgv0Size - 1] == '\"';
|
|
|
|
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.
|
|
bool bFoundStartQuote = (m_nArgv0Size > nStartGet) && (m_pArgSBuffer[m_nArgv0Size - 1] == '\"');
|
|
Assert(bFoundEndQuote == bFoundStartQuote);
|
|
|
|
if (bFoundStartQuote)
|
|
{
|
|
--m_nArgv0Size;
|
|
}
|
|
}
|
|
|
|
m_ppArgv[m_nArgc++] = pArgvBuf;
|
|
|
|
if (m_nArgc >= COMMAND_MAX_ARGC)
|
|
{
|
|
Warning(eDLL_T::COMMON, "%s: Encountered command which overflows the argument buffer... Clamped!\n", __FUNCTION__);
|
|
}
|
|
|
|
nArgvBufferSize += nSize + 1;
|
|
Assert(nArgvBufferSize <= COMMAND_MAX_LENGTH);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: return boolean depending on if the string only has digits in it
|
|
// Input : svString -
|
|
//-----------------------------------------------------------------------------
|
|
bool CCommand::HasOnlyDigits(int nIndex) const
|
|
{
|
|
const char* source = Arg(nIndex);
|
|
|
|
for (size_t i = 0; source[i] != '\0'; i++)
|
|
{
|
|
if (!V_isdigit(source[i]))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: reset
|
|
//-----------------------------------------------------------------------------
|
|
void CCommand::Reset()
|
|
{
|
|
m_nArgc = 0;
|
|
m_nArgv0Size = 0;
|
|
m_pArgSBuffer[0] = 0;
|
|
m_nQueuedVal = cmd_source_t::kCommandSrcInvalid;
|
|
}
|