📄 console.cc
字号:
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "platform/platform.h"
#include "console/console.h"
#include "console/consoleInternal.h"
#include "console/consoleObject.h"
#include "core/fileStream.h"
#include "core/resManager.h"
#include "console/ast.h"
#include "core/tAlgorithm.h"
#include "console/consoleTypes.h"
#include "console/telnetDebugger.h"
#include "console/simBase.h"
#include "console/compiler.h"
#include "console/stringStack.h"
#include <stdarg.h>
extern StringStack STR;
ExprEvalState gEvalState;
StmtNode *statementList;
ConsoleConstructor *ConsoleConstructor::first = NULL;
bool gWarnUndefinedScriptVariables;
static char scratchBuffer[4096];
CON_DECLARE_PARSER(CMD);
CON_DECLARE_PARSER(BAS);
#ifdef TGE_RPG_SCRIPT// Torque Chinese Script
CON_DECLARE_PARSER(CHS);
#endif
// TO-DO: Console debugger stuff to be cleaned up later
static S32 dbgGetCurrentFrame(void)
{
return gEvalState.stack.size() - 1;
}
static const char * prependDollar ( const char * name )
{
if(name[0] != '$')
{
S32 len = dStrlen(name);
AssertFatal(len < sizeof(scratchBuffer)-2, "CONSOLE: name too long");
scratchBuffer[0] = '$';
dMemcpy(scratchBuffer + 1, name, len + 1);
name = scratchBuffer;
}
return name;
}
static const char * prependPercent ( const char * name )
{
if(name[0] != '%')
{
S32 len = dStrlen(name);
AssertFatal(len < sizeof(scratchBuffer)-2, "CONSOLE: name too long");
scratchBuffer[0] = '%';
dMemcpy(scratchBuffer + 1, name, len + 1);
name = scratchBuffer;
}
return name;
}
//--------------------------------------
void ConsoleConstructor::init(const char *cName, const char *fName, const char *usg, S32 minArgs, S32 maxArgs)
{
mina = minArgs;
maxa = maxArgs;
funcName = fName;
usage = usg;
className = cName;
sc = 0; fc = 0; vc = 0; bc = 0; ic = 0;
group = false;
next = first;
first = this;
}
void ConsoleConstructor::setup()
{
for(ConsoleConstructor *walk = first; walk; walk = walk->next)
{
if(walk->sc)
Con::addCommand(walk->className, walk->funcName, walk->sc, walk->usage, walk->mina, walk->maxa);
else if(walk->ic)
Con::addCommand(walk->className, walk->funcName, walk->ic, walk->usage, walk->mina, walk->maxa);
else if(walk->fc)
Con::addCommand(walk->className, walk->funcName, walk->fc, walk->usage, walk->mina, walk->maxa);
else if(walk->vc)
Con::addCommand(walk->className, walk->funcName, walk->vc, walk->usage, walk->mina, walk->maxa);
else if(walk->bc)
Con::addCommand(walk->className, walk->funcName, walk->bc, walk->usage, walk->mina, walk->maxa);
else if(walk->group)
Con::markCommandGroup(walk->className, walk->funcName, walk->usage);
else if(walk->overload)
Con::addOverload(walk->className, walk->funcName, walk->usage);
else
AssertFatal(false, "Found a ConsoleConstructor with an indeterminate type!");
}
}
ConsoleConstructor::ConsoleConstructor(const char *className, const char *funcName, StringCallback sfunc, const char *usage, S32 minArgs, S32 maxArgs)
{
init(className, funcName, usage, minArgs, maxArgs);
sc = sfunc;
}
ConsoleConstructor::ConsoleConstructor(const char *className, const char *funcName, IntCallback ifunc, const char *usage, S32 minArgs, S32 maxArgs)
{
init(className, funcName, usage, minArgs, maxArgs);
ic = ifunc;
}
ConsoleConstructor::ConsoleConstructor(const char *className, const char *funcName, FloatCallback ffunc, const char *usage, S32 minArgs, S32 maxArgs)
{
init(className, funcName, usage, minArgs, maxArgs);
fc = ffunc;
}
ConsoleConstructor::ConsoleConstructor(const char *className, const char *funcName, VoidCallback vfunc, const char *usage, S32 minArgs, S32 maxArgs)
{
init(className, funcName, usage, minArgs, maxArgs);
vc = vfunc;
}
ConsoleConstructor::ConsoleConstructor(const char *className, const char *funcName, BoolCallback bfunc, const char *usage, S32 minArgs, S32 maxArgs)
{
init(className, funcName, usage, minArgs, maxArgs);
bc = bfunc;
}
ConsoleConstructor::ConsoleConstructor(const char* className, const char* groupName, const char* aUsage)
{
init(className, groupName, usage, -1, -2);
group = true;
// Somewhere, the entry list is getting flipped, partially.
// so we have to do tricks to deal with making sure usage
// is properly populated.
// This is probably redundant.
static char * lastUsage = NULL;
if(aUsage)
lastUsage = (char *)aUsage;
usage = lastUsage;
}
// We comment out the implementation of the Con namespace when doxygenizing because
// otherwise Doxygen decides to ignore our docs in console.h
#ifndef DOXYGENIZING
namespace Con
{
static Vector<ConsumerCallback> gConsumers(__FILE__, __LINE__);
static DataChunker consoleLogChunker;
static Vector<ConsoleLogEntry> consoleLog(__FILE__, __LINE__);
static bool consoleLogLocked;
static bool logBufferEnabled=true;
static S32 printLevel = 10;
static FileStream consoleLogFile;
#ifdef TGE_RPG
#ifdef TGE_RPGSERVER
static const char *defLogFileName = "server.log";
#else
static const char *defLogFileName = "client.log";
#endif
#else
static const char *defLogFileName = "console.log";
#endif
static S32 consoleLogMode = 0;
static bool active = false;
static bool newLogFile;
static const char *logFileName;
static const int MaxCompletionBufferSize = 4096;
static char completionBuffer[MaxCompletionBufferSize];
static char tabBuffer[MaxCompletionBufferSize] = {0};
static SimObjectPtr<SimObject> tabObject;
static U32 completionBaseStart;
static U32 completionBaseLen;
#ifdef TORQUE_MULTITHREAD
static void *mainThreadMutex;
#endif
/// Current script file name and root, these are registered as
/// console variables.
/// @{
///
StringTableEntry gCurrentFile;
StringTableEntry gCurrentRoot;
/// @}
ConsoleFunctionGroupBegin( Clipboard, "Miscellaneous functions to control the clipboard and clear the console.");
ConsoleFunction( cls, void, 1, 1, "Clear the screen.")
{
if(consoleLogLocked)
return;
consoleLogChunker.freeBlocks();
consoleLog.setSize(0);
};
ConsoleFunction( getClipboard, const char*, 1, 1, "Get text from the clipboard.")
{
return Platform::getClipboard();
};
ConsoleFunction( setClipboard, bool, 2, 2, "(string text)"
"Set the system clipboard.")
{
return Platform::setClipboard(argv[1]);
};
ConsoleFunctionGroupEnd( Clipboard );
void init()
{
AssertFatal(active == false, "Con::init should only be called once.");
// Set up general init values.
active = true;
logFileName = NULL;
newLogFile = true;
gWarnUndefinedScriptVariables = false;
#ifdef TORQUE_MULTITHREAD
// This isn't so much for locking, as a cheap way to tell if we're
// in the main thread.
mainThreadMutex = Mutex::createMutex();
Mutex::lockMutex(mainThreadMutex);
#endif
// Initialize subsystems.
Namespace::init();
ConsoleConstructor::setup();
// Set up the parser(s)
CON_ADD_PARSER(CMD, "cs", true); // TorqueScript
CON_ADD_PARSER(BAS, "bas", false); // TorqueBasic
#ifdef TGE_RPG_SCRIPT
CON_ADD_PARSER(CMD, "gui", false);
CON_ADD_PARSER(CMD, "mis", false);
CON_ADD_PARSER(CMD, "th", false);
CON_ADD_PARSER(CHS, "chs", false); // Torque Chinese Script
#endif
// Variables
setVariable("Con::prompt", "% ");
addVariable("Con::logBufferEnabled", TypeBool, &logBufferEnabled);
addVariable("Con::printLevel", TypeS32, &printLevel);
addVariable("Con::warnUndefinedVariables", TypeBool, &gWarnUndefinedScriptVariables);
// Current script file name and root
Con::addVariable( "Con::File", TypeString, &gCurrentFile );
Con::addVariable( "Con::Root", TypeString, &gCurrentRoot );
// Setup the console types.
ConsoleBaseType::initialize();
// And finally, the ACR...
AbstractClassRep::initialize();
}
//--------------------------------------
void shutdown()
{
AssertFatal(active == true, "Con::shutdown should only be called once.");
active = false;
consoleLogFile.close();
Namespace::shutdown();
#ifdef TORQUE_MULTITHREAD
Mutex::unlockMutex(mainThreadMutex);
Mutex::destroyMutex(mainThreadMutex);
#endif
}
bool isActive()
{
return active;
}
bool isMainThread()
{
#ifdef TORQUE_MULTITHREAD
if(Mutex::lockMutex(mainThreadMutex, false))
{
Mutex::unlockMutex(mainThreadMutex);
return true;
}
return false;
#else
// If we're single threaded we're always in the main thread.
return true;
#endif
}
//--------------------------------------
void getLockLog(ConsoleLogEntry *&log, U32 &size)
{
consoleLogLocked = true;
log = &consoleLog[0];
size = consoleLog.size();
}
void unlockLog()
{
consoleLogLocked = false;
}
U32 tabComplete(char* inputBuffer, U32 cursorPos, U32 maxResultLength, bool forwardTab)
{
// Check for null input.
if (!inputBuffer[0])
{
return cursorPos;
}
// Cap the max result length.
if (maxResultLength > MaxCompletionBufferSize)
{
maxResultLength = MaxCompletionBufferSize;
}
// See if this is the same partial text as last checked.
if (dStrcmp(tabBuffer, inputBuffer))
{
// If not...
// Save it for checking next time.
dStrcpy(tabBuffer, inputBuffer);
// Scan backward from the cursor position to find the base to complete from.
S32 p = cursorPos;
while ((p > 0) && (inputBuffer[p - 1] != ' ') && (inputBuffer[p - 1] != '.') && (inputBuffer[p - 1] != '('))
{
p--;
}
completionBaseStart = p;
completionBaseLen = cursorPos - p;
// Is this function being invoked on an object?
if (inputBuffer[p - 1] == '.')
{
// If so...
if (p <= 1)
{
// Bail if no object identifier.
return cursorPos;
}
// Find the object identifier.
S32 objLast = --p;
while ((p > 0) && (inputBuffer[p - 1] != ' ') && (inputBuffer[p - 1] != '('))
{
p--;
}
if (objLast == p)
{
// Bail if no object identifier.
return cursorPos;
}
// Look up the object identifier.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -