diff options
Diffstat (limited to 'squirrel_3_0_1_stable/sqplus/SqPlus.cpp')
-rw-r--r-- | squirrel_3_0_1_stable/sqplus/SqPlus.cpp | 382 |
1 files changed, 382 insertions, 0 deletions
diff --git a/squirrel_3_0_1_stable/sqplus/SqPlus.cpp b/squirrel_3_0_1_stable/sqplus/SqPlus.cpp new file mode 100644 index 000000000..a2eaacb72 --- /dev/null +++ b/squirrel_3_0_1_stable/sqplus/SqPlus.cpp @@ -0,0 +1,382 @@ +#include "sqplus.h" +#include <stdio.h> + +#ifdef SQPLUS_SMARTPOINTER_OPT +#define SQPLUS_SMARTPOINTER_CPP_DECLARATION +#include "SqPlusSmartPointer.h" +#endif + +namespace SqPlus { + +static int getVarInfo(StackHandler & sa,VarRefPtr & vr) { + HSQOBJECT htable = sa.GetObjectHandle(1); + SquirrelObject table(htable); + const SQChar * el = sa.GetString(2); + ScriptStringVar256 varNameTag; + getVarNameTag(varNameTag,sizeof(varNameTag),el); + SQUserPointer data=0; + if (!table.RawGetUserData(varNameTag,&data)) { + return sa.ThrowError(_SC("getVarInfo: Could not retrieve UserData")); // Results in variable not being found error. + } + vr = (VarRefPtr)data; + return SQ_OK; +} // getVarInfo + +static int getInstanceVarInfo(StackHandler & sa,VarRefPtr & vr,SQUserPointer & data) { + HSQOBJECT ho = sa.GetObjectHandle(1); + SquirrelObject instance(ho); + const SQChar * el = sa.GetString(2); + ScriptStringVar256 varNameTag; + getVarNameTag(varNameTag,sizeof(varNameTag),el); + SQUserPointer ivrData=0; + if (!instance.RawGetUserData(varNameTag,&ivrData)) { + return sa.ThrowError(_SC("getInstanceVarInfo: Could not retrieve UserData")); // Results in variable not being found error. + } + vr = (VarRefPtr)ivrData; + + char * up; + if (!(vr->m_access & (VAR_ACCESS_STATIC|VAR_ACCESS_CONSTANT))) { + SQUserPointer typetag; + instance.GetTypeTag(&typetag); + +#if defined(SQ_USE_CLASS_INHERITANCE) + if (typetag != vr->instanceType) { + SquirrelObject typeTable = instance.GetValue(SQ_CLASS_OBJECT_TABLE_NAME); + up = (char *)typeTable.GetUserPointer(INT((size_t)vr->instanceType)); // <TODO> 64-bit compatible version. + if (!up) { + throw SquirrelError(_SC("Invalid Instance Type")); + } + } else { + up = (char *)instance.GetInstanceUP(0); + } // if + +#elif defined(SQ_USE_CLASS_INHERITANCE_SIMPLE) + ClassTypeBase *ctb = (ClassTypeBase*)vr->instanceType; + up = (char *)instance.GetInstanceUP(0); + // Walk base classes until type tag match, adjust for inheritence offset + while(ctb && typetag!=ctb) { + up = (char*)up - ctb->m_offset; + ctb = ctb->m_pbase; + } + if (!ctb) { + throw SquirrelError(_SC("Invalid Instance Type")); + } +#else + up = (char *)instance.GetInstanceUP(0); +#endif + +#ifdef SQPLUS_SMARTPOINTER_OPT +#define SQPLUS_SMARTPOINTER_INSTANCE_VARINFO +#include "SqPlusSmartPointer.h" +#endif + + up += (size_t)vr->offsetOrAddrOrConst; // Offset + } else { + up = (char *)vr->offsetOrAddrOrConst; // Address + } // if + data = up; + return SQ_OK; +} // getInstanceVarInfo + + +// If not static/global, message can (and will) disappear before arriving at catch (G++) +static ScriptStringVar256 g_msg_throw; + +static int setVar(StackHandler & sa,VarRef * vr,void * data) { + if (vr->m_access & (VAR_ACCESS_READ_ONLY|VAR_ACCESS_CONSTANT)) { + const SQChar * el = sa.GetString(2); + SCSNPRINTF(g_msg_throw.s,sizeof(g_msg_throw),_SC("setVar(): Cannot write to constant: %s"),el); + throw SquirrelError(g_msg_throw.s); + } // if + switch (vr->m_type) { + case TypeInfo<INT>::TypeID: { + INT * val = (INT *)data; // Address + if (val) { + INT v = sa.GetInt(3); + // Support for different int sizes + switch( vr->m_size ) { + case 1: v = (*(char*)val = (char)v); break; + case 2: v = (*(short*)val = (short)v); break; +#ifdef _SQ64 + case 4: v = (*(int*)val = (int)v); break; +#endif + default: *val = v; + } + return sa.Return(v); + } // if + break; + } // case + case TypeInfo<unsigned>::TypeID: { + unsigned * val = (unsigned *)data; // Address + if (val) { + *val = sa.GetInt(3); + return sa.Return(static_cast<INT>(*val)); + } // if + break; + } // case + case TypeInfo<FLOAT>::TypeID: { + FLOAT * val = (FLOAT *)data; // Address + if (val) { + *val = sa.GetFloat(3); + return sa.Return(*val); + } // if + break; + } // case + case TypeInfo<bool>::TypeID: { + bool * val = (bool *)data; // Address + if (val) { + *val = sa.GetBool(3) ? true : false; + return sa.Return(*val); + } // if + break; + } // case + case VAR_TYPE_INSTANCE: { + HSQUIRRELVM v = sa.GetVMPtr(); + SQUserPointer src = sa.GetInstanceUp(3,(SQUserPointer)vr->varType); // Effectively performs: ClassType<>::type() == ClassType<>(). + if (!src) { + throw SquirrelError(_SC("INSTANCE type assignment mismatch")); + } + vr->varType->vgetCopyFunc()(data,src); + return 0; + } + case TypeInfo<SQUserPointer>::TypeID: { + const SQChar * el = sa.GetString(2); + SCSNPRINTF(g_msg_throw.s,sizeof(g_msg_throw),_SC("setVar(): Cannot write to an SQUserPointer: %s"),el); + throw SquirrelError(g_msg_throw.s); + } // case + case TypeInfo<ScriptStringVarBase>::TypeID: { + ScriptStringVarBase * val = (ScriptStringVarBase *)data; // Address + if (val) { + const SQChar * strVal = sa.GetString(3); + if (strVal) { + *val = strVal; + return sa.Return(val->s); + } // if + } // if + break; + } // case +#if defined(SQPLUS_SUPPORT_STD_STRING) && !defined(SQUNICODE) + case TypeInfo<std::string>::TypeID: { + std::string *val = (std::string*)data; // Address + if (val) { + const SQChar *strVal = sa.GetString(3); + if (strVal) { + *val = strVal; + return sa.Return(val->c_str()); + } // if + } // if + break; + } // case +#endif + } // switch + return SQ_ERROR; +} // setVar + +static int getVar(StackHandler & sa,VarRef * vr,void * data) { + switch (vr->m_type) { + case TypeInfo<INT>::TypeID: { + if (!(vr->m_access & VAR_ACCESS_CONSTANT)) { + if (data) { + INT v; + // Support for different int sizes + switch( vr->m_size ){ + case 1: v = *(char*)data; break; + case 2: v = *(short*)data; break; +#ifdef _SQ64 + case 4: v = *(int*)data; break; +#endif + default: v = *(INT*)data; + } + return sa.Return(v); + } // if + } else { + INT * val = (INT *)&data; // Constant value + return sa.Return(*val); + } // if + break; + } // case + case TypeInfo<unsigned>::TypeID: { + if (!(vr->m_access & VAR_ACCESS_CONSTANT)) { + unsigned * val = (unsigned *)data; // Address + if (val){ + return sa.Return(static_cast<INT>(*val)); + } + } else { + unsigned * val = (unsigned *)&data; // Constant value + return sa.Return(static_cast<INT>(*val)); + } // if + break; + } // case + case TypeInfo<FLOAT>::TypeID: { + if (!(vr->m_access & VAR_ACCESS_CONSTANT)) { + FLOAT * val = (FLOAT *)data; // Address + if (val) { + return sa.Return(*val); + } // if + } else { + FLOAT * val = (FLOAT *)&data; // Constant value + return sa.Return(*val); + } // if + break; + } // case + case TypeInfo<bool>::TypeID: { + if (!(vr->m_access & VAR_ACCESS_CONSTANT)) { + bool * val = (bool *)data; // Address + if (val) { + return sa.Return(*val); + } // if + } else { + bool * val = (bool *)&data; // Constant value + return sa.Return(*val); + } // if + break; + } // case + case VAR_TYPE_INSTANCE: + if (!CreateNativeClassInstance(sa.GetVMPtr(),vr->varType->GetTypeName(),data,0)) { // data = address. Allocates memory. + SCSNPRINTF(g_msg_throw.s,sizeof(g_msg_throw),_SC("getVar(): Could not create instance: %s"),vr->varType->GetTypeName()); + throw SquirrelError(g_msg_throw.s); + } // if + return 1; + case TypeInfo<SQUserPointer>::TypeID: + return sa.Return(data); // The address of member variable, not the variable itself. + case TypeInfo<ScriptStringVarBase>::TypeID: { + if (!(vr->m_access & VAR_ACCESS_CONSTANT)) { + ScriptStringVarBase * val = (ScriptStringVarBase *)data; // Address + if (val) { + return sa.Return(val->s); + } // if + } else { + throw SquirrelError(_SC("getVar(): Invalid type+access: 'ScriptStringVarBase' with VAR_ACCESS_CONSTANT (use VAR_ACCESS_READ_ONLY instead)")); + } + break; + } // case + case TypeInfo<const SQChar *>::TypeID: { + if (!(vr->m_access & VAR_ACCESS_CONSTANT)) { + if( vr->m_access==VAR_ACCESS_READ_WRITE ) + throw SquirrelError(_SC("getVar(): Invalid type+access: 'const SQChar *' without VAR_ACCESS_CONSTANT")); + // It is OK to read from a SQChar* if requested + return sa.Return(*(const SQChar **)data); // Address + } else { + return sa.Return((const SQChar *)data); // Address + } + break; + } // case +#ifdef SQPLUS_SUPPORT_STD_STRING + case TypeInfo<std::string>::TypeID: { + if (!(vr->m_access & VAR_ACCESS_CONSTANT)) { + std::string *val = (std::string *)data; // Address + if (val) { + return sa.Return(val->c_str()); + } + } else { + throw SquirrelError(_SC("getVar(): Invalid type+access: 'std::string' with VAR_ACCESS_CONSTANT (use VAR_ACCESS_READ_ONLY instead)")); + } + break; + } // case +#endif + } // switch + return SQ_ERROR; +} // getVar + +// === Global Vars === + +int setVarFunc(HSQUIRRELVM v) { + SquirrelVM::Init(v); // For handling multi-VM setting right + StackHandler sa(v); + if (sa.GetType(1) == OT_TABLE) { + VarRefPtr vr; + int res = getVarInfo(sa,vr); + if (res != SQ_OK) return res; + return setVar(sa,vr,vr->offsetOrAddrOrConst); + } // if + return SQ_ERROR; +} // setVarFunc + +int getVarFunc(HSQUIRRELVM v) { + SquirrelVM::Init(v); // For handling multi-VM setting right + StackHandler sa(v); + if (sa.GetType(1) == OT_TABLE) { + VarRefPtr vr; + int res = getVarInfo(sa,vr); + if (res != SQ_OK) return res; + return getVar(sa,vr,vr->offsetOrAddrOrConst); + } // if + return SQ_ERROR; +} // getVarFunc + +// === Instance Vars === + +int setInstanceVarFunc(HSQUIRRELVM v) { + SquirrelVM::Init(v); // For handling multi-VM setting right + StackHandler sa(v); + if (sa.GetType(1) == OT_INSTANCE) { + VarRefPtr vr; + void * data; + int res = getInstanceVarInfo(sa,vr,data); + if (res != SQ_OK) return res; + return setVar(sa,vr,data); + } // if + return SQ_ERROR; +} // setInstanceVarFunc + +int getInstanceVarFunc(HSQUIRRELVM v) { + SquirrelVM::Init(v); // For handling multi-VM setting right + StackHandler sa(v); + if (sa.GetType(1) == OT_INSTANCE) { + VarRefPtr vr; + void * data; + int res = getInstanceVarInfo(sa,vr,data); + if (res != SQ_OK) return res; + return getVar(sa,vr,data); + } // if + return SQ_ERROR; +} // getInstanceVarFunc + +// === Classes === + +BOOL CreateClass(HSQUIRRELVM v,SquirrelObject & newClass,SQUserPointer classType,const SQChar * name,const SQChar * baseName) { + int n = 0; + int oldtop = sq_gettop(v); + sq_pushroottable(v); + sq_pushstring(v,name,-1); + if (baseName) { + sq_pushstring(v,baseName,-1); + if (SQ_FAILED(sq_get(v,-3))) { // Make sure the base exists if specified by baseName. + sq_settop(v,oldtop); + return FALSE; + } // if + } // if + if (SQ_FAILED(sq_newclass(v,baseName ? 1 : 0))) { // Will inherit from base class on stack from sq_get() above. + sq_settop(v,oldtop); + return FALSE; + } // if + newClass.AttachToStackObject(-1); + sq_settypetag(v,-1,classType); + sq_createslot(v,-3); + sq_pop(v,1); + return TRUE; +} // CreateClass + +SquirrelObject RegisterClassType(HSQUIRRELVM v,const SQChar * scriptClassName,SQUserPointer classType,SQFUNCTION constructor) { + SquirrelVM::Init(v); // For handling multi-VM setting right + int top = sq_gettop(v); + SquirrelObject newClass; + if (CreateClass(v,newClass,classType,scriptClassName)) { + SquirrelVM::CreateFunction(newClass,constructor,_SC("constructor")); + } // if + sq_settop(v,top); + return newClass; +} // RegisterClassType + + +/////////////////////////////////////////////////////////////////////////// +// GCC sometimes has problems with finding inline functions at link time +// (that also have a template definition). To solve the problem, +// non-inlines goes here. +#ifdef GCC_INLINE_WORKAROUND +# include "SqPlusFunctionCallImpl.h" +#endif // GCC_INLINE_WORKAROUND +/////////////////////////////////////////////////////////////////////////// + +} // namespace SqPlus + |