//=============================================================================
// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
//
// File: console.cpp
//
// Description:
//
// History: + Created -- Darwin Chau
//
//=============================================================================
//========================================
// System Includes
//========================================
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
// Radcore
#include <radDebug.hpp>
#include <raddebugwatch.hpp>
#include <radFile.hpp>
// Pure3D
#include <p3d/utility.hpp>
//========================================
// Project Includes
//========================================
#include <console/console.h>
#include <console/fbstricmp.h>
#include <main/commandlineoptions.h>
#include <memory/srrmemory.h>
#include <memory/memorypool.h>
#include <loading/loadingmanager.h>
#ifdef RAD_DEBUG
#include <raddebugconsole.hpp>
#include <console/debugconsolecallback.h>
#endif
//******************************************************************************
//
// Global Data, Local Data, Local Classes
//
//******************************************************************************
#define PROFILE_PARSER 0
const char* gErrFileName = 0;
unsigned int gErrLineNum = ~0;
//---------------------------------------------------------------------------//
// Static pointer to instance of singleton.
Console* Console::spInstance = 0;
static char gConsoleEntry[Console::MAX_STRING_LENGTH];
//log message buffers needed so the async writes to the log file don't bog
static char* gConsoleMsgBuffer[2] = {0};
static char* gConsoleMsgBufferPtr = 0;
static int gConsoleBufferIndex = 0;
#ifdef RAD_GAMECUBE
FBMemoryPool Console::FunctionTableEntry::sMemoryPool( sizeof(Console::FunctionTableEntry), Console::MAX_FUNCTIONS, GMA_GC_VMM );
FBMemoryPool Console::AliasTableEntry::sMemoryPool( sizeof(Console::AliasTableEntry), Console::MAX_ALIASES, GMA_GC_VMM );
#else
FBMemoryPool Console::FunctionTableEntry::sMemoryPool( sizeof(Console::FunctionTableEntry), Console::MAX_FUNCTIONS, GMA_PERSISTENT );
FBMemoryPool Console::AliasTableEntry::sMemoryPool( sizeof(Console::AliasTableEntry), Console::MAX_ALIASES, GMA_PERSISTENT );
#endif
//=============================================================================
// static bool cConsoleTrue
//=============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//=============================================================================
static bool cConsoleTrue( int argc, char** argv )
{
argc;
argv;
return( true );
}
static bool cConsoleFalse( int argc, char** argv )
{
argc;
argv;
return( false );
}
static void cConsoleExit(int argc, char **argv)
{
argc;
argv;
//does nothing, but the parser will terminate executing a script
}
static void cConsoleExec(int argc, char **argv)
{
GetConsole()->ExecuteScriptSync(argv[1], true);
}
static void cConsoleSetLogMode(int argc, char **argv)
{
argc;
if (! smStricmp(argv[1], "on"))
GetConsole()->SetConsoleLogMode(Console::LOGMODE_ON);
else if (! smStricmp(argv[1], "append"))
GetConsole()->SetConsoleLogMode(Console::LOGMODE_APPEND);
else
GetConsole()->SetConsoleLogMode(Console::LOGMODE_OFF);
}
static void cConsoleFlushLog(int argc, char **argv)
{
GetConsole()->FlushConsoleLogFile();
}
static void cConsoleEcho(int argc, char **argv)
{
if (argc == 3)
GetConsole()->Printf(atoi(argv[1]), argv[2]);
else
GetConsole()->Printf(argv[1]);
}
static void cConsoleError(int argc, char **argv)
{
GetConsole()->Errorf(argv[1]);
}
static void cConsoleListFunctions(int argc, char **argv)
{
argc;
argv;
GetConsole()->ListConsoleFunctions();
}
static void cConsoleListenChannel(int argc, char **argv)
{
argc;
GetConsole()->ConsoleListenChannel(atoi(argv[1]));
}
static void cConsoleBlockChannel(int argc, char **argv)
{
argc;
GetConsole()->ConsoleBlockChannel(atoi(argv[1]));
}
static void cConsoleAlias(int argc, char **argv)
{
GetConsole()->AddAlias(argv[1], argv[2], argc - 3, &argv[3]);
}
static void cWatcherExecConsoleCommand(void *)
{
GetConsole()->Printf("==> %s", gConsoleEntry);
GetConsole()->Evaluate(gConsoleEntry, "CMDLine");
}
//******************************************************************************
//
// Public Member Functions
//
//******************************************************************************
//==============================================================================
// Console::CreateInstance
//==============================================================================
//
// Description: Creates the Console.
//
// Parameters: None.
//
// Return: Pointer to the Console.
//
// Constraints: This is a singleton so only one instance is allowed.
//
//==============================================================================
Console* Console::CreateInstance()
{
MEMTRACK_PUSH_GROUP( "Console" );
rTuneAssert( spInstance == 0 );
#ifdef RAD_GAMECUBE
HeapMgr()->PushHeap( GMA_GC_VMM );
#else
HeapMgr()->PushHeap( GMA_PERSISTENT );
#endif
spInstance = new Console;
rTuneAssert( spInstance );
#ifdef RAD_GAMECUBE
HeapMgr()->PopHeap( GMA_GC_VMM );
#else
HeapMgr()->PopHeap( GMA_PERSISTENT );
#endif
Console::Initialize();
MEMTRACK_POP_GROUP( "Console" );
return spInstance;
}
//==============================================================================
// Console::GetInstance
//==============================================================================
//
// Description: - Access point for the Console singleton.
//
// Parameters: None.
//
// Return: Pointer to the Console.
//
// Constraints: This is a singleton so only one instance is allowed.
//
//==============================================================================
Console* Console::GetInstance()
{
rTuneAssert( spInstance != 0 );
return spInstance;
}
//==============================================================================
// Console::DestroyInstance
//==============================================================================
//
// Description: Destroy the Console.
//
// Parameters: None.
//
// Return: None.
//
//==============================================================================
void Console::DestroyInstance()
{
rTuneAssert( spInstance != 0 );
delete spInstance;
spInstance = 0;
}
//==============================================================================
// Console::Initialize
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
bool Console::Initialize()
{
//the console doesn't use remote drive in the release build
#ifdef RAD_DEBUG
MEMTRACK_PUSH_GROUP( "Console Initialize" );
if( !CommandLineOptions::Get( CLO_FIREWIRE ) )
{
//initialize the console log buffers
gConsoleMsgBuffer[0] = new(GMA_DEBUG) char[MAX_STRING_LENGTH * MAX_BUFFERS];
gConsoleMsgBuffer[1] = new(GMA_DEBUG) char[MAX_STRING_LENGTH * MAX_BUFFERS];
gConsoleMsgBufferPtr = gConsoleMsgBuffer[0];
gConsoleBufferIndex = 0;
//add a function to allow the program to generate a console.log file
GetConsole()->AddFunction("ifTrue", cConsoleTrue, "ifTrue() { } //returns true", 0, 0);
GetConsole()->AddFunction("ifFalse", cConsoleFalse, "ifFalse() { } //returns false", 0, 0);
GetConsole()->AddFunction("Exit", cConsoleExit, "Exit(msg);", 1, 1);
GetConsole()->AddFunction("ConsoleExec", cConsoleExec, "ConsoleExec(file);", 1, 1);
GetConsole()->AddFunction("ConsoleSetLogMode", cConsoleSetLogMode, "ConsoleSetLogMode(off/on/append);", 1, 1);
GetConsole()->AddFunction("ConsoleFlushLog", cConsoleFlushLog, "ConsoleFlushLog();", 0, 0);
GetConsole()->AddFunction("Echo", cConsoleEcho, "Echo([channel, ] msg);", 1, 2);
GetConsole()->AddFunction("Error", cConsoleError, "Error(msg);", 1, 1);
GetConsole()->AddFunction("ConsoleListFunctions", cConsoleListFunctions, "ConsoleListFunctions();", 0, 0);
GetConsole()->AddFunction("ConsoleListenChannel", cConsoleListenChannel, "ConsoleListenChannel(-1 or [0 .. 31]);", 1, 1);
GetConsole()->AddFunction("ConsoleBlockChannel", cConsoleBlockChannel, "ConsoleBlockChannel(-1 or [0 .. 31]);", 1, 1);
GetConsole()->AddFunction("Alias", cConsoleAlias, "Alias(aliasName, functionName, arg1, arg2, \"%1\", arg3, \"%2\", etc...);", 2, MAX_ARGS);
//add the console entry string and it's update function
radDbgWatchAddString(gConsoleEntry, sizeof(gConsoleEntry), "Console command", "\\", cWatcherExecConsoleCommand);
//add the debugconsole window as well...
radDebugConsoleCreate(&(spInstance->mDebugConsole), GMA_DEBUG);
if (spInstance->mDebugConsole)
{
//set the title and background color
spInstance->mDebugConsole->SetTitle( "Fish Bulb Console" );
spInstance->mDebugConsole->SetBackgroundColor(RGB( 0, 0, 0x188 ));
spInstance->mDebugConsole->Clear();
spInstance->mDebugConsole->SetCursorPosition(0, 0);
spInstance->mDebugConsole->SetTextColor(RGB(0xFF, 0xFF,0xFF));
spInstance->mDebugConsoleCallback = new(GMA_DEBUG) DebugConsoleCallback();
spInstance->mDebugConsole->SetKeyboardInputCallback(spInstance->mDebugConsoleCallback);
spInstance->mDebugConsole->SetPointerInputCallback(spInstance->mDebugConsoleCallback);
//initialize the debug console line number
spInstance->mDebugConsoleLine = 0;
}
}
MEMTRACK_POP_GROUP( "Console Initialize" );
#endif
return (true);
}
//==============================================================================
// Console::Console
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
Console::Console()
:
mpCallback( 0 )
{
// Initialize the tables
int i = 0;
for( i = 0; i < MAX_FUNCTIONS; ++i )
{
mFunctionTable[i] = 0;
}
for( i = 0; i < MAX_ALIASES; ++i )
{
mAliasTable[i] = 0;
}
mFunctionCount = 0;
mAliasCount = 0;
//create the argv array
#ifdef RAD_GAMECUBE
HeapMgr()->PushHeap( GMA_GC_VMM );
#else
HeapMgr()->PushHeap( GMA_PERSISTENT );
#endif
mArgv = new char*[MAX_ARGS];
mPrevArgv = new char*[MAX_ARGS];
for( i = 0; i < MAX_ARGS; ++i )
{
mArgv[i] = new char[MAX_ARG_LENGTH];
mPrevArgv[i] = new char[MAX_ARG_LENGTH];
}
#ifdef RAD_GAMECUBE
HeapMgr()->PopHeap( GMA_GC_VMM );
#else
HeapMgr()->PopHeap( GMA_PERSISTENT );
#endif
//set the log file mode
mLogFile = 0;
mLogMode = LOGMODE_OFF;
//initialize the console listen channels to everything
mChannelMask = ~0;
#ifdef RAD_DEBUG
//initialize the radcore debugconsole members
mDebugConsole = 0;
#endif
}
//==============================================================================
// Console::~Console
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
Console::~Console()
{
//clean up the console
if( spInstance )
{
#ifdef RAD_DEBUG
if( spInstance->mDebugConsole )
{
spInstance->mDebugConsole->Release();
delete spInstance->mDebugConsoleCallback;
}
#endif
if( spInstance->mLogFile )
spInstance->mLogFile->WaitForCompletion();
}
//clean up after the watcher
#ifdef RAD_DEBUG
delete [] gConsoleMsgBuffer[0];
delete [] gConsoleMsgBuffer[1];
radDbgWatchDelete(gConsoleEntry);
#endif
int i = 0;
//delete the tables
for( i = 0; i < mFunctionCount; ++i )
{
if (mFunctionTable[i])
{
delete mFunctionTable[i];
}
}
for( i = 0; i < MAX_ALIASES; ++i )
{
if( mAliasTable[i] )
{
delete mAliasTable[i];
}
}
//delete the argv array
for( i = 0; i < MAX_ARGS; ++i )
{
delete [] mArgv[i];
delete [] mPrevArgv[i];
}
delete [] mArgv;
delete [] mPrevArgv;
//close the logfile
if( mLogFile )
{
FlushLogFile();
mLogFile->Release();
}
}
//==============================================================================
// Console::SetConsoleLogMode
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
bool Console::SetConsoleLogMode(int logMode)
{
#ifndef RAD_DEBUG
return (false);
#else
//make sure we have a console
if (!spInstance)
return (false);
return (spInstance->SetLogMode(logMode));
#endif
}
bool Console::SetLogMode(int logMode)
{
//no work to do if we're not actually changing the mode
if (logMode == mLogMode)
return (true);
switch (logMode)
{
case LOGMODE_OFF:
if (mLogFile)
{
mLogFile->WaitForCompletion();
mLogFile->Release();
mLogFile = 0;
}
mLogMode = logMode;
return (true);
case LOGMODE_ON:
if (!mLogFile)
{
char fullPath[256];
// RM sprintf(fullPath, "%sconsole.log", ResourceManager::GetInstance()->GetRemoteDriveName());
::radFileOpen(&mLogFile, fullPath, true, CreateAlways, NormalPriority, 0, RADMEMORY_ALLOC_TEMP);
if (mLogFile)
{
const char *msg = "\r\n******** CONSOLE LOG OPENED ********\r\n";
mLogFile->WaitForCompletion();
mLogFile->WriteAsync(msg, strlen(msg));
mLogFile->WaitForCompletion();
mLogMode = logMode;
return (true);
}
else
{
mLogMode = LOGMODE_OFF;
return (false);
}
}
return (true);
case LOGMODE_APPEND:
if (!mLogFile)
{
char fullPath[256];
// RM sprintf(fullPath, "%sconsole.log", ResourceManager::GetInstance()->GetRemoteDriveName());
::radFileOpen(&mLogFile, fullPath, true, OpenAlways, NormalPriority, 0, RADMEMORY_ALLOC_TEMP);
if (mLogFile)
{
const char *msg = "\r\n******** CONSOLE LOG OPENED ********\r\n";
mLogFile->WaitForCompletion();
int fileSize = mLogFile->GetSize();
mLogFile->SetPositionAsync(fileSize);
mLogFile->WaitForCompletion();
mLogFile->WriteAsync(msg, strlen(msg));
mLogFile->WaitForCompletion();
mLogMode = logMode;
return (true);
}
else
{
mLogMode = LOGMODE_OFF;
return (false);
}
}
return (true);
}
// Set Error Condition, to remove compiler warning.
return (false);
}
//==============================================================================
// Console::Printf
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
void Console::Printf(char *fmt, ...)
{
#ifdef RAD_DEBUG
//make sure we have a console
if (!spInstance)
return;
char message[MAX_STRING_LENGTH];
va_list args;
int i = 0;
va_start(args, fmt);
i = vsprintf(message, fmt, args);
va_end(args);
// do some tune printf for designers
rTunePrintf( message );
//record the message to the console log file
spInstance->LogMessage(0, message);
#endif
}
//for now, it does the same as Printf()... should also echo
//to an error page in the DebugInfo stuff Chakib is working on!
void Console::Errorf(char *fmt, ...)
{
#ifdef RAD_DEBUG
//make sure we have a console
if (!spInstance)
return;
char message[MAX_STRING_LENGTH];
va_list args;
int i = 0;
va_start(args, fmt);
i = vsprintf(message, fmt, args);
va_end(args);
//record the message to the console log file
spInstance->LogMessage(0, message, true);
#endif
}
void Console::Printf(int channel, char *fmt, ...)
{
#ifdef RAD_DEBUG
//make sure we have a console
if (!spInstance)
return;
char message[MAX_STRING_LENGTH];
//prefix the message with the channel number
sprintf(message, "ch%d ", channel);
char *msgPtr;
if (channel >= 10)
msgPtr = &message[5];
else
msgPtr = &message[4];
va_list args;
int i = 0;
va_start(args, fmt);
i = vsprintf(msgPtr, fmt, args);
va_end(args);
// do some tune printf for designers
rTunePrintf( message );
//record the message to the console log file
spInstance->LogMessage(channel, message);
#endif
}
//==============================================================================
// Console::AssertFatal
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
void Console::AssertFatal(char *fmt, ...)
{
char msgFmt[512];
sprintf(msgFmt, "File: %s, line: %d %s", gErrFileName, gErrLineNum, fmt);
char message[MAX_STRING_LENGTH];
va_list args;
int i = 0;
va_start(args, fmt);
i = vsprintf(message, msgFmt, args);
va_end(args);
//record the message to the console log file
this->LogMessage(0, message, true);
//flush the log file in case we're about to crash
this->FlushLogFile();
//pop the assert
rTuneAssertMsg( 0, message );
}
//==============================================================================
// Console::AssertWarn
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
void Console::AssertWarn(char *fmt, ...)
{
char msgFmt[512];
sprintf(msgFmt, "File: %s, line: %d %s", gErrFileName, gErrLineNum, fmt);
char message[MAX_STRING_LENGTH];
va_list args;
int i = 0;
va_start(args, fmt);
i = vsprintf(message, msgFmt, args);
va_end(args);
//record the message to the console log file
spInstance->LogMessage(0, message, true);
//flush the log file in case we're about to crash
spInstance->FlushLogFile();
//assert warn using the p3d versions
rDebugWarningFail_Implementation(message, gErrFileName, gErrLineNum);
}
//==============================================================================
// Console::LogMessage
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
void Console::LogMessage(int channel, char* msg, bool warning)
{
//see if we're listening to this channel
int listenChannel = channel;
if (channel < 0 || channel > 31)
listenChannel = 0;
if (! (mChannelMask & (1 << listenChannel)))
return;
//append an '\r\n' to the end of every message
char logMessage[512];
if (strchr(msg, '\n'))
strcpy(logMessage, msg);
else
sprintf(logMessage, "%s\r\n", msg);
//print the message to the console
p3d::printf(logMessage);
#ifdef RAD_DEBUG
//print the message out the the radcore debug console as well...
AddDebugConsoleLine(logMessage, warning);
#endif
//write the msg out to the console.log (buffered)
if (mLogMode == LOGMODE_ON || mLogMode == LOGMODE_APPEND)
{
//see if there's enough room in the buffer to store the string
int bytesUsed = int(gConsoleMsgBufferPtr) - int(gConsoleMsgBuffer[gConsoleBufferIndex]);
int bytesLeft = (MAX_STRING_LENGTH * MAX_BUFFERS) - bytesUsed;
int strLength = strlen(logMessage);
//if we don't have space, wait for file completion, then start using the next buffer
if (bytesUsed > 0 && bytesLeft < strLength)
{
mLogFile->WaitForCompletion();
mLogFile->WriteAsync(gConsoleMsgBuffer[gConsoleBufferIndex], bytesUsed);
gConsoleBufferIndex = 1 - gConsoleBufferIndex;
gConsoleMsgBufferPtr = gConsoleMsgBuffer[gConsoleBufferIndex];
}
//copy the string into the static console msg buffer
strcpy(gConsoleMsgBufferPtr, logMessage);
//increment the console msg buffer
gConsoleMsgBufferPtr += strLength;
}
}
//==============================================================================
// Console::FlushConsoleLogFile
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
void Console::FlushConsoleLogFile()
{
//flush the log file in case we're about to crash
spInstance->FlushLogFile();
}
//==============================================================================
// Console::FlushLogFile
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
void Console::FlushLogFile()
{
if (mLogMode == LOGMODE_ON || mLogMode == LOGMODE_APPEND)
{
//see if there's enough room in the buffer to store the string
int bytesUsed = int(gConsoleMsgBufferPtr) - int(gConsoleMsgBuffer[gConsoleBufferIndex]);
//if there is info waiting in the buffer to be written out...
if (bytesUsed > 0)
mLogFile->WriteAsync(gConsoleMsgBuffer[gConsoleBufferIndex], bytesUsed);
//wait for the File server to complete
mLogFile->WaitForCompletion();
//reset the buffer vars
gConsoleBufferIndex = 0;
gConsoleMsgBufferPtr = gConsoleMsgBuffer[0];
}
}
#ifdef RAD_DEBUG
//debug console methods
//==============================================================================
// char* FormatDebugConsoleString
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
const unsigned char MAX_STRING_LEN = 128;
static const char* FormatDebugConsoleString(const char *text, bool consoleEntry)
{
static char formatString[MAX_STRING_LEN + 1];
//copy the first 80 characters of the text
if (consoleEntry)
{
formatString[0] = '=';
formatString[1] = '>';
strncpy(&formatString[2], text, MAX_STRING_LEN - 2);
}
else
strncpy(formatString, text, MAX_STRING_LEN);
//make sure there are no \r\n's in the string
char *eolChar = strchr(formatString, '\r');
if (eolChar)
*eolChar = '\0';
eolChar = strchr(formatString, '\n');
if (eolChar)
*eolChar = '\0';
//pad the string with spaces
formatString[MAX_STRING_LEN] = '\0';
int strlength = strlen(formatString);
if (strlength < MAX_STRING_LEN)
memset(&formatString[strlength], ' ', MAX_STRING_LEN - strlength);
formatString[MAX_STRING_LEN] = '\0';
//return the formatted string
return(formatString);
}
//==============================================================================
// Console::AddDebugConsoleLine
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
void Console::AddDebugConsoleLine(const char *text, bool warning)
{
//make sure we have a debugconsole
if (! mDebugConsole)
return;
//create the string to send to the debug console
const char *formatString = FormatDebugConsoleString(text, false);
if (warning)
mDebugConsole->SetTextColor(RGB(0xFF, 0, 0));
else
mDebugConsole->SetTextColor(RGB(0xFF, 0xFF, 0xFF));
mDebugConsole->TextOutAt(formatString, 0, mDebugConsoleLine++);
//create the console entry string
int cursorPosition;
const char *consoleEntry = mDebugConsoleCallback->GetConsoleEntry(&cursorPosition);
SetDebugConsoleEntry(consoleEntry, cursorPosition);
}
//==============================================================================
// Console::SetDebugConsoleEntry
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
void Console::SetDebugConsoleEntry(const char *text, int cursorPosition)
{
const char *formatString = FormatDebugConsoleString(text, true);
//update the consoleEntry
mDebugConsole->SetTextColor(RGB(0xFF, 0xFF, 0xFF));
mDebugConsole->TextOutAt(formatString, 0, mDebugConsoleLine);
//update the cursor position
spInstance->mDebugConsole->SetCursorPosition(cursorPosition + 2, mDebugConsoleLine);
}
#endif
//==============================================================================
// Console::ConsoleListenChannel
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
void Console::ConsoleListenChannel(int channel)
{
//make sure we have a console
if (!spInstance)
return;
if (channel <= -2 || channel > 31)
{
Printf("Console error - invalid channel: %d. Specify -1 for all channels, or 0 to 31", channel);
return;
}
spInstance->ListenChannel(channel);
}
//==============================================================================
// Console::ConsoleBlockChannel
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
void Console::ConsoleBlockChannel(int channel)
{
//make sure we have a console
if (!spInstance)
return;
if (channel <= -2 || channel > 31)
{
Printf("Console error - invalid channel: %d. Specify -1 for all channels, or 0 to 31", channel);
return;
}
spInstance->BlockChannel(channel);
}
//==============================================================================
// Console::ListenChannel
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
void Console::ListenChannel(int channel)
{
//validate params
if (channel <= -2 || channel > 31)
return;
if (channel == -1)
mChannelMask = 0xffffffff;
else
mChannelMask |= (1 << channel);
}
//==============================================================================
// Console::BlockChannel
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
void Console::BlockChannel(int channel)
{
//validate params
if (channel <= -2 || channel > 31)
return;
//note: can't block channel 0
if (channel == -1)
mChannelMask = (1 << 0);
else
mChannelMask &= ~(1 << channel);
}
//==============================================================================
// Console::ListConsoleFunctions
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
void Console::ListConsoleFunctions()
{
if (!spInstance)
return;
spInstance->ListFunctions();
}
//==============================================================================
// Console::ListFunctions
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
void Console::ListFunctions()
{
//for (int i = 0; i < mFunctionCount; i++)
//Printf(mFunctionTable[i]->help.GetText());
}
//==============================================================================
// Console::AddFunction
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
bool Console::AddFunction
(
const char* name,
CONSOLE_FUNCTION funcPtr,
const char* helpString,
int minArgs,
int maxArgs
)
{
//make sure we've initialized the global console
if (!spInstance)
{
rDebugString("Error - Console::AddFunction(): Console::Initialize() hasn't been called yet.");
return (false);
}
return (spInstance->AddFunc(name, funcPtr, 0, helpString, minArgs, maxArgs));
}
//==============================================================================
// Console::AddFunction
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
bool Console::AddFunction
(
const char* name,
CONSOLE_BOOL_FUNCTION funcPtr,
const char* helpString,
int minArgs,
int maxArgs
)
{
//make sure we've initialized the global console
if (!spInstance)
{
rDebugString("Error - Console::AddFunction(): Console::Initialize() hasn't been called yet.");
return (false);
}
return (spInstance->AddFunc(name, 0, funcPtr, helpString, minArgs, maxArgs));
}
//==============================================================================
// Console::AddFunc
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
bool Console::AddFunc
(
const char* name,
CONSOLE_FUNCTION funcPtr,
CONSOLE_BOOL_FUNCTION boolFuncPtr,
const char* helpString,
int minArgs,
int maxArgs
)
{
//validate the input
if (!name || !name[0] || strlen(name) >= MAX_STRING_LENGTH)
{
rDebugString("Error - Console::AddFunction(): invalid function name specified.\n");
return (false);
}
if (!helpString || strlen(helpString) >= MAX_STRING_LENGTH)
{
rDebugString("Error - Console::AddFunction(): invalid help string specified.\n");
return (false);
}
if (!funcPtr && !boolFuncPtr)
{
rDebugString("Error - Console::AddFunction(): no CONSOLE_FUNCTION specified.\n");
return (false);
}
if (minArgs < 0)
{
rDebugString("Error - Console::AddFunction(): invalid minArgs specified.\n");
return (false);
}
if (maxArgs < minArgs || maxArgs > MAX_ARGS)
{
rDebugString("Error - Console::AddFunction(): invalid maxArgs specified.\n");
return (false);
}
//make sure we have room for one more
if( mFunctionCount >= MAX_FUNCTIONS )
{
rDebugString("Error - Console::AddFunction(): Maximum number of functions has been reached.\n");
return (false);
}
#ifdef RAD_GAMECUBE
HeapMgr()->PushHeap( GMA_GC_VMM );
#else
HeapMgr()->PushHeap( GMA_PERSISTENT );
#endif
//create the new function
FunctionTableEntry* newFunction;
if( funcPtr )
{
newFunction = new FunctionTableEntry(name, funcPtr, helpString, minArgs, maxArgs);
}
else
{
newFunction = new FunctionTableEntry(name, boolFuncPtr, helpString, minArgs, maxArgs);
}
//add the function to the table
mFunctionTable[mFunctionCount] = newFunction;
mFunctionLookup[radMakeCaseInsensitiveKey32(name)] = mFunctionCount;
//increment the function count
mFunctionCount++;
#ifdef RAD_GAMECUBE
HeapMgr()->PopHeap( GMA_GC_VMM );
#else
HeapMgr()->PopHeap( GMA_PERSISTENT );
#endif
// return success condition
return (true);
}
//==============================================================================
// Console::AddAlias
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
bool Console::AddAlias
(
const char* name,
const char* functionName,
int argc,
char** argv
)
{
//make sure we've initialized the global console
if (!spInstance)
{
rDebugString("Error - Console::AddFunction(): Console::Initialize() hasn't been called yet.");
return (false);
}
return (spInstance->AddFunctionAlias(name, functionName, argc, argv));
}
//==============================================================================
// Console::AddFunctionAlias
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
bool Console::AddFunctionAlias
(
const char* name,
const char* functionName,
int argc,
char** argv
)
{
//validate the input
if (!name || !name[0] || strlen(name) >= MAX_STRING_LENGTH)
{
rDebugString("Error - Console::AddFunctionAlias(): invalid function name specified.\n");
return (false);
}
//make sure we have room for one more
if (mAliasCount >= MAX_FUNCTIONS)
{
rDebugString("Error - Console::AddFunctionAlias(): Maximum number of alias' has been reached.\n");
return (false);
}
#ifdef RAD_GAMECUBE
HeapMgr()->PushHeap( GMA_GC_VMM );
#else
HeapMgr()->PushHeap( GMA_PERSISTENT );
#endif
//create the new alias
AliasTableEntry* newAlias = new AliasTableEntry(name, functionName, argc, argv);
//insert the new alias into the table alphabetically
int index = 0;
while (index < mAliasCount)
{
if (smStricmp(mAliasTable[index]->name, name) > 0)
break;
index++;
}
//the new alias should be inserted at position "index", shift everything else down by one
for (int i = mAliasCount; i > index; i--)
mAliasTable[i] = mAliasTable[i - 1];
//add the alias to the table
mAliasTable[index] = newAlias;
//increment the alias count
mAliasCount++;
#ifdef RAD_GAMECUBE
HeapMgr()->PopHeap( GMA_GC_VMM );
#else
HeapMgr()->PopHeap( GMA_PERSISTENT );
#endif
// return success condition
return (true);
}
//==============================================================================
// Console::TabCompleteFunction
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
const tNameInsensitive& Console::TabCompleteFunction
(
const char* tabString,
const char* curFunction
)
{
static tNameInsensitive error( "ERROR" );
//make sure we've initialized the global console
if (!spInstance)
{
rDebugString("Error - Console::TabCompleteFunction(): Console::Initialize() hasn't been called yet.");
return error;
}
return (spInstance->TabComplete(tabString, curFunction));
}
//==============================================================================
// Console::TabComplete
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
const tNameInsensitive& Console::TabComplete
(
const char* tabString,
const char* curFunction
)
{
int i;
static tNameInsensitive error( "ERROR" );
//sanity check
if (! tabString || ! tabString[0])
{
rAssert( false );
return error;
}
//find the first function beginning with the tabString
//note - functions are stored alphabetically...
int firstFunctionIndex = -1;
for (i = 0; i < mFunctionCount; i++)
{
if (! smStrincmp(tabString, mFunctionTable[i]->name.GetText(), strlen(tabString)))
{
firstFunctionIndex = i;
break;
}
}
//if no function was found, return 0
if (firstFunctionIndex < 0)
{
rAssert( false );
return error;
}
//if there's no current function, return the first function we found
if (! curFunction || ! curFunction[0])
return (mFunctionTable[firstFunctionIndex]->name);
//if the current function doesn't contain the tabString, ???
if (smStrincmp(tabString, curFunction, strlen(tabString)))
return (mFunctionTable[firstFunctionIndex]->name);
//search for the next function that contains the tabstring, but follows the curFunction
int curFunctionIndex = -1;
for (i = firstFunctionIndex; i < mFunctionCount; i++)
{
if ( mFunctionTable[i]->name == curFunction )
{
curFunctionIndex = i;
break;
}
}
//if no current function was found, return the first function
if (curFunctionIndex < 0 || curFunctionIndex == mFunctionCount - 1)
return (mFunctionTable[firstFunctionIndex]->name);
//see if the next function also contains the tabString
if (! smStrincmp(tabString, mFunctionTable[curFunctionIndex + 1]->name.GetText(), strlen(tabString)))
return (mFunctionTable[curFunctionIndex + 1]->name);
//otherwise, return the first function found again
else
return (mFunctionTable[firstFunctionIndex]->name);
}
//---------------------------------------------------------------------------//
static const char* gWhiteSpace = " \t\r\n";
static const char* gEndOfToken = " \t\r\n,();[]{}+/*!@#$%^&:\"<>?'`~";
char *Console::SkipWhiteSpace(const char *string)
{
//this function should never be called with an invalid string
char *temp = const_cast<char*>(string);
while (true)
{
//break on an end of string character
if (*temp == '\0')
break;
//break when a non-white space character is found
char *found = strchr(gWhiteSpace, *temp);
if (! found)
break;
//see if we found an eol char
if (*found == '\n')
mLineNumber++;
//check the next character
temp++;
}
return (temp);
}
//==============================================================================
// Console::FoundComment
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
bool Console::FoundComment(char** stringPtr)
{
char *tokenPtr = *stringPtr;
if (*tokenPtr == '/')
{
tokenPtr++;
//see if we've found a line comment
if (*tokenPtr == '/')
{
while (*tokenPtr != '\r' && *tokenPtr != '\n' && *tokenPtr != '\0')
tokenPtr++;
//increment the line count
if (*tokenPtr == '\n')
mLineNumber++;
//now we've hit the end of the line or file
*stringPtr = tokenPtr;
return (true);
}
//else see if we've found a block comment
else if (*tokenPtr == '*')
{
//here we search for the end of the block: */
while (true)
{
tokenPtr++;
while (*tokenPtr != '*' && *tokenPtr != '\0')
{
//increment the line count
if (*tokenPtr == '\n')
mLineNumber++;
tokenPtr++;
}
//see if we've found the end of the file
if (*tokenPtr == '\0')
{
*stringPtr = tokenPtr;
return (true);
}
//else see if we've found the end of the comment block
else
{
tokenPtr++;
if (*tokenPtr == '/')
{
tokenPtr++;
*stringPtr = tokenPtr;
return (true);
}
}
}
}
//else no comment found
else
return (false);
}
//else no commment found
else
return (false);
}
//==============================================================================
// Console::FindTokenEnd
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
char* Console::FindTokenEnd( const char* string )
{
//this function should never be called with an invalid string
char *temp = const_cast<char*>(string);
bool finished = false;
while (true)
{
//break on an end of string character
if (*temp == '\0')
break;
//break on an end of token character
char *found = strchr(gEndOfToken, *temp);
if (found)
{
//see if we found an eol char
if (*found == '\n')
mLineNumber++;
break;
}
//neither was found, check the next character
temp++;
}
return (temp);
}
//==============================================================================
// Console::ReadToken
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
bool Console::ReadToken(char **stringPtr, const char *requiredToken)
{
//validate parameters
if (! stringPtr || ! *stringPtr || !requiredToken)
return (false);
//read the next token
char tempBuffer[MAX_STRING_LENGTH];
char *token = GetNextToken(stringPtr, tempBuffer);
//if we don't have a token, or it doesn't match what we're looking for, return false
if (! token || smStricmp(token, requiredToken))
return (false);
//everything is ok, return true
return (true);
}
//==============================================================================
// Console::GetNextToken
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
char* Console::GetNextToken(char **stringPtr, char *tokenBuffer)
{
//validate parameters
if (! stringPtr || ! *stringPtr || !tokenBuffer)
return (0);
char *tokenPtr = *stringPtr;
char *tokenEnd = 0;
//skip comments and white space until we reach the beginning of a valid token
while (true)
{
tokenPtr = SkipWhiteSpace(tokenPtr);
if (! FoundComment(&tokenPtr))
break;
}
//if the next character is a '\0', no more tokens
if (*tokenPtr == '\0')
return (0);
//if the token is enclosed in quotes, search for the end quote
if (*tokenPtr == '\"')
{
tokenEnd = tokenPtr + 1;
while (true)
{
tokenEnd = strchr(tokenEnd, '\"');
if (! tokenEnd)
return (0);
//make sure the previous character isn't a '\\'
if (*(tokenEnd - 1) == '\\')
tokenEnd++;
//otherwise, we've found our matching quotes
else
break;
}
//now we've got our string enclosed with quotes, copy it the contents to the tokenBuffer
int strLength = (tokenEnd - tokenPtr) - 1;
strncpy(tokenBuffer, tokenPtr + 1, strLength);
tokenBuffer[strLength] = '\0';
//update the next position in the string
*stringPtr = tokenEnd + 1;
return (tokenBuffer);
}
//else find the end of the token
else
{
tokenEnd = FindTokenEnd(tokenPtr);
//if 0 was returned, the token ends on a '\0'
if (! tokenEnd)
{
//copy the token to the tokenBuffer
strcpy(tokenBuffer, tokenPtr);
//update the next position in the string
*stringPtr = &tokenPtr[strlen(tokenPtr)];
return (tokenBuffer);
}
//if the tokenEnd == the tokenPtr, the token is either a '\0', or one of the token end chars
else if (tokenEnd == tokenPtr)
{
//copy the character into the tokenBuffer
tokenBuffer[0] = *tokenPtr;
tokenBuffer[1] = '\0';
//update the next position in the string
*stringPtr = tokenEnd + 1;
return (tokenBuffer);
}
else
{
//copy the token into the tokenBuffer
int strLength = tokenEnd - tokenPtr;
strncpy(tokenBuffer, tokenPtr, strLength);
tokenBuffer[strLength] = '\0';
//update the next position in the string
*stringPtr = tokenEnd;
return (tokenBuffer);
}
}
}
//==============================================================================
// Console::Evaluate
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
bool Console::Evaluate( const char* string, const char* fileName )
{
rTuneAssert( string != 0 );
#if PROFILE_PARSER
float curTime = 0.0f, elapsedTime = 0.0f, totalTime = 0.0f;
#endif
// make sure we have a real string
if( !string[0] )
{
return( false );
}
// intialize the file name line number
strcpy( mFileName, fileName );
mLineNumber = 1;
// setup the string ptr
char* stringPtr = const_cast<char*>(string);
// process the string until it's finished
int readEndBracketLevel = 0;
bool negateCondition = false;
do
{
#if !PROFILE_PARSER
// Sound::daSoundManagerService( );
#endif
// first, get the function name
char* token = this->GetNextToken( &stringPtr, mArgv[0] );
// if no function name found, we're finished
if( !token )
{
if( readEndBracketLevel > 0 )
{
this->Printf( "ConERR file %s line %d - expecting '}'.", mFileName, mLineNumber );
rTuneAssert( 0 );
return( false );
}
break;
}
// it's possible we might read an end bracket - skip past it...
while( !smStricmp(token, "}") )
{
if( readEndBracketLevel <= 0 )
{
this->Printf( "ConERR file %s line %d - unexpected '}' found.", mFileName, mLineNumber );
rTuneAssert( 0 );
return( false );
}
// otherwise, set the bool, and read the next token
readEndBracketLevel--;
token = GetNextToken( &stringPtr, mArgv[0] );
// if no function name found, we're finished
if( !token )
{
if( readEndBracketLevel > 0 )
{
this->Printf("ConERR file %s line %d - expecting '}'.", mFileName, mLineNumber);
rTuneAssert( 0 );
return( false );
}
else
{
return( true );
}
}
}
mArgc = 1;
// see if we read a "!" symbol before a conditional function call...
if( !strcmp( token, "!") )
{
// set the bool
negateCondition = true;
//read the next token (should be function name)
token = GetNextToken(&stringPtr, mArgv[0]);
if (! token)
{
Printf("ConERR file %s line %d - unexpected '!'.", mFileName, mLineNumber);
rTuneAssert( 0 );
return (false);
}
}
//mArgv[0] currently contains the function name
//next token should be an '('
if (! ReadToken(&stringPtr, "("))
{
Printf("ConERR file %s line %d - unable to process function %s. Expecting '('", mFileName, mLineNumber, mArgv[0]);
rTuneAssert( 0 );
return (false);
}
//some bools to ensure proper syntax
bool canReadBrace = true;
bool mustReadComma = false;
do
{
//make sure we haven't run out of arguments
if (mArgc >= MAX_ARGS)
{
Printf("ConERR file %s line %d - unable to process function %s. Too many args.", mFileName, mLineNumber, mArgv[0]);
rTuneAssert( 0 );
return (false);
}
//get the next argument
token = GetNextToken(&stringPtr, mArgv[mArgc]);
if (! token)
{
Printf("ConERR file %s line %d - unable to process function %s. Expecting ')'", mFileName, mLineNumber, mArgv[0]);
rTuneAssert( 0 );
return (false);
}
//if we've read a ')', the next token should be a ';' and we've found our function
if (! smStricmp(token, ")"))
{
//make sure we can read a ')'
if (! canReadBrace)
{
Printf("ConERR file %s line %d - unable to process function %s. Extra ',' found.", mFileName, mLineNumber, mArgv[0]);
rTuneAssert( 0 );
return (false);
}
//our function and it's arguments is complete
break;
}
//else the next token is an argument or a comma
else
{
if (mustReadComma)
{
if (smStricmp(token, ","))
{
Printf("ConERR file %s line %d - unable to process function %s. Args must be separated by a ','", mFileName, mLineNumber, mArgv[0]);
rTuneAssert( 0 );
return (false);
}
//else we read our comma in correctly
else
{
mustReadComma = false;
canReadBrace = false;
}
}
//otherwise the next token is a valid argument
else
{
mArgc++;
mustReadComma = true;
canReadBrace = true;
}
}
} while (true);
//at this point, the array mArgv should contain the function name and all the arg strings
//search the table looking for the matching function
//first, search the alias table...
int i;
for (i = 0; i < mAliasCount; i++)
{
if (! smStricmp(mAliasTable[i]->name, mArgv[0]))
{
//copy the original set of args
int mPrevArgc = mArgc;
int j;
for( j = 0; j < mPrevArgc; ++j )
{
strcpy( mPrevArgv[j], mArgv[j] );
}
//replace the function name
AliasTableEntry *alias = mAliasTable[i];
strcpy(mArgv[0], alias->functionName);
//do the argument substitution
bool argcSet = false;
for (j = 0; j < alias->argc; j++)
{
//see if the variable is a substitution (%1, %2, etc...)
if (alias->argv[j][0] == '%')
{
//copy the given argment in
int index = alias->argv[j][1] - '0';
if( index < mPrevArgc )
{
strcpy( mArgv[j + 1], mPrevArgv[index] );
}
//once we get to an argument which has not been provided
//the substitutions are complete...
else
{
//set the argc
mArgc = j + 1;
argcSet = true;
break;
}
}
//else use the alias's argument
else
{
strcpy(mArgv[j + 1], alias->argv[j]);
}
}
//if we used the entire set of args from the alias, set the argc count
if (! argcSet)
mArgc = alias->argc + 1;
break;
}
}
//now the mArgc and mArgv vars are set, and any alias substitutions have been done
//search for the function
bool isConditional = false;
bool conditionalResult = false;
bool found = false;
std::map<radKey32, int>::const_iterator lookup;
lookup = mFunctionLookup.find(radMakeCaseInsensitiveKey32(mArgv[0]));
{
if( lookup != mFunctionLookup.end() )
{
i = lookup->second;
rTuneAssert( mFunctionTable[i]->name == mArgv[0] ); // make sure there wasn't a hash collision
//call the function
found = true;
//now make sure the argument count is correct
if ((mArgc - 1) >= mFunctionTable[i]->minArgs && (mArgc - 1) <= mFunctionTable[i]->maxArgs)
{
//conditional function call
if (mFunctionTable[i]->isConditional)
{
//make sure we read the opening brace '{'
if (! ReadToken(&stringPtr, "{"))
{
Printf("ConERR file %s line %d - unable to process function %s. Expecting '{'", mFileName, mLineNumber, mArgv[0]);
rTuneAssert( 0 );
return (false);
}
isConditional = true;
readEndBracketLevel++;
conditionalResult = (mFunctionTable[i]->functionPointer.boolReturn)(mArgc, (char**)mArgv);
if (negateCondition)
conditionalResult = (! conditionalResult);
negateCondition = false;
}
//non conditional function call
else
{
//make sure we're not trying to negate a non-conditional function
if (negateCondition)
{
Printf("ConERR file %s line %d - trying to negate non-conditional function %s.", mFileName, mLineNumber, mArgv[0]);
rTuneAssert( 0 );
return (false);
}
//make sure the function call ends with a ';'
if (! ReadToken(&stringPtr, ";"))
{
Printf("ConERR file %s line %d - unable to process function %s. Expecting ';'", mFileName, mLineNumber, mArgv[0]);
rTuneAssert( 0 );
return (false);
}
isConditional = false;
negateCondition = false;
(mFunctionTable[i]->functionPointer.voidReturn)(mArgc, (char**)mArgv);
//see if the function was "exit"
if (! smStricmp(mArgv[0], "exit"))
{
//print out any exit messages
if (mArgc >= 2)
GetConsole()->Printf(mArgv[1]);
//terminate evaluating...
return (true);
}
}
}
//else print out the help string, but continue processing the string
else
{
Printf("ConERR file %s line %d - invalid arg list for function: %s()", mFileName, mLineNumber, mArgv[0]);
//Printf(mFunctionTable[i]->help);
rTuneAssert( 0 );
//even though the function couldn't be called, still need to read in
//either the ';' or the '{ ... }'
if (mFunctionTable[i]->isConditional)
{
//make sure we read the opening brace '{'
if (! ReadToken(&stringPtr, "{"))
{
Printf("ConERR file %s line %d - unable to process function %s. Expecting '{'", mFileName, mLineNumber, mArgv[0]);
rTuneAssert( 0 );
return (false);
}
int balanceBrackets = readEndBracketLevel;
readEndBracketLevel++;
//skip past everything until we find the closing bracket
while (readEndBracketLevel > balanceBrackets)
{
char *token = GetNextToken(&stringPtr, mArgv[0]);
if (! token)
{
Printf("ConERR file %s line %d - end bracket for function %s not found.", mFileName, mLineNumber, mArgv[0]);
rTuneAssert( 0 );
return (false);
}
//see if we read another '{'
else if (! smStricmp(token, "{"))
readEndBracketLevel++;
else if (! smStricmp(token, "}"))
readEndBracketLevel--;
}
}
else
{
//make sure the function call ends with a ';'
if (! ReadToken(&stringPtr, ";"))
{
Printf("ConERR file %s line %d - unable to process function %s. Expecting ';'", mFileName, mLineNumber, mArgv[0]);
rTuneAssert( 0 );
return (false);
}
}
}
}
}
//if we didn't find the function, print an error msg, but go on to the next...
if (! found)
{
Printf("ConERR file %s line %d - console function not found: %s", mFileName, mLineNumber, mArgv[0]);
rTuneAssert( 0 );
//since the function couldn't be found, don't forget to skip past the ';'
if (! ReadToken(&stringPtr, ";"))
{
Printf("ConERR file %s line %d - unable to process function %s. Expecting ';'", mFileName, mLineNumber, mArgv[0]);
rTuneAssert( 0 );
return (false);
}
}
//if the function is conditional, and the result is false
//skip past until we find the closing brace...
if (isConditional && ! conditionalResult)
{
//skip past everything until we find the closing bracket
while (true)
{
char *token = GetNextToken(&stringPtr, mArgv[0]);
if (! token)
{
Printf("ConERR file %s line %d - end bracket for function %s not found.", mFileName, mLineNumber, mArgv[0]);
rTuneAssert( 0 );
return (false);
}
else if (! smStricmp(token, "}"))
{
readEndBracketLevel--;
break;
}
}
}
} while (true);
#if PROFILE_PARSER
GetConsole()->Printf("DEBUG total time spent calling functions: %.3f", totalTime);
#endif
return (true);
}
//==============================================================================
// Console::ExecuteScriptSync
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
void Console::ExecuteScriptSync( const char* filename, bool reload )
{
#if PROFILE_PARSER
float curTime = GameManager::GetRealTime();
GetConsole()->Printf("Console loading script file %s\n", filename);
#endif
GetLoadingManager()->LoadSync( FILEHANDLER_CONSOLE, filename );
}
//==============================================================================
//
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
bool Console::atob( const char* value )
{
if( atoi(value) != 0 || !smStricmp(value, "true") )
{
return( true );
}
else
{
return( false );
}
}
//==============================================================================
// Console::ExecuteScript
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
void Console::ExecuteScript
(
const char* filename,
Console::ExecuteScriptCallback* pCallback,
void* pUserData,
bool reload
)
{
rTuneAssert( filename != 0 );
rTuneAssert( pCallback != 0 );
mpCallback = pCallback;
GetLoadingManager()->AddRequest( FILEHANDLER_CONSOLE, filename, HeapMgr()->GetCurrentHeap(), this, pUserData );
}
//==============================================================================
// Console::OnProcessRequestsComplete
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
void Console::OnProcessRequestsComplete( void* pUserData )
{
mpCallback->OnExecuteScriptComplete( pUserData );
}
//******************************************************************************
//
// Private Member Functions
//
//******************************************************************************
//==============================================================================
// FunctionTableEntry::FunctionTableEntry
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
Console::FunctionTableEntry::FunctionTableEntry
(
const char* in_name,
CONSOLE_FUNCTION in_func,
const char* in_help,
int in_minArgs,
int in_maxArgs
)
:
minArgs( in_minArgs ),
maxArgs( in_maxArgs ),
isConditional( false )
{
rTuneAssert( in_func != 0 );
rTuneAssert( strlen( in_name ) < MAX_FUNCTION_NAME );
rTuneWarningMsg( strlen( in_help ) < MAX_HELP_LENGTH, "Help text too long. Text has been truncated.\n" );
functionPointer.voidReturn = in_func;
name = in_name;
help = in_help;
};
//==============================================================================
// FunctionTableEntry::FunctionTableEntry
//==============================================================================
//
// Description: Constructor.
//
// Parameters:
//
// Return: N/A.
//
//==============================================================================
Console::FunctionTableEntry::FunctionTableEntry
(
const char* in_name,
CONSOLE_BOOL_FUNCTION in_func,
const char* in_help,
int in_minArgs,
int in_maxArgs
)
:
minArgs( in_minArgs ),
maxArgs( in_maxArgs ),
isConditional( true )
{
rTuneAssert( in_func != 0 );
rTuneAssert( strlen( in_name ) < MAX_FUNCTION_NAME );
rTuneAssert( strlen( in_help ) < MAX_HELP_LENGTH );
functionPointer.boolReturn = in_func;
name = in_name;
help = in_help;
}
//==============================================================================
// AliasTableEntry::AliasTableEntry
//==============================================================================
//
// Description: Constructor.
//
// Parameters:
//
// Return: N/A.
//
//==============================================================================
Console::AliasTableEntry::AliasTableEntry
(
const char* srcName,
const char* funcName,
int srcArgc,
char** srcArgv
)
{
rTuneAssert( strlen( srcName ) < MAX_ALIAS_NAME );
rTuneAssert( strlen( funcName ) < MAX_FUNCTION_NAME );
rTuneAssert( srcArgc < MAX_ARGS );
strcpy( name, srcName );
strcpy( functionName, funcName );
argc = srcArgc;
int i;
for( i = 0; i < argc; ++i )
{
rTuneAssert( strlen( srcArgv[i]) < MAX_ARG_LENGTH );
strcpy(argv[i], srcArgv[i]);
}
}