Merge remote-tracking branch 'jamesu/console_stack_fix2' into development

Conflicts:
	Engine/source/console/console.cpp
This commit is contained in:
Daniel Buckmaster 2015-03-01 20:33:29 +11:00
commit 6c92ab065e
48 changed files with 2979 additions and 449 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

@ -87,7 +87,7 @@ struct IterStackRecord
struct StringPos
{
/// The raw string data on the string stack.
const char* mString;
StringStackPtr mString;
/// Current parsing position.
U32 mIndex;
@ -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;
@ -286,6 +288,12 @@ inline void ExprEvalState::setStringVariable(const char *val)
currentVariable->setStringValue(val);
}
inline void ExprEvalState::setStringStackPtrVariable(StringStackPtr str)
{
AssertFatal(currentVariable != NULL, "Invalid evaluator state - trying to set null variable!");
currentVariable->setStringStackPtrValue(str);
}
inline void ExprEvalState::setCopyVariable()
{
if (copyVariable)
@ -432,6 +440,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 +451,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)
@ -489,15 +499,25 @@ ConsoleValueRef CodeBlock::exec(U32 ip, const char *functionName, Namespace *thi
ConsoleValueRef ref = argv[i+1];
if (argv[i+1].isString())
gEvalState.setStringVariable(argv[i+1]);
else if (argv[i+1].isInt())
switch(argv[i+1].getType())
{
case ConsoleValue::TypeInternalInt:
gEvalState.setIntVariable(argv[i+1]);
else if (argv[i+1].isFloat())
break;
case ConsoleValue::TypeInternalFloat:
gEvalState.setFloatVariable(argv[i+1]);
else
break;
case ConsoleValue::TypeInternalStringStackPtr:
gEvalState.setStringStackPtrVariable(argv[i+1].getStringStackPtrValue());
break;
case ConsoleValue::TypeInternalStackString:
case ConsoleValue::TypeInternalString:
default:
gEvalState.setStringVariable(argv[i+1]);
break;
}
}
ip = ip + (fnArgc * 2) + (2 + 6 + 1);
curFloatTable = functionFloats;
curStringTable = functionStrings;
@ -533,17 +553,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();
@ -590,7 +599,7 @@ ConsoleValueRef CodeBlock::exec(U32 ip, const char *functionName, Namespace *thi
Con::gCurrentRoot = this->modPath;
}
const char * val;
const char *retValue;
StringStackPtr retValue;
// note: anything returned is pushed to CSTK and will be invalidated on the next exec()
ConsoleValueRef returnValue;
@ -1144,7 +1153,7 @@ breakContinue:
// We're falling thru here on purpose.
case OP_RETURN:
retValue = STR.getStringValue();
retValue = STR.getStringValuePtr();
if( iterDepth > 0 )
{
@ -1156,13 +1165,13 @@ breakContinue:
}
STR.rewind();
STR.setStringValue( retValue ); // Not nice but works.
retValue = STR.getStringValue();
STR.setStringValue( StringStackPtrRef(retValue).getPtr(&STR) ); // Not nice but works.
retValue = STR.getStringValuePtr();
}
// Previously the return value was on the stack and would be returned using STR.getStringValue().
// Now though we need to wrap it in a ConsoleValueRef
returnValue.value = CSTK.pushStackString(retValue);
returnValue.value = CSTK.pushStringStackPtr(retValue);
goto execFinished;
@ -1847,7 +1856,7 @@ breakContinue:
// This will clear everything including returnValue
CSTK.popFrame();
STR.clearFunctionOffset();
//STR.clearFunctionOffset();
}
else
{
@ -1999,7 +2008,7 @@ breakContinue:
break;
case OP_PUSH:
STR.push();
CSTK.pushString(STR.getPreviousStringValue());
CSTK.pushStringStackPtr(STR.getPreviousStringValuePtr());
break;
case OP_PUSH_UINT:
CSTK.pushUINT(intStack[_UINT]);
@ -2080,7 +2089,7 @@ breakContinue:
if( iter.mIsStringIter )
{
iter.mData.mStr.mString = STR.getStringValue();
iter.mData.mStr.mString = STR.getStringValuePtr();
iter.mData.mStr.mIndex = 0;
}
else
@ -2118,7 +2127,7 @@ breakContinue:
if( iter.mIsStringIter )
{
const char* str = iter.mData.mStr.mString;
const char* str = StringStackPtrRef(iter.mData.mStr.mString).getPtr(&STR);
U32 startIndex = iter.mData.mStr.mIndex;
U32 endIndex = startIndex;
@ -2234,18 +2243,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);
@ -1167,26 +1173,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
@ -1200,17 +1214,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!
@ -1230,10 +1251,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);
@ -1242,10 +1261,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
@ -1253,7 +1270,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
@ -1261,17 +1278,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*)");
@ -1279,42 +1331,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(6, 6, 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(7, 7, 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(8, 8, 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(9, 9, 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(10, 10, params); }
#undef A
//------------------------------------------------------------------------------
bool isFunction(const char *fn)
@ -1577,10 +1601,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)
@ -1613,6 +1640,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];
@ -1637,10 +1707,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]);
}
}
@ -1651,8 +1724,11 @@ StringStackConsoleWrapper::~StringStackConsoleWrapper()
argv[i] = 0;
}
delete[] argv;
delete[] argvValue;
}
//------------------------------------------------------------------------------
S32 ConsoleValue::getSignedIntValue()
{
if(type <= TypeInternalString)
@ -1681,6 +1757,8 @@ const char *ConsoleValue::getStringValue()
{
if(type == TypeInternalString || type == TypeInternalStackString)
return sval;
else if (type == TypeInternalStringStackPtr)
return STR.mBuffer + (U32)sval;
if(type == TypeInternalFloat)
return Con::getData(TypeF32, &fval, 0);
else if(type == TypeInternalInt)
@ -1689,10 +1767,18 @@ const char *ConsoleValue::getStringValue()
return Con::getData(type, dataPtr, 0, enumTable);
}
StringStackPtr ConsoleValue::getStringStackPtr()
{
if (type == TypeInternalStringStackPtr)
return (U32)sval;
else
return (U32)-1;
}
bool ConsoleValue::getBoolValue()
{
if(type == TypeInternalString || type == TypeInternalStackString)
return dAtob(sval);
if(type == TypeInternalString || type == TypeInternalStackString || type == TypeInternalStringStackPtr)
return dAtob(getStringValue());
if(type == TypeInternalFloat)
return fval > 0;
else if(type == TypeInternalInt)
@ -1716,7 +1802,7 @@ void ConsoleValue::setIntValue(U32 val)
ival = val;
if(sval != typeValueEmpty)
{
if (type != TypeInternalStackString) dFree(sval);
if (type != TypeInternalStackString && type != TypeInternalStringStackPtr) dFree(sval);
sval = typeValueEmpty;
}
type = TypeInternalInt;
@ -1741,7 +1827,7 @@ void ConsoleValue::setFloatValue(F32 val)
ival = static_cast<U32>(val);
if(sval != typeValueEmpty)
{
if (type != TypeInternalStackString) dFree(sval);
if (type != TypeInternalStackString && type != TypeInternalStringStackPtr) dFree(sval);
sval = typeValueEmpty;
}
type = TypeInternalFloat;
@ -1753,70 +1839,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

@ -44,6 +44,8 @@ struct ConsoleFunctionHeader;
class EngineEnumTable;
typedef EngineEnumTable EnumTable;
typedef U32 StringStackPtr;
template< typename T > S32 TYPEID();
@ -121,8 +123,9 @@ public:
enum
{
TypeInternalInt = -4,
TypeInternalFloat = -3,
TypeInternalInt = -5,
TypeInternalFloat = -4,
TypeInternalStringStackPtr = -3,
TypeInternalStackString = -2,
TypeInternalString = -1,
};
@ -166,6 +169,7 @@ public:
S32 getSignedIntValue();
F32 getFloatValue();
const char *getStringValue();
StringStackPtr getStringStackPtr();
bool getBoolValue();
void setIntValue(U32 val);
@ -173,6 +177,7 @@ public:
void setFloatValue(F32 val);
void setStringValue(const char *value);
void setStackStringValue(const char *value);
void setStringStackPtrValue(StringStackPtr ptr);
void setBoolValue(bool val);
void init()
@ -181,12 +186,13 @@ public:
fval = 0;
sval = typeValueEmpty;
bufferLen = 0;
type = TypeInternalString;
}
void cleanup()
{
if (type <= TypeInternalString &&
sval != typeValueEmpty && type != TypeInternalStackString )
sval != typeValueEmpty && type != TypeInternalStackString && type != TypeInternalStringStackPtr)
dFree(sval);
sval = typeValueEmpty;
type = ConsoleValue::TypeInternalString;
@ -203,9 +209,8 @@ class ConsoleValueRef
{
public:
ConsoleValue *value;
const char *stringStackValue;
ConsoleValueRef() : value(0), stringStackValue(0) { ; }
ConsoleValueRef() : value(0) { ; }
~ConsoleValueRef() { ; }
ConsoleValueRef(const ConsoleValueRef &ref);
@ -216,8 +221,10 @@ 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();
StringStackPtr getStringStackPtrValue() { return value ? value->getStringStackPtr() : 0; }
inline U32 getIntValue() { return value ? value->getIntValue() : 0; }
inline S32 getSignedIntValue() { return value ? value->getSignedIntValue() : 0; }
@ -229,10 +236,13 @@ public:
inline operator U32() { return getIntValue(); }
inline operator S32() { return getSignedIntValue(); }
inline operator F32() { return getFloatValue(); }
inline bool isString() { return value ? value->type >= ConsoleValue::TypeInternalStackString : true; }
inline operator bool() { return getBoolValue(); }
inline bool isStringStackPtr() { return value ? value->type == ConsoleValue::TypeInternalStringStackPtr : false; }
inline bool isString() { return value ? value->type >= ConsoleValue::TypeInternalStringStackPtr : true; }
inline bool isInt() { return value ? value->type == ConsoleValue::TypeInternalInt : false; }
inline bool isFloat() { return value ? value->type == ConsoleValue::TypeInternalFloat : false; }
inline S32 getType() { return value ? value->type : -1; }
// Note: operators replace value
ConsoleValueRef& operator=(const ConsoleValueRef &other);
@ -281,6 +291,7 @@ public:
class StringStackConsoleWrapper
{
public:
ConsoleValue *argvValue;
ConsoleValueRef *argv;
int argc;
@ -753,23 +764,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 +780,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 +816,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 +855,48 @@ 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.template call<ConsoleValueRef>(); }
template<typename A, typename B> ConsoleValueRef executef(A a, B b) { _EngineConsoleExecCallbackHelper<A> callback( a ); return callback.template call<ConsoleValueRef>(b); }
template<typename A, typename B, typename C> ConsoleValueRef executef(A a, B b, C c) { _EngineConsoleExecCallbackHelper<A> callback( a ); return callback.template 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.template 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.template 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.template 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.template 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.template 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.template 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.template 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.template call<ConsoleValueRef>(b, c, d, e, f, g, h, i, j, k); }
template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J, typename K, typename L> ConsoleValueRef executef(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l) { _EngineConsoleExecCallbackHelper<A> callback( a ); return callback.template call<ConsoleValueRef>(b, c, d, e, f, g, h, i, j, k, l); }
/// }
};
extern void expandEscape(char *dest, const char *src);
extern bool collapseEscape(char *buf);
extern U32 HashPointer(StringTableEntry ptr);
@ -1103,6 +1113,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

@ -512,7 +512,7 @@ void ConsoleValue::setStringValue(const char * value)
*/
if (value == typeValueEmpty)
{
if (sval && sval != typeValueEmpty && type != TypeInternalStackString) dFree(sval);
if (sval && sval != typeValueEmpty && type != TypeInternalStackString && type != TypeInternalStringStackPtr) dFree(sval);
sval = typeValueEmpty;
bufferLen = 0;
fval = 0.f;
@ -541,7 +541,7 @@ void ConsoleValue::setStringValue(const char * value)
// may as well pad to the next cache line
U32 newLen = ((stringLen + 1) + 15) & ~15;
if(sval == typeValueEmpty || type == TypeInternalStackString)
if(sval == typeValueEmpty || type == TypeInternalStackString || type == TypeInternalStringStackPtr)
sval = (char *) dMalloc(newLen);
else if(newLen > bufferLen)
sval = (char *) dRealloc(sval, newLen);
@ -556,7 +556,7 @@ void ConsoleValue::setStringValue(const char * value)
}
void ConsoleValue::setStackStringValue(const char * value)
void ConsoleValue::setStackStringValue(const char *value)
{
if (value == NULL) value = typeValueEmpty;
@ -564,7 +564,7 @@ void ConsoleValue::setStackStringValue(const char * value)
{
if (value == typeValueEmpty)
{
if (sval && sval != typeValueEmpty && type != ConsoleValue::TypeInternalStackString) dFree(sval);
if (sval && sval != typeValueEmpty && type != ConsoleValue::TypeInternalStackString && type != ConsoleValue::TypeInternalStringStackPtr) dFree(sval);
sval = typeValueEmpty;
bufferLen = 0;
fval = 0.f;
@ -586,13 +586,42 @@ void ConsoleValue::setStackStringValue(const char * value)
}
type = TypeInternalStackString;
sval = (char*)value;
sval = (char*)value;
bufferLen = stringLen;
}
else
Con::setData(type, dataPtr, 0, 1, &value, enumTable);
}
void ConsoleValue::setStringStackPtrValue(StringStackPtr ptrValue)
{
if(type <= ConsoleValue::TypeInternalString)
{
const char *value = StringStackPtrRef(ptrValue).getPtr(&STR);
if (sval && sval != typeValueEmpty && type != ConsoleValue::TypeInternalStackString && type != TypeInternalStringStackPtr) dFree(sval);
U32 stringLen = dStrlen(value);
if(stringLen < 256)
{
fval = dAtof(value);
ival = dAtoi(value);
}
else
{
fval = 0.f;
ival = 0;
}
type = TypeInternalStringStackPtr;
sval = (char*)(value - STR.mBuffer);
bufferLen = stringLen;
}
else
{
const char *value = StringStackPtrRef(ptrValue).getPtr(&STR);
Con::setData(type, dataPtr, 0, 1, &value, enumTable);
}
}
S32 Dictionary::getIntVariable(StringTableEntry name, bool *entValid)
{
@ -651,7 +680,8 @@ Dictionary::Entry* Dictionary::addVariable( const char *name,
Entry *ent = add(StringTable->insert(name));
if ( ent->value.type <= ConsoleValue::TypeInternalString &&
ent->value.sval != typeValueEmpty && ent->value.type != ConsoleValue::TypeInternalStackString )
ent->value.sval != typeValueEmpty &&
ent->value.type != ConsoleValue::TypeInternalStackString && ent->value.type != ConsoleValue::TypeInternalStringStackPtr )
dFree(ent->value.sval);
ent->value.type = type;
@ -1338,14 +1368,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 +1390,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 +1398,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;
@ -367,6 +367,22 @@ public:
notify->trigger();
}
void setStringStackPtrValue(StringStackPtr newValue)
{
if( mIsConstant )
{
Con::errorf( "Cannot assign value to constant '%s'.", name );
return;
}
value.setStringStackPtrValue(newValue);
// Fire off the notification if we have one.
if ( notify )
notify->trigger();
}
void setStringValue(const char *newValue)
{
if( mIsConstant )
@ -495,6 +511,7 @@ public:
void setIntVariable(S32 val);
void setFloatVariable(F64 val);
void setStringVariable(const char *str);
void setStringStackPtrVariable(StringStackPtr str);
void setCopyVariable();
void pushFrame(StringTableEntry frameName, Namespace *ns);

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,24 @@ public:
~SimConsoleEvent();
virtual void process(SimObject *object);
/// Creates a reference to our internal args list in argv
void populateArgs(ConsoleValueRef *argv);
};
// NOTE: SimConsoleThreadExecCallback & SimConsoleThreadExecEvent moved to engineAPI.h
/// 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 +141,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++;
@ -91,11 +90,43 @@ void ConsoleValueStack::pushValue(ConsoleValue &variable)
mStack[mStackPos++].setIntValue((S32)variable.getIntValue());
case ConsoleValue::TypeInternalFloat:
mStack[mStackPos++].setFloatValue((F32)variable.getFloatValue());
case ConsoleValue::TypeInternalStringStackPtr:
mStack[mStackPos++].setStringStackPtrValue(variable.getStringStackPtr());
default:
mStack[mStackPos++].setStringValue(variable.getStringValue());
}
}
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) {
@ -122,6 +153,19 @@ ConsoleValue *ConsoleValueStack::pushStackString(const char *value)
return &mStack[mStackPos-1];
}
ConsoleValue *ConsoleValueStack::pushStringStackPtr(StringStackPtr value)
{
if (mStackPos == ConsoleValueStack::MaxStackDepth) {
AssertFatal(false, "Console Value Stack is empty");
return NULL;
}
//Con::printf("[%i]CSTK pushStringStackPtr %s", mStackPos, StringStackPtrRef(value).getPtr(&STR));
mStack[mStackPos++].setStringStackPtrValue(value);
return &mStack[mStackPos-1];
}
ConsoleValue *ConsoleValueStack::pushUINT(U32 value)
{
if (mStackPos == ConsoleValueStack::MaxStackDepth) {

View file

@ -35,8 +35,21 @@
#include "console/console.h"
#endif
typedef U32 StringStackPtr;
struct StringStack;
/// Helper class which stores a relative pointer in the StringStack buffer
class StringStackPtrRef
{
public:
StringStackPtrRef() : mOffset(0) {;}
StringStackPtrRef(StringStackPtr offset) : mOffset(offset) {;}
StringStackPtr mOffset;
/// Get pointer to string in stack stk
inline char *getPtr(StringStack *stk);
};
/// Core stack for interpreter operations.
///
@ -127,6 +140,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 +150,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;
@ -197,6 +212,16 @@ struct StringStack
return mBuffer + mStartOffsets[mStartStackSize-1];
}
inline StringStackPtr getStringValuePtr()
{
return (getStringValue() - mBuffer);
}
inline StringStackPtr getPreviousStringValuePtr()
{
return (getPreviousStringValue() - mBuffer);
}
/// Advance the start stack, placing a zero length string on the top.
///
/// @note You should use StringStack::push, not this, if you want to
@ -314,10 +339,13 @@ 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);
ConsoleValue *pushStackString(const char *value);
ConsoleValue *pushStringStackPtr(StringStackPtr ptr);
ConsoleValue *pushUINT(U32 value);
ConsoleValue *pushFLT(float value);
@ -338,4 +366,9 @@ public:
ConsoleValueRef mArgv[MaxArgs];
};
extern StringStack STR;
extern ConsoleValueStack CSTK;
inline char* StringStackPtrRef::getPtr(StringStack *stk) { return stk->mBuffer + mOffset; }
#endif

View file

@ -21,9 +21,11 @@
//-----------------------------------------------------------------------------
#include "platform/platform.h"
#include "console/simBase.h"
#include "console/engineAPI.h"
#include "console/telnetConsole.h"
#include "console/engineAPI.h"
#include "core/strings/stringFunctions.h"
#include "core/util/journal/process.h"
#include "core/module.h"

View file

@ -0,0 +1,287 @@
#ifdef TORQUE_TESTS_ENABLED
#include "testing/unitTesting.h"
#include "platform/platform.h"
#include "console/simBase.h"
#include "console/consoleTypes.h"
#include "console/simBase.h"
#include "console/engineAPI.h"
#include "math/mMath.h"
#include "console/stringStack.h"
TEST(Con, executef)
{
char buffer[128];
Con::evaluate("if (isObject(TestConExec)) {\r\nTestConExec.delete();\r\n}\r\nfunction testExecutef(%a,%b,%c,%d,%e,%f,%g,%h,%i,%j,%k){return %a SPC %b SPC %c SPC %d SPC %e SPC %f SPC %g SPC %h SPC %i SPC %j SPC %k;}\r\nfunction TestConExec::testThisFunction(%this,%a,%b,%c,%d,%e,%f,%g,%h,%i,%j){ return %a SPC %b SPC %c SPC %d SPC %e SPC %f SPC %g SPC %h SPC %i SPC %j;}\r\nnew ScriptObject(TestConExec);\r\n", false, "test");
SimObject *testObject = NULL;
Sim::findObject("TestConExec", testObject);
EXPECT_TRUE(testObject != NULL)
<< "TestConExec object should exist";
// Check basic calls with SimObject. We'll do this for every single possible call just to make sure.
const char *returnValue = NULL;
returnValue = Con::executef(testObject, "testThisFunction");
EXPECT_TRUE(dStricmp(returnValue, " ") == 0) <<
"All values should be printed in the correct order";
returnValue = Con::executef(testObject, "testThisFunction", "a");
EXPECT_TRUE(dStricmp(returnValue, "a ") == 0) <<
"All values should be printed in the correct order";
returnValue = Con::executef(testObject, "testThisFunction", "a", "b");
EXPECT_TRUE(dStricmp(returnValue, "a b ") == 0) <<
"All values should be printed in the correct order";
returnValue = Con::executef(testObject, "testThisFunction", "a", "b", "c");
EXPECT_TRUE(dStricmp(returnValue, "a b c ") == 0) <<
"All values should be printed in the correct order";
returnValue = Con::executef(testObject, "testThisFunction", "a", "b", "c", "d");
EXPECT_TRUE(dStricmp(returnValue, "a b c d ") == 0) <<
"All values should be printed in the correct order";
returnValue = Con::executef(testObject, "testThisFunction", "a", "b", "c", "d", "e");
EXPECT_TRUE(dStricmp(returnValue, "a b c d e ") == 0) <<
"All values should be printed in the correct order";
returnValue = Con::executef(testObject, "testThisFunction", "a", "b", "c", "d", "e", "f");
EXPECT_TRUE(dStricmp(returnValue, "a b c d e f ") == 0) <<
"All values should be printed in the correct order";
returnValue = Con::executef(testObject, "testThisFunction", "a", "b", "c", "d", "e", "f", "g");
EXPECT_TRUE(dStricmp(returnValue, "a b c d e f g ") == 0) <<
"All values should be printed in the correct order";
returnValue = Con::executef(testObject, "testThisFunction", "a", "b", "c", "d", "e", "f", "g", "h");
EXPECT_TRUE(dStricmp(returnValue, "a b c d e f g h ") == 0) <<
"All values should be printed in the correct order";
returnValue = Con::executef(testObject, "testThisFunction", "a", "b", "c", "d", "e", "f", "g", "h", "i");
EXPECT_TRUE(dStricmp(returnValue, "a b c d e f g h i ") == 0) <<
"All values should be printed in the correct order";
// Now test without the object
returnValue = Con::executef("testExecutef");
EXPECT_TRUE(dStricmp(returnValue, " ") == 0) <<
"All values should be printed in the correct order";
returnValue = Con::executef("testExecutef", "a");
EXPECT_TRUE(dStricmp(returnValue, "a ") == 0) <<
"All values should be printed in the correct order";
returnValue = Con::executef("testExecutef", "a", "b");
EXPECT_TRUE(dStricmp(returnValue, "a b ") == 0) <<
"All values should be printed in the correct order";
returnValue = Con::executef("testExecutef", "a", "b", "c");
EXPECT_TRUE(dStricmp(returnValue, "a b c ") == 0) <<
"All values should be printed in the correct order";
returnValue = Con::executef("testExecutef", "a", "b", "c", "d");
EXPECT_TRUE(dStricmp(returnValue, "a b c d ") == 0) <<
"All values should be printed in the correct order";
returnValue = Con::executef("testExecutef", "a", "b", "c", "d", "e");
EXPECT_TRUE(dStricmp(returnValue, "a b c d e ") == 0) <<
"All values should be printed in the correct order";
returnValue = Con::executef("testExecutef", "a", "b", "c", "d", "e", "f");
EXPECT_TRUE(dStricmp(returnValue, "a b c d e f ") == 0) <<
"All values should be printed in the correct order";
returnValue = Con::executef("testExecutef", "a", "b", "c", "d", "e", "f", "g");
EXPECT_TRUE(dStricmp(returnValue, "a b c d e f g ") == 0) <<
"All values should be printed in the correct order";
returnValue = Con::executef("testExecutef", "a", "b", "c", "d", "e", "f", "g", "h");
EXPECT_TRUE(dStricmp(returnValue, "a b c d e f g h ") == 0) <<
"All values should be printed in the correct order";
returnValue = Con::executef("testExecutef", "a", "b", "c", "d", "e", "f", "g", "h", "i");
EXPECT_TRUE(dStricmp(returnValue, "a b c d e f g h i ") == 0) <<
"All values should be printed in the correct order";
returnValue = Con::executef("testExecutef", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j");
EXPECT_TRUE(dStricmp(returnValue, "a b c d e f g h i j ") == 0) <<
"All values should be printed in the correct order";
// Test type conversions with and without SimObject...
// Integer
returnValue = Con::executef(testObject, "testThisFunction", 123);
EXPECT_TRUE(dStricmp(returnValue, "123 ") == 0) <<
"Integer should be converted";
returnValue = Con::executef("testExecutef", 123);
EXPECT_TRUE(dStricmp(returnValue, "123 ") == 0) <<
"Integer should be converted";
// Float
returnValue = Con::executef(testObject, "testThisFunction", (F32)123.4);
EXPECT_TRUE(dStricmp(returnValue, "123.4 ") == 0) <<
"Float should be converted";
returnValue = Con::executef("testExecutef", (F32)123.4);
EXPECT_TRUE(dStricmp(returnValue, "123.4 ") == 0) <<
"Float should be converted";
// SimObject
dSprintf(buffer, sizeof(buffer), "%i ", testObject->getId());
returnValue = Con::executef(testObject, "testThisFunction", testObject);
EXPECT_TRUE(dStricmp(returnValue, buffer) == 0) <<
"SimObject should be converted";
dSprintf(buffer, sizeof(buffer), "%i ", testObject->getId());
returnValue = Con::executef("testExecutef", testObject);
EXPECT_TRUE(dStricmp(returnValue, buffer) == 0) <<
"SimObject should be converted";
// Point3F
Point3F point(1,2,3);
returnValue = Con::executef(testObject, "testThisFunction", point);
EXPECT_TRUE(dStricmp(returnValue, "1 2 3 ") == 0) <<
"Point3F should be converted";
returnValue = Con::executef("testExecutef", point);
EXPECT_TRUE(dStricmp(returnValue, "1 2 3 ") == 0) <<
"Point3F should be converted";
// Finally test the function arg offset. This should be consistently 0 after each call
EXPECT_TRUE(STR.mFunctionOffset == 0) <<
"Function offset should be 0";
const char *floatArg = Con::getFloatArg(1.23);
EXPECT_TRUE(STR.mFunctionOffset > 0) <<
"Function offset should not be 0";
Con::executef("testExecutef", floatArg);
EXPECT_TRUE(STR.mFunctionOffset == 0) <<
"Function offset should be 0";
floatArg = Con::getFloatArg(1.23);
EXPECT_TRUE(STR.mFunctionOffset > 0) <<
"Function offset should not be 0";
Con::executef("testImaginaryFunction_", floatArg);
EXPECT_TRUE(STR.mFunctionOffset == 0) <<
"Function offset should be 0";
}
TEST(Con, execute)
{
Con::evaluate("if (isObject(TestConExec)) {\r\nTestConExec.delete();\r\n}\r\nfunction testScriptExecuteFunction(%a,%b) {return %a SPC %b;}\nfunction TestConExec::testScriptExecuteFunction(%this, %a,%b) {return %a SPC %b;}new ScriptObject(TestConExec);\r\n", false, "testExecute");
U32 startStackPos = CSTK.mStackPos;
U32 startStringStackPos = STR.mStart;
U32 startStackFrame = CSTK.mFrame;
SimObject *testObject = NULL;
Sim::findObject("TestConExec", testObject);
EXPECT_TRUE(testObject != NULL)
<< "TestConExec object should exist";
// const char* versions of execute should maintain stack
const char *argv[] = {"testScriptExecuteFunction", "1", "2"};
const char *argvObject[] = {"testScriptExecuteFunction", "", "1", "2"};
const char *returnValue = Con::execute(3, argv);
EXPECT_TRUE(dStricmp(returnValue, "1 2") == 0) <<
"execute should return 1 2";
EXPECT_TRUE(CSTK.mStackPos == startStackPos) <<
"execute should restore stack";
returnValue = Con::execute(testObject, 4, argvObject);
EXPECT_TRUE(dStricmp(returnValue, "1 2") == 0) <<
"execute should return 1 2";
EXPECT_TRUE(CSTK.mStackPos == startStackPos) <<
"execute should restore stack";
// ConsoleValueRef versions of execute should not restore stack
CSTK.pushFrame();
STR.pushFrame();
ConsoleValue valueArg[4];
ConsoleValueRef refArg[4];
ConsoleValue valueArgObject[4];
ConsoleValueRef refArgObject[4];
for (U32 i=0; i<4; i++)
{
refArg[i].value = &valueArg[i];
refArgObject[i].value = &valueArgObject[i];
valueArgObject[i].init();
valueArg[i].init();
}
refArg[0] = "testScriptExecuteFunction";
refArg[1] = "1";
refArg[2] = "2";
refArgObject[0] = "testScriptExecuteFunction";
refArgObject[2] = "1";
refArgObject[3] = "2";
returnValue = Con::execute(3, refArg);
EXPECT_TRUE(dStricmp(returnValue, "1 2") == 0) <<
"execute should return 1 2";
EXPECT_TRUE(CSTK.mStackPos == startStackPos) <<
"execute should restore stack";
CSTK.popFrame();
STR.popFrame();
CSTK.pushFrame();
STR.pushFrame();
returnValue = Con::execute(testObject, 4, refArgObject);
EXPECT_TRUE(dStricmp(returnValue, "1 2") == 0) <<
"execute should return 1 2";
EXPECT_TRUE(CSTK.mStackPos == startStackPos) <<
"execute should restore stack";
CSTK.popFrame();
STR.popFrame();
}
static U32 gConsoleStackFrame = 0;
ConsoleFunction(testConsoleStackFrame, S32, 1, 1, "")
{
gConsoleStackFrame = CSTK.mFrame;
return (U32)Con::executef("testScriptEvalFunction"); // execute a sub function which manipulates the stack
}
TEST(Con, evaluate)
{
U32 startStackPos = CSTK.mStackPos;
U32 startStringStackPos = STR.mStart;
S32 returnValue = Con::evaluate("function testScriptEvalFunction() {return \"1\"@\"2\"@\"3\";}\nreturn testConsoleStackFrame();", false, "testEvaluate");
U32 frame = CSTK.mFrame;
EXPECT_TRUE(returnValue == 123) <<
"Evaluate should return 123";
EXPECT_TRUE(gConsoleStackFrame == (frame+2)) <<
"Console stack frame inside function should be +2";
EXPECT_TRUE(CSTK.mFrame == frame) <<
"Console stack frame outside function should be the same as before";
EXPECT_TRUE(STR.mStart == startStringStackPos) <<
"Console string stack should not be changed";
EXPECT_TRUE(CSTK.mStackPos == startStackPos) <<
"Console stack should not be changed";
}
#endif

View file

@ -0,0 +1,150 @@
#ifdef TORQUE_TESTS_ENABLED
#include "testing/unitTesting.h"
#include "platform/platform.h"
#include "console/simBase.h"
#include "console/consoleTypes.h"
#include "console/simBase.h"
#include "console/engineAPI.h"
#include "math/mMath.h"
TEST(EngineAPI, EngineMarshallData)
{
// Reserve some values
ConsoleValue values[16];
ConsoleValueRef refValues[16];
for (U32 i=0; i<16; i++)
{
values[i].init();
refValues[i].value = &values[i];
}
// Basic string casting...
SimObject *foo = new SimObject();
foo->registerObject();
const char *value = EngineMarshallData(foo);
EXPECT_TRUE(dStricmp(value, foo->getIdString()) == 0)
<< "SimObject should be casted to its ID";
U32 unsignedNumber = 123;
S32 signedNumber = -123;
value = EngineMarshallData(unsignedNumber);
EXPECT_TRUE(dStricmp(value, "123") == 0)
<< "Integer should be converted to 123";
value = EngineMarshallData(signedNumber);
EXPECT_TRUE(dStricmp(value, "-123") == 0)
<< "Integer should be converted to -123";
bool boolValue = true;
value = EngineMarshallData(boolValue);
EXPECT_TRUE(dStricmp(value, "1") == 0)
<< "Bool should be converted to 1";
Point3F point(1,2,3);
value = EngineMarshallData(point);
EXPECT_TRUE(dStricmp(value, "1 2 3") == 0)
<< "Point3F should be converted to 1 2 3";
F32 floatValue = 1.23f;
value = EngineMarshallData(floatValue);
EXPECT_TRUE(dStricmp(value, "1.23") == 0)
<< "F32 should be converted to 1.23";
// Argv based casting
S32 argc = 0;
EngineMarshallData(foo, argc, refValues);
EngineMarshallData((const SimObject*)foo, argc, refValues);
EngineMarshallData(point, argc, refValues);
EngineMarshallData(unsignedNumber, argc, refValues);
EngineMarshallData(signedNumber, argc, refValues);
EngineMarshallData(boolValue, argc, refValues);
EngineMarshallData(floatValue, argc, refValues);
EXPECT_TRUE(argc == 7)
<< "7 args should have been set";
EXPECT_TRUE(values[0].type == ConsoleValue::TypeInternalInt && values[0].getSignedIntValue() == foo->getId())
<< "1st arg should be foo's id";
EXPECT_TRUE(values[1].type == ConsoleValue::TypeInternalInt && values[1].getSignedIntValue() == foo->getId())
<< "2nd arg should be foo's id";
EXPECT_TRUE(values[2].type == ConsoleValue::TypeInternalString && dStricmp(values[2].getStringValue(), "1 2 3") == 0)
<< "3rd arg should be 1 2 3";
EXPECT_TRUE(values[3].type == ConsoleValue::TypeInternalFloat && values[3].getSignedIntValue() == 123)
<< "4th arg should be 123";
EXPECT_TRUE(values[4].type == ConsoleValue::TypeInternalFloat && values[4].getSignedIntValue() == -123)
<< "5th arg should be -123";
EXPECT_TRUE(values[5].type == ConsoleValue::TypeInternalFloat && values[5].getBoolValue() == true)
<< "6th arg should be -123";
EXPECT_TRUE(values[6].type == ConsoleValue::TypeInternalFloat && mRound(values[6].getFloatValue() * 100) == 123)
<< "7th arg should be 1.23";
foo->deleteObject();
}
TEST(EngineAPI, EngineUnMarshallData)
{
SimObject *foo = new SimObject();
foo->registerObject();
SimObject *testFoo = EngineUnmarshallData<SimObject*>()(foo->getIdString());
EXPECT_TRUE(foo == testFoo)
<< "Unmarshalling foo's id should return foo";
testFoo = EngineUnmarshallData<SimObject*>()("ShouldNotExist_Really123");
EXPECT_TRUE(testFoo == NULL)
<< "Unmarshalling a bad object should return NULL";
foo->deleteObject();
}
TEST(EngineAPI, _EngineConsoleCallbackHelper)
{
Con::evaluate("if (isObject(TestConExec)) {\r\nTestConExec.delete();\r\n}\r\nfunction testExecutef(%a,%b,%c,%d,%e,%f,%g,%h,%i,%j,%k){return %a SPC %b SPC %c SPC %d SPC %e SPC %f SPC %g SPC %h SPC %i SPC %j SPC %k;}\r\nfunction TestConExec::testThisFunction(%this,%a,%b,%c,%d,%e,%f,%g,%h,%i,%j){ return %a SPC %b SPC %c SPC %d SPC %e SPC %f SPC %g SPC %h SPC %i SPC %j;}\r\nnew ScriptObject(TestConExec);\r\n", false, "test");
SimObject *testObject = NULL;
Sim::findObject("TestConExec", testObject);
_EngineConsoleCallbackHelper helper("testExecutef", NULL);
const char *returnValue = helper.call<const char*>("a", "b", "c");
EXPECT_TRUE(dStricmp(returnValue, "a b c ") == 0) <<
"All values should be printed in the correct order";
_EngineConsoleCallbackHelper objectHelper("testThisFunction", testObject);
returnValue = helper.call<const char*>("a", "b", "c");
EXPECT_TRUE(dStricmp(returnValue, "a b c ") == 0) <<
"All values should be printed in the correct order";
}
// NOTE: this is also indirectly tested by the executef tests
TEST(EngineAPI, _EngineConsoleExecCallbackHelper)
{
Con::evaluate("if (isObject(TestConExec)) {\r\nTestConExec.delete();\r\n}\r\nfunction testExecutef(%a,%b,%c,%d,%e,%f,%g,%h,%i,%j,%k){return %a SPC %b SPC %c SPC %d SPC %e SPC %f SPC %g SPC %h SPC %i SPC %j SPC %k;}\r\nfunction TestConExec::testThisFunction(%this,%a,%b,%c,%d,%e,%f,%g,%h,%i,%j){ return %a SPC %b SPC %c SPC %d SPC %e SPC %f SPC %g SPC %h SPC %i SPC %j;}\r\nnew ScriptObject(TestConExec);\r\n", false, "test");
SimObject *testObject = NULL;
Sim::findObject("TestConExec", testObject);
_EngineConsoleExecCallbackHelper<const char*> helper("testExecutef");
const char *returnValue = helper.call<const char*>("a", "b", "c");
EXPECT_TRUE(dStricmp(returnValue, "a b c ") == 0) <<
"All values should be printed in the correct order";
_EngineConsoleExecCallbackHelper<SimObject*> objectHelper(testObject);
returnValue = objectHelper.call<const char*>("testThisFunction", "a", "b", "c");
EXPECT_TRUE(dStricmp(returnValue, "a b c ") == 0) <<
"All values should be printed in the correct order";
}
#endif