Fix stack balancing problems by refactoring execution calls

- Con::executef now uses a template
- All public execution functions now restore the console stack upon return
- Fixed bad parameters on some callbacks
- Reverts get*Arg behavior
This commit is contained in:
James Urquhart 2015-02-07 22:41:54 +00:00
parent b1ad72692c
commit f44a3f27d6
43 changed files with 1781 additions and 358 deletions

View file

@ -103,9 +103,7 @@ S32 QSORT_CALLBACK ArrayObject::_keyFunctionCompare( const void* a, const void*
ArrayObject::Element* ea = ( ArrayObject::Element* )( a );
ArrayObject::Element* eb = ( ArrayObject::Element* )( b );
ConsoleValueRef argv[] = { smCompareFunction, ea->key, eb->key };
S32 result = dAtoi( Con::execute( 3, argv ) );
S32 result = dAtoi( Con::executef( (const char*)smCompareFunction, ea->value, eb->key ) );
S32 res = result < 0 ? -1 : ( result > 0 ? 1 : 0 );
return ( smDecreasing ? -res : res );
}
@ -115,9 +113,7 @@ S32 QSORT_CALLBACK ArrayObject::_valueFunctionCompare( const void* a, const void
ArrayObject::Element* ea = ( ArrayObject::Element* )( a );
ArrayObject::Element* eb = ( ArrayObject::Element* )( b );
ConsoleValueRef argv[] = { smCompareFunction, ea->value, eb->value };
S32 result = dAtoi( Con::execute( 3, argv ) );
S32 result = dAtoi( Con::executef( (const char*)smCompareFunction, ea->value, eb->value ) );
S32 res = result < 0 ? -1 : ( result > 0 ? 1 : 0 );
return ( smDecreasing ? -res : res );
}

View file

@ -570,7 +570,7 @@ bool CodeBlock::compile(const char *codeFileName, StringTableEntry fileName, con
}
const char *CodeBlock::compileExec(StringTableEntry fileName, const char *inString, bool noCalls, S32 setFrame)
ConsoleValueRef CodeBlock::compileExec(StringTableEntry fileName, const char *inString, bool noCalls, S32 setFrame)
{
AssertFatal(Con::isMainThread(), "Compiling code on a secondary thread");
@ -635,7 +635,7 @@ const char *CodeBlock::compileExec(StringTableEntry fileName, const char *inStri
if(!gStatementList)
{
delete this;
return "";
return ConsoleValueRef();
}
resetTables();

View file

@ -129,7 +129,7 @@ public:
/// with, zero being the top of the stack. If the the index is
/// -1 a new frame is created. If the index is out of range the
/// top stack frame is used.
const char *compileExec(StringTableEntry fileName, const char *script,
ConsoleValueRef compileExec(StringTableEntry fileName, const char *script,
bool noCalls, S32 setFrame = -1 );
/// Executes the existing code in the CodeBlock. The return string is any

View file

@ -195,18 +195,20 @@ namespace Con
return STR.getArgBuffer(bufferSize);
}
ConsoleValueRef getFloatArg(F64 arg)
char *getFloatArg(F64 arg)
{
ConsoleValueRef ref = arg;
return ref;
char *ret = STR.getArgBuffer(32);
dSprintf(ret, 32, "%g", arg);
return ret;
}
ConsoleValueRef getIntArg(S32 arg)
char *getIntArg(S32 arg)
{
ConsoleValueRef ref = arg;
return ref;
char *ret = STR.getArgBuffer(32);
dSprintf(ret, 32, "%d", arg);
return ret;
}
char *getStringArg( const char *arg )
{
U32 len = dStrlen( arg ) + 1;
@ -432,6 +434,8 @@ ConsoleValueRef CodeBlock::exec(U32 ip, const char *functionName, Namespace *thi
U32 consoleStackStart = CSTK.mStackPos;
#endif
//Con::printf("CodeBlock::exec(%s,%u)", functionName ? functionName : "??", ip);
static char traceBuffer[1024];
S32 i;
@ -441,7 +445,7 @@ ConsoleValueRef CodeBlock::exec(U32 ip, const char *functionName, Namespace *thi
F64 *curFloatTable;
char *curStringTable;
S32 curStringTableLen = 0; //clint to ensure we dont overwrite it
STR.clearFunctionOffset();
STR.clearFunctionOffset(); // ensures arg buffer offset is back to 0
StringTableEntry thisFunctionName = NULL;
bool popFrame = false;
if(argv)
@ -533,17 +537,6 @@ ConsoleValueRef CodeBlock::exec(U32 ip, const char *functionName, Namespace *thi
}
}
bool doResetValueStack = !gEvalState.mResetLocked;
gEvalState.mResetLocked = true;
if (gEvalState.mShouldReset)
{
// Ensure all stacks are clean in case anything became unbalanced during the previous execution
STR.clearFrames();
CSTK.clearFrames();
gEvalState.mShouldReset = false;
}
// Grab the state of the telenet debugger here once
// so that the push and pop frames are always balanced.
const bool telDebuggerOn = TelDebugger && TelDebugger->isConnected();
@ -1847,7 +1840,7 @@ breakContinue:
// This will clear everything including returnValue
CSTK.popFrame();
STR.clearFunctionOffset();
//STR.clearFunctionOffset();
}
else
{
@ -2234,18 +2227,11 @@ execFinished:
Con::gCurrentRoot = saveCodeBlock->modPath;
}
// Mark the reset flag for the next run if we've finished execution
if (doResetValueStack)
{
gEvalState.mShouldReset = true;
gEvalState.mResetLocked = false;
}
decRefCount();
#ifdef TORQUE_DEBUG
AssertFatal(!(STR.mStartStackSize > stackStart), "String stack not popped enough in script exec");
AssertFatal(!(STR.mStartStackSize < stackStart), "String stack popped too much in script exec");
//AssertFatal(!(STR.mStartStackSize > stackStart), "String stack not popped enough in script exec");
//AssertFatal(!(STR.mStartStackSize < stackStart), "String stack popped too much in script exec");
#endif
return returnValue;

View file

@ -1138,8 +1138,11 @@ void addCommand( const char *name,BoolCallback cb,const char *usage, S32 minArgs
Namespace::global()->addCommand( StringTable->insert(name), cb, usage, minArgs, maxArgs, isToolOnly, header );
}
const char *evaluate(const char* string, bool echo, const char *fileName)
ConsoleValueRef evaluate(const char* string, bool echo, const char *fileName)
{
ConsoleStackFrameSaver stackSaver;
stackSaver.save();
if (echo)
{
if (string[0] == '%')
@ -1156,8 +1159,11 @@ const char *evaluate(const char* string, bool echo, const char *fileName)
}
//------------------------------------------------------------------------------
const char *evaluatef(const char* string, ...)
ConsoleValueRef evaluatef(const char* string, ...)
{
ConsoleStackFrameSaver stackSaver;
stackSaver.save();
char buffer[4096];
va_list args;
va_start(args, string);
@ -1166,26 +1172,34 @@ const char *evaluatef(const char* string, ...)
return newCodeBlock->compileExec(NULL, buffer, false, 0);
}
const char *execute(S32 argc, ConsoleValueRef argv[])
//------------------------------------------------------------------------------
// Internal execute for global function which does not save the stack
ConsoleValueRef _internalExecute(S32 argc, ConsoleValueRef argv[])
{
Namespace::Entry *ent;
StringTableEntry funcName = StringTable->insert(argv[0]);
ent = Namespace::global()->lookup(funcName);
if(!ent)
{
warnf(ConsoleLogEntry::Script, "%s: Unknown command.", (const char*)argv[0]);
STR.clearFunctionOffset();
return ConsoleValueRef();
}
return ent->execute(argc, argv, &gEvalState);
}
ConsoleValueRef execute(S32 argc, ConsoleValueRef argv[])
{
#ifdef TORQUE_MULTITHREAD
if(isMainThread())
{
#endif
Namespace::Entry *ent;
StringTableEntry funcName = StringTable->insert(argv[0]);
ent = Namespace::global()->lookup(funcName);
if(!ent)
{
warnf(ConsoleLogEntry::Script, "%s: Unknown command.", (const char*)argv[0]);
// Clean up arg buffers, if any.
STR.clearFunctionOffset();
CSTK.resetFrame();
return "";
}
return ent->execute(argc, argv, &gEvalState);
ConsoleStackFrameSaver stackSaver;
stackSaver.save();
return _internalExecute(argc, argv);
#ifdef TORQUE_MULTITHREAD
}
else
@ -1199,17 +1213,24 @@ const char *execute(S32 argc, ConsoleValueRef argv[])
#endif
}
const char *execute(S32 argc, const char *argv[])
ConsoleValueRef execute(S32 argc, const char *argv[])
{
ConsoleStackFrameSaver stackSaver;
stackSaver.save();
StringStackConsoleWrapper args(argc, argv);
return execute(args.count(), args);
}
//------------------------------------------------------------------------------
const char *execute(SimObject *object, S32 argc, ConsoleValueRef argv[], bool thisCallOnly)
// Internal execute for object method which does not save the stack
ConsoleValueRef _internalExecute(SimObject *object, S32 argc, ConsoleValueRef argv[], bool thisCallOnly)
{
if(argc < 2)
return "";
{
STR.clearFunctionOffset();
return ConsoleValueRef();
}
// [neo, 10/05/2007 - #3010]
// Make sure we don't get recursive calls, respect the flag!
@ -1229,10 +1250,8 @@ const char *execute(SimObject *object, S32 argc, ConsoleValueRef argv[], bool th
if(object->getNamespace())
{
ConsoleValueRef internalArgv[StringStack::MaxArgs];
U32 ident = object->getId();
ConsoleValueRef oldIdent = argv[1];
U32 ident = object->getId();
ConsoleValueRef oldIdent = argv[1];
StringTableEntry funcName = StringTable->insert(argv[0]);
Namespace::Entry *ent = object->getNamespace()->lookup(funcName);
@ -1241,10 +1260,8 @@ const char *execute(SimObject *object, S32 argc, ConsoleValueRef argv[], bool th
{
//warnf(ConsoleLogEntry::Script, "%s: undefined for object '%s' - id %d", funcName, object->getName(), object->getId());
// Clean up arg buffers, if any.
STR.clearFunctionOffset();
CSTK.resetFrame();
return "";
return ConsoleValueRef();
}
// Twiddle %this argument
@ -1252,7 +1269,7 @@ const char *execute(SimObject *object, S32 argc, ConsoleValueRef argv[], bool th
SimObject *save = gEvalState.thisObject;
gEvalState.thisObject = object;
const char *ret = ent->execute(argc, argv, &gEvalState);
ConsoleValueRef ret = ent->execute(argc, argv, &gEvalState);
gEvalState.thisObject = save;
// Twiddle it back
@ -1260,17 +1277,52 @@ const char *execute(SimObject *object, S32 argc, ConsoleValueRef argv[], bool th
return ret;
}
warnf(ConsoleLogEntry::Script, "Con::execute - %d has no namespace: %s", object->getId(), (const char*)argv[0]);
return "";
STR.clearFunctionOffset();
return ConsoleValueRef();
}
const char *execute(SimObject *object, S32 argc, const char *argv[], bool thisCallOnly)
ConsoleValueRef execute(SimObject *object, S32 argc, ConsoleValueRef argv[], bool thisCallOnly)
{
if(argc < 2)
{
STR.clearFunctionOffset();
return ConsoleValueRef();
}
ConsoleStackFrameSaver stackSaver;
stackSaver.save();
if (object->getNamespace() || !thisCallOnly)
{
if (isMainThread())
{
return _internalExecute(object, argc, argv, thisCallOnly);
}
else
{
SimConsoleThreadExecCallback cb;
SimConsoleThreadExecEvent *evt = new SimConsoleThreadExecEvent(argc, argv, true, &cb);
Sim::postEvent(object, evt, Sim::getCurrentTime());
}
}
warnf(ConsoleLogEntry::Script, "Con::execute - %d has no namespace: %s", object->getId(), (const char*)argv[0]);
STR.clearFunctionOffset();
return ConsoleValueRef();
}
ConsoleValueRef execute(SimObject *object, S32 argc, const char *argv[], bool thisCallOnly)
{
ConsoleStackFrameSaver stackSaver;
stackSaver.save();
StringStackConsoleWrapper args(argc, argv);
return execute(object, args.count(), args, thisCallOnly);
}
inline const char*_executef(SimObject *obj, S32 checkArgc, S32 argc, ConsoleValueRef *argv)
inline ConsoleValueRef _executef(SimObject *obj, S32 checkArgc, S32 argc, ConsoleValueRef *argv)
{
const U32 maxArg = 12;
AssertWarn(checkArgc == argc, "Incorrect arg count passed to Con::executef(SimObject*)");
@ -1278,42 +1330,14 @@ inline const char*_executef(SimObject *obj, S32 checkArgc, S32 argc, ConsoleValu
return execute(obj, argc, argv);
}
#define A ConsoleValueRef
#define OBJ SimObject* obj
const char *executef(OBJ, A a) { ConsoleValueRef params[] = {a,ConsoleValueRef()}; return _executef(obj, 2, 2, params); }
const char *executef(OBJ, A a, A b) { ConsoleValueRef params[] = {a,ConsoleValueRef(),b}; return _executef(obj, 3, 3, params); }
const char *executef(OBJ, A a, A b, A c) { ConsoleValueRef params[] = {a,ConsoleValueRef(),b,c}; return _executef(obj, 4, 4, params); }
const char *executef(OBJ, A a, A b, A c, A d) { ConsoleValueRef params[] = {a,ConsoleValueRef(),b,c,d}; return _executef(obj, 5, 5, params); }
const char *executef(OBJ, A a, A b, A c, A d, A e) { ConsoleValueRef params[] = {a,ConsoleValueRef(),b,c,d,e}; return _executef(obj, 6, 6, params); }
const char *executef(OBJ, A a, A b, A c, A d, A e, A f) { ConsoleValueRef params[] = {a,ConsoleValueRef(),b,c,d,e,f}; return _executef(obj, 7, 7, params); }
const char *executef(OBJ, A a, A b, A c, A d, A e, A f, A g) { ConsoleValueRef params[] = {a,ConsoleValueRef(),b,c,d,e,f,g}; return _executef(obj, 8, 8, params); }
const char *executef(OBJ, A a, A b, A c, A d, A e, A f, A g, A h) { ConsoleValueRef params[] = {a,ConsoleValueRef(),b,c,d,e,f,g,h}; return _executef(obj, 9, 9, params); }
const char *executef(OBJ, A a, A b, A c, A d, A e, A f, A g, A h, A i) { ConsoleValueRef params[] = {a,ConsoleValueRef(),b,c,d,e,f,g,h,i}; return _executef(obj, 10, 10, params); }
const char *executef(OBJ, A a, A b, A c, A d, A e, A f, A g, A h, A i, A j) { ConsoleValueRef params[] = {a,ConsoleValueRef(),b,c,d,e,f,g,h,i,j}; return _executef(obj, 11, 11, params); }
const char *executef(OBJ, A a, A b, A c, A d, A e, A f, A g, A h, A i, A j, A k) { ConsoleValueRef params[] = {a,ConsoleValueRef(),b,c,d,e,f,g,h,i,j,k}; return _executef(obj, 12, 12, params); }
//------------------------------------------------------------------------------
inline const char*_executef(S32 checkArgc, S32 argc, ConsoleValueRef *argv)
inline ConsoleValueRef _executef(S32 checkArgc, S32 argc, ConsoleValueRef *argv)
{
const U32 maxArg = 10;
AssertFatal(checkArgc == argc, "Incorrect arg count passed to Con::executef()");
AssertFatal(argc <= maxArg, "Too many args passed to Con::_executef(). Please update the function to handle more.");
return execute(argc, argv);
}
#define A ConsoleValueRef
const char *executef(A a) { ConsoleValueRef params[] = {a}; return _executef(1, 1, params); }
const char *executef(A a, A b) { ConsoleValueRef params[] = {a,b}; return _executef(2, 2, params); }
const char *executef(A a, A b, A c) { ConsoleValueRef params[] = {a,b,c}; return _executef(3, 3, params); }
const char *executef(A a, A b, A c, A d) { ConsoleValueRef params[] = {a,b,c,d}; return _executef(4, 4, params); }
const char *executef(A a, A b, A c, A d, A e) { ConsoleValueRef params[] = {a,b,c,d,e}; return _executef(5, 5, params); }
const char *executef(A a, A b, A c, A d, A e, A f) { ConsoleValueRef params[] = {a,b,c,d,e,f}; return _executef(1, 1, params); }
const char *executef(A a, A b, A c, A d, A e, A f, A g) { ConsoleValueRef params[] = {a,b,c,d,e,f,g}; return _executef(1, 1, params); }
const char *executef(A a, A b, A c, A d, A e, A f, A g, A h) { ConsoleValueRef params[] = {a,b,c,d,e,f,g,h}; return _executef(1, 1, params); }
const char *executef(A a, A b, A c, A d, A e, A f, A g, A h, A i) { ConsoleValueRef params[] = {a,b,c,d,e,f,g,h,i}; return _executef(1, 1, params); }
const char *executef(A a, A b, A c, A d, A e, A f, A g, A h, A i, A j) { ConsoleValueRef params[] = {a,b,c,d,e,f,g,h,i,j}; return _executef(1, 1, params); }
#undef A
//------------------------------------------------------------------------------
bool isFunction(const char *fn)
@ -1576,10 +1600,13 @@ DefineEngineFunction( logWarning, void, ( const char* message ),,
Con::warnf( "%s", message );
}
//------------------------------------------------------------------------------
extern ConsoleValueStack CSTK;
ConsoleValueRef::ConsoleValueRef(const ConsoleValueRef &ref)
{
value = ref.value;
stringStackValue = ref.stringStackValue;
value = ref.value;
}
ConsoleValueRef::ConsoleValueRef(const char *newValue) : value(NULL)
@ -1612,6 +1639,49 @@ ConsoleValueRef::ConsoleValueRef(F64 newValue) : value(NULL)
*this = newValue;
}
ConsoleValueRef& ConsoleValueRef::operator=(const ConsoleValueRef &newValue)
{
value = newValue.value;
return *this;
}
ConsoleValueRef& ConsoleValueRef::operator=(const char *newValue)
{
AssertFatal(value, "value should not be NULL");
value->setStringValue(newValue);
return *this;
}
ConsoleValueRef& ConsoleValueRef::operator=(S32 newValue)
{
AssertFatal(value, "value should not be NULL");
value->setIntValue(newValue);
return *this;
}
ConsoleValueRef& ConsoleValueRef::operator=(U32 newValue)
{
AssertFatal(value, "value should not be NULL");
value->setIntValue(newValue);
return *this;
}
ConsoleValueRef& ConsoleValueRef::operator=(F32 newValue)
{
AssertFatal(value, "value should not be NULL");
value->setFloatValue(newValue);
return *this;
}
ConsoleValueRef& ConsoleValueRef::operator=(F64 newValue)
{
AssertFatal(value, "value should not be NULL");
value->setFloatValue(newValue);
return *this;
}
//------------------------------------------------------------------------------
StringStackWrapper::StringStackWrapper(int targc, ConsoleValueRef targv[])
{
argv = new const char*[targc];
@ -1636,10 +1706,13 @@ StringStackWrapper::~StringStackWrapper()
StringStackConsoleWrapper::StringStackConsoleWrapper(int targc, const char** targ)
{
argv = new ConsoleValueRef[targc];
argvValue = new ConsoleValue[targc];
argc = targc;
for (int i=0; i<targc; i++) {
argv[i] = ConsoleValueRef(targ[i]);
argvValue[i].init();
argv[i].value = &argvValue[i];
argvValue[i].setStackStringValue(targ[i]);
}
}
@ -1650,8 +1723,11 @@ StringStackConsoleWrapper::~StringStackConsoleWrapper()
argv[i] = 0;
}
delete[] argv;
delete[] argvValue;
}
//------------------------------------------------------------------------------
S32 ConsoleValue::getSignedIntValue()
{
if(type <= TypeInternalString)
@ -1752,70 +1828,49 @@ void ConsoleValue::setFloatValue(F32 val)
}
}
//------------------------------------------------------------------------------
const char *ConsoleValueRef::getStringArgValue()
ConsoleValueRef _BaseEngineConsoleCallbackHelper::_exec()
{
if (value)
ConsoleValueRef returnValue;
if( mThis )
{
if (stringStackValue == NULL)
stringStackValue = Con::getStringArg(value->getStringValue());
return stringStackValue;
// Cannot invoke callback until object has been registered
if (mThis->isProperlyAdded()) {
returnValue = Con::_internalExecute( mThis, mArgc, mArgv, false );
} else {
STR.clearFunctionOffset();
returnValue = ConsoleValueRef();
}
}
else
returnValue = Con::_internalExecute( mArgc, mArgv );
mArgc = mInitialArgc; // reset args
return returnValue;
}
ConsoleValueRef _BaseEngineConsoleCallbackHelper::_execLater(SimConsoleThreadExecEvent *evt)
{
mArgc = mInitialArgc; // reset args
Sim::postEvent((SimObject*)Sim::getRootGroup(), evt, Sim::getCurrentTime());
return evt->getCB().waitForResult();
}
//------------------------------------------------------------------------------
void ConsoleStackFrameSaver::save()
{
CSTK.pushFrame();
STR.pushFrame();
mSaved = true;
}
void ConsoleStackFrameSaver::restore()
{
if (mSaved)
{
return "";
CSTK.popFrame();
STR.popFrame();
}
}
extern ConsoleValueStack CSTK;
ConsoleValueRef& ConsoleValueRef::operator=(const ConsoleValueRef &newValue)
{
value = newValue.value;
stringStackValue = newValue.stringStackValue;
return *this;
}
ConsoleValueRef& ConsoleValueRef::operator=(const char *newValue)
{
value = CSTK.pushStackString(newValue);
stringStackValue = NULL;
return *this;
}
ConsoleValueRef& ConsoleValueRef::operator=(S32 newValue)
{
value = CSTK.pushFLT(newValue);
stringStackValue = NULL;
return *this;
}
ConsoleValueRef& ConsoleValueRef::operator=(U32 newValue)
{
value = CSTK.pushUINT(newValue);
stringStackValue = NULL;
return *this;
}
ConsoleValueRef& ConsoleValueRef::operator=(F32 newValue)
{
value = CSTK.pushFLT(newValue);
stringStackValue = NULL;
return *this;
}
ConsoleValueRef& ConsoleValueRef::operator=(F64 newValue)
{
value = CSTK.pushFLT(newValue);
stringStackValue = NULL;
return *this;
}
namespace Con
{
void resetStackFrame()
{
CSTK.resetFrame();
}
}
}

View file

@ -181,6 +181,7 @@ public:
fval = 0;
sval = typeValueEmpty;
bufferLen = 0;
type = TypeInternalString;
}
void cleanup()
@ -203,9 +204,8 @@ class ConsoleValueRef
{
public:
ConsoleValue *value;
const char *stringStackValue;
ConsoleValueRef() : value(0), stringStackValue(0) { ; }
ConsoleValueRef() : value(0) { ; }
~ConsoleValueRef() { ; }
ConsoleValueRef(const ConsoleValueRef &ref);
@ -216,8 +216,9 @@ public:
ConsoleValueRef(F32 value);
ConsoleValueRef(F64 value);
static ConsoleValueRef fromValue(ConsoleValue *value) { ConsoleValueRef ref; ref.value = value; return ref; }
const char *getStringValue() { return value ? value->getStringValue() : ""; }
const char *getStringArgValue();
inline U32 getIntValue() { return value ? value->getIntValue() : 0; }
inline S32 getSignedIntValue() { return value ? value->getSignedIntValue() : 0; }
@ -229,6 +230,7 @@ public:
inline operator U32() { return getIntValue(); }
inline operator S32() { return getSignedIntValue(); }
inline operator F32() { return getFloatValue(); }
inline operator bool() { return getBoolValue(); }
inline bool isString() { return value ? value->type >= ConsoleValue::TypeInternalStackString : true; }
inline bool isInt() { return value ? value->type == ConsoleValue::TypeInternalInt : false; }
@ -281,6 +283,7 @@ public:
class StringStackConsoleWrapper
{
public:
ConsoleValue *argvValue;
ConsoleValueRef *argv;
int argc;
@ -753,23 +756,9 @@ namespace Con
/// char* argv[] = {"abs", "-9"};
/// char* result = execute(2, argv);
/// @endcode
const char *execute(S32 argc, const char* argv[]);
const char *execute(S32 argc, ConsoleValueRef argv[]);
/// @see execute(S32 argc, const char* argv[])
// Note: this can't be ConsoleValueRef& since the compiler will confuse it with SimObject*
#define ARG ConsoleValueRef
const char *executef( ARG);
const char *executef( ARG, ARG);
const char *executef( ARG, ARG, ARG);
const char *executef( ARG, ARG, ARG, ARG);
const char *executef( ARG, ARG, ARG, ARG, ARG);
const char *executef( ARG, ARG, ARG, ARG, ARG, ARG);
const char *executef( ARG, ARG, ARG, ARG, ARG, ARG, ARG);
const char *executef( ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG);
const char *executef( ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG);
const char *executef( ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG);
#undef ARG
/// NOTE: this function restores the console stack on return.
ConsoleValueRef execute(S32 argc, const char* argv[]);
ConsoleValueRef execute(S32 argc, ConsoleValueRef argv[]);
/// Call a Torque Script member function of a SimObject from C/C++ code.
/// @param object Object on which to execute the method call.
@ -783,35 +772,23 @@ namespace Con
/// char* argv[] = {"setMode", "", "2"};
/// char* result = execute(mysimobject, 3, argv);
/// @endcode
const char *execute(SimObject *object, S32 argc, const char *argv[], bool thisCallOnly = false);
const char *execute(SimObject *object, S32 argc, ConsoleValueRef argv[], bool thisCallOnly = false);
/// @see execute(SimObject *, S32 argc, ConsoleValueRef argv[])
#define ARG ConsoleValueRef
const char *executef(SimObject *, ARG);
const char *executef(SimObject *, ARG, ARG);
const char *executef(SimObject *, ARG, ARG, ARG);
const char *executef(SimObject *, ARG, ARG, ARG, ARG);
const char *executef(SimObject *, ARG, ARG, ARG, ARG, ARG);
const char *executef(SimObject *, ARG, ARG, ARG, ARG, ARG, ARG);
const char *executef(SimObject *, ARG, ARG, ARG, ARG, ARG, ARG, ARG);
const char *executef(SimObject *, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG);
const char *executef(SimObject *, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG);
const char *executef(SimObject *, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG);
const char *executef(SimObject *, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG, ARG);
#undef ARG
/// NOTE: this function restores the console stack on return.
ConsoleValueRef execute(SimObject *object, S32 argc, const char* argv[], bool thisCallOnly = false);
ConsoleValueRef execute(SimObject *object, S32 argc, ConsoleValueRef argv[], bool thisCallOnly = false);
/// Evaluate an arbitrary chunk of code.
///
/// @param string Buffer containing code to execute.
/// @param echo Should we echo the string to the console?
/// @param fileName Indicate what file this code is coming from; used in error reporting and such.
const char *evaluate(const char* string, bool echo = false, const char *fileName = NULL);
/// NOTE: This function restores the console stack on return.
ConsoleValueRef evaluate(const char* string, bool echo = false, const char *fileName = NULL);
/// Evaluate an arbitrary line of script.
///
/// This wraps dVsprintf(), so you can substitute parameters into the code being executed.
const char *evaluatef(const char* string, ...);
/// NOTE: This function restores the console stack on return.
ConsoleValueRef evaluatef(const char* string, ...);
/// @}
@ -831,14 +808,12 @@ namespace Con
char* getReturnBuffer( const StringBuilder& str );
char* getArgBuffer(U32 bufferSize);
ConsoleValueRef getFloatArg(F64 arg);
ConsoleValueRef getIntArg (S32 arg);
char* getStringArg( const char *arg );
char* getFloatArg(F64 arg);
char* getIntArg (S32 arg);
char* getStringArg( const char* arg );
char* getStringArg( const String& arg );
/// @}
void resetStackFrame();
/// @name Namespaces
/// @{
@ -872,21 +847,47 @@ namespace Con
/// @name Dynamic Type System
/// @{
///
/* void registerType( const char *typeName, S32 type, S32 size, GetDataFunction gdf, SetDataFunction sdf, bool isDatablockType = false );
void registerType( const char* typeName, S32 type, S32 size, bool isDatablockType = false );
void registerTypeGet( S32 type, GetDataFunction gdf );
void registerTypeSet( S32 type, SetDataFunction sdf );
const char *getTypeName(S32 type);
bool isDatablockType( S32 type ); */
void setData(S32 type, void *dptr, S32 index, S32 argc, const char **argv, const EnumTable *tbl = NULL, BitSet32 flag = 0);
const char *getData(S32 type, void *dptr, S32 index, const EnumTable *tbl = NULL, BitSet32 flag = 0);
const char *getFormattedData(S32 type, const char *data, const EnumTable *tbl = NULL, BitSet32 flag = 0);
/// @}
};
struct _EngineConsoleCallbackHelper;
template<typename P1> struct _EngineConsoleExecCallbackHelper;
namespace Con
{
/// @name Console Execution - executef
/// {
///
/// Implements a script function thunk which automatically converts parameters to relevant console types.
/// Can be used as follows:
/// - Con::executef("functionName", ...);
/// - Con::executef(mySimObject, "functionName", ...);
///
/// NOTE: if you get a rather cryptic template error coming through here, most likely you are trying to
/// convert a parameter which EngineMarshallType does not have a specialization for.
/// Another problem can occur if you do not include "console/simBase.h" and "console/engineAPI.h"
/// since _EngineConsoleExecCallbackHelper and SimConsoleThreadExecCallback are required.
///
/// @see _EngineConsoleExecCallbackHelper
///
template<typename A> ConsoleValueRef executef(A a) { _EngineConsoleExecCallbackHelper<A> callback( a ); return callback.call<ConsoleValueRef>(); }
template<typename A, typename B> ConsoleValueRef executef(A a, B b) { _EngineConsoleExecCallbackHelper<A> callback( a ); return callback.call<ConsoleValueRef>(b); }
template<typename A, typename B, typename C> ConsoleValueRef executef(A a, B b, C c) { _EngineConsoleExecCallbackHelper<A> callback( a ); return callback.call<ConsoleValueRef>(b, c); }
template<typename A, typename B, typename C, typename D> ConsoleValueRef executef(A a, B b, C c, D d) { _EngineConsoleExecCallbackHelper<A> callback( a ); return callback.call<ConsoleValueRef>(b, c, d); }
template<typename A, typename B, typename C, typename D, typename E> ConsoleValueRef executef(A a, B b, C c, D d, E e) { _EngineConsoleExecCallbackHelper<A> callback( a ); return callback.call<ConsoleValueRef>(b, c, d, e); }
template<typename A, typename B, typename C, typename D, typename E, typename F> ConsoleValueRef executef(A a, B b, C c, D d, E e, F f) { _EngineConsoleExecCallbackHelper<A> callback( a ); return callback.call<ConsoleValueRef>(b, c, d, e, f); }
template<typename A, typename B, typename C, typename D, typename E, typename F, typename G> ConsoleValueRef executef(A a, B b, C c, D d, E e, F f, G g) { _EngineConsoleExecCallbackHelper<A> callback( a ); return callback.call<ConsoleValueRef>(b, c, d, e, f, g); }
template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H> ConsoleValueRef executef(A a, B b, C c, D d, E e, F f, G g, H h) { _EngineConsoleExecCallbackHelper<A> callback( a ); return callback.call<ConsoleValueRef>(b, c, d, e, f, g, h); }
template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I> ConsoleValueRef executef(A a, B b, C c, D d, E e, F f, G g, H h, I i) { _EngineConsoleExecCallbackHelper<A> callback( a ); return callback.call<ConsoleValueRef>(b, c, d, e, f, g, h, i); }
template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J> ConsoleValueRef executef(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j) { _EngineConsoleExecCallbackHelper<A> callback( a ); return callback.call<ConsoleValueRef>(b, c, d, e, f, g, h, i, j); }
template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J, typename K> ConsoleValueRef executef(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k) { _EngineConsoleExecCallbackHelper<A> callback( a ); return callback.call<ConsoleValueRef>(b, c, d, e, f, g, h, i, j, k); }
/// }
};
extern void expandEscape(char *dest, const char *src);
extern bool collapseEscape(char *buf);
extern U32 HashPointer(StringTableEntry ptr);
@ -1103,6 +1104,28 @@ struct ConsoleDocFragment
};
/// Utility class to save and restore the current console stack frame
///
class ConsoleStackFrameSaver
{
public:
bool mSaved;
ConsoleStackFrameSaver() : mSaved(false)
{
}
~ConsoleStackFrameSaver()
{
restore();
}
void save();
void restore();
};
/// @name Global Console Definition Macros
///
/// @note If TORQUE_DEBUG is defined, then we gather documentation information, and

View file

@ -1338,14 +1338,20 @@ void Namespace::markGroup(const char* name, const char* usage)
extern S32 executeBlock(StmtNode *block, ExprEvalState *state);
const char *Namespace::Entry::execute(S32 argc, ConsoleValueRef *argv, ExprEvalState *state)
ConsoleValueRef Namespace::Entry::execute(S32 argc, ConsoleValueRef *argv, ExprEvalState *state)
{
STR.clearFunctionOffset();
if(mType == ConsoleFunctionType)
{
if(mFunctionOffset)
{
return mCode->exec(mFunctionOffset, argv[0], mNamespace, argc, argv, false, mPackage);
}
else
return "";
{
return ConsoleValueRef();
}
}
#ifndef TORQUE_DEBUG
@ -1354,7 +1360,7 @@ const char *Namespace::Entry::execute(S32 argc, ConsoleValueRef *argv, ExprEvalS
if(mToolOnly && ! Con::isCurrentScriptToolScript())
{
Con::errorf(ConsoleLogEntry::Script, "%s::%s - attempting to call tools only function from outside of tools", mNamespace->mName, mFunctionName);
return "";
return ConsoleValueRef();
}
#endif
@ -1362,32 +1368,26 @@ const char *Namespace::Entry::execute(S32 argc, ConsoleValueRef *argv, ExprEvalS
{
Con::warnf(ConsoleLogEntry::Script, "%s::%s - wrong number of arguments.", mNamespace->mName, mFunctionName);
Con::warnf(ConsoleLogEntry::Script, "usage: %s", mUsage);
return "";
return ConsoleValueRef();
}
static char returnBuffer[32];
switch(mType)
{
case StringCallbackType:
return cb.mStringCallbackFunc(state->thisObject, argc, argv);
return ConsoleValueRef::fromValue(CSTK.pushStackString(cb.mStringCallbackFunc(state->thisObject, argc, argv)));
case IntCallbackType:
dSprintf(returnBuffer, sizeof(returnBuffer), "%d",
cb.mIntCallbackFunc(state->thisObject, argc, argv));
return returnBuffer;
return ConsoleValueRef::fromValue(CSTK.pushUINT((U32)cb.mBoolCallbackFunc(state->thisObject, argc, argv)));
case FloatCallbackType:
dSprintf(returnBuffer, sizeof(returnBuffer), "%g",
cb.mFloatCallbackFunc(state->thisObject, argc, argv));
return returnBuffer;
return ConsoleValueRef::fromValue(CSTK.pushFLT((U32)cb.mBoolCallbackFunc(state->thisObject, argc, argv)));
case VoidCallbackType:
cb.mVoidCallbackFunc(state->thisObject, argc, argv);
return "";
return ConsoleValueRef();
case BoolCallbackType:
dSprintf(returnBuffer, sizeof(returnBuffer), "%d",
(U32)cb.mBoolCallbackFunc(state->thisObject, argc, argv));
return returnBuffer;
return ConsoleValueRef::fromValue(CSTK.pushUINT((U32)cb.mBoolCallbackFunc(state->thisObject, argc, argv)));
}
return "";
return ConsoleValueRef();
}
//-----------------------------------------------------------------------------

View file

@ -151,7 +151,7 @@ class Namespace
void clear();
///
const char *execute( S32 argc, ConsoleValueRef* argv, ExprEvalState* state );
ConsoleValueRef execute( S32 argc, ConsoleValueRef* argv, ExprEvalState* state );
/// Return a one-line documentation text string for the function.
String getBriefDescription( String* outRemainingDocText = NULL ) const;

File diff suppressed because it is too large Load diff

View file

@ -157,13 +157,13 @@ namespace Sim
SimTime getTargetTime();
/// a target time of 0 on an event means current event
U32 postEvent(SimObject*, SimEvent*, U32 targetTime);
U32 postEvent(SimObject*, SimEvent*, SimTime targetTime);
inline U32 postEvent(SimObjectId iD,SimEvent*evt, U32 targetTime)
inline U32 postEvent(SimObjectId iD,SimEvent*evt, SimTime targetTime)
{
return postEvent(findObject(iD), evt, targetTime);
}
inline U32 postEvent(const char *objectName,SimEvent*evt, U32 targetTime)
inline U32 postEvent(const char *objectName,SimEvent*evt, SimTime targetTime)
{
return postEvent(findObject(objectName), evt, targetTime);
}

View file

@ -39,7 +39,10 @@ SimConsoleEvent::SimConsoleEvent(S32 argc, ConsoleValueRef *argv, bool onObject)
mArgv[i].value = new ConsoleValue();
mArgv[i].value->type = ConsoleValue::TypeInternalString;
mArgv[i].value->init();
mArgv[i].value->setStringValue((const char*)argv[i]);
if (argv)
{
mArgv[i].value->setStringValue((const char*)argv[i]);
}
}
}
@ -92,10 +95,19 @@ void SimConsoleEvent::process(SimObject* object)
}
}
void SimConsoleEvent::populateArgs(ConsoleValueRef *argv)
{
for (U32 i=0; i<mArgc; i++)
{
argv[i].value = mArgv[i].value;
}
}
//-----------------------------------------------------------------------------
SimConsoleThreadExecCallback::SimConsoleThreadExecCallback() : retVal(NULL)
SimConsoleThreadExecCallback::SimConsoleThreadExecCallback()
{
retVal.value = NULL;
sem = new Semaphore(0);
}
@ -104,13 +116,13 @@ SimConsoleThreadExecCallback::~SimConsoleThreadExecCallback()
delete sem;
}
void SimConsoleThreadExecCallback::handleCallback(const char *ret)
void SimConsoleThreadExecCallback::handleCallback(ConsoleValueRef ret)
{
retVal = ret;
sem->release();
}
const char *SimConsoleThreadExecCallback::waitForResult()
ConsoleValueRef SimConsoleThreadExecCallback::waitForResult()
{
if(sem->acquire(true))
{
@ -129,7 +141,7 @@ SimConsoleThreadExecEvent::SimConsoleThreadExecEvent(S32 argc, ConsoleValueRef *
void SimConsoleThreadExecEvent::process(SimObject* object)
{
const char *retVal;
ConsoleValueRef retVal;
if(mOnObject)
retVal = Con::execute(object, mArgc, mArgv);
else

View file

@ -114,19 +114,22 @@ public:
~SimConsoleEvent();
virtual void process(SimObject *object);
/// Creates a reference to our internal args list in argv
void populateArgs(ConsoleValueRef *argv);
};
/// Used by Con::threadSafeExecute()
struct SimConsoleThreadExecCallback
{
Semaphore *sem;
const char *retVal;
ConsoleValueRef retVal;
SimConsoleThreadExecCallback();
~SimConsoleThreadExecCallback();
void handleCallback(const char *ret);
const char *waitForResult();
void handleCallback(ConsoleValueRef ret);
ConsoleValueRef waitForResult();
};
class SimConsoleThreadExecEvent : public SimConsoleEvent
@ -136,6 +139,7 @@ class SimConsoleThreadExecEvent : public SimConsoleEvent
public:
SimConsoleThreadExecEvent(S32 argc, ConsoleValueRef *argv, bool onObject, SimConsoleThreadExecCallback *callback);
SimConsoleThreadExecCallback& getCB() { return *cb; }
virtual void process(SimObject *object);
};

View file

@ -23,7 +23,8 @@
#include "platform/platform.h"
#include "console/simObjectList.h"
#include "console/console.h"
#include "console/simBase.h"
#include "console/engineAPI.h"
#include "console/sim.h"
#include "console/simObject.h"

View file

@ -31,12 +31,11 @@ void ConsoleValueStack::getArgcArgv(StringTableEntry name, U32 *argc, ConsoleVal
U32 argCount = getMin(mStackPos - startStack, (U32)MaxArgs - 1);
*in_argv = mArgv;
mArgv[0] = name;
mArgv[0].value = CSTK.pushStackString(name);
for(U32 i = 0; i < argCount; i++) {
ConsoleValueRef *ref = &mArgv[i+1];
ref->value = &mStack[startStack + i];
ref->stringStackValue = NULL;
}
argCount++;
@ -96,6 +95,36 @@ void ConsoleValueStack::pushValue(ConsoleValue &variable)
}
}
ConsoleValue* ConsoleValueStack::reserveValues(U32 count)
{
U32 startPos = mStackPos;
if (startPos+count >= ConsoleValueStack::MaxStackDepth) {
AssertFatal(false, "Console Value Stack is empty");
return NULL;
}
//Con::printf("[%i]CSTK reserveValues %i", mStackPos, count);
mStackPos += count;
return &mStack[startPos];
}
bool ConsoleValueStack::reserveValues(U32 count, ConsoleValueRef *outValues)
{
U32 startPos = mStackPos;
if (startPos+count >= ConsoleValueStack::MaxStackDepth) {
AssertFatal(false, "Console Value Stack is empty");
return false;
}
//Con::printf("[%i]CSTK reserveValues %i", mStackPos, count);
for (U32 i=0; i<count; i++)
{
outValues[i].value = &mStack[mStackPos+i];
}
mStackPos += count;
return true;
}
ConsoleValue *ConsoleValueStack::pushString(const char *value)
{
if (mStackPos == ConsoleValueStack::MaxStackDepth) {

View file

@ -127,6 +127,7 @@ struct StringStack
/// Return a temporary buffer we can use to return data.
char* getReturnBuffer(U32 size)
{
AssertFatal(Con::isMainThread(), "Manipulating return buffer from a secondary thread!");
validateArgBufferSize(size);
return mArgBuffer;
}
@ -136,6 +137,7 @@ struct StringStack
/// This updates the function offset.
char *getArgBuffer(U32 size)
{
AssertFatal(Con::isMainThread(), "Manipulating console arg buffer from a secondary thread!");
validateBufferSize(mStart + mFunctionOffset + size);
char *ret = mBuffer + mStart + mFunctionOffset;
mFunctionOffset += size;
@ -314,6 +316,8 @@ public:
void pushVar(ConsoleValue *variable);
void pushValue(ConsoleValue &value);
ConsoleValue* reserveValues(U32 numValues);
bool reserveValues(U32 numValues, ConsoleValueRef *values);
ConsoleValue* pop();
ConsoleValue *pushString(const char *value);
@ -338,4 +342,7 @@ public:
ConsoleValueRef mArgv[MaxArgs];
};
extern StringStack STR;
extern ConsoleValueStack CSTK;
#endif