Squirrel 2.x 对64位平台支持不是很好,转到3.0beta版却发现sqplus似乎不支持该版本,强行编译会出现若干问题。sqrat对3.0版支持较好,可能是本人的无知,不知如何对全局变量绑定,经过一上午的分析,从sqplus中分离出了变量绑定的代码,方便需要者使用。
使用方法:
//
c++源文件中的代码
// 包含头文件
#include " sqGlobalVariable.h "
// ...
// 绑定全局变量
// 使用方法:
// BindVariable(VM,变量地址,绑定名称,[读写权限])
int iVar = 777 ;
std:: string sVar = " This is a string " ;
char * s = " This is a const string " ;
float fVar = 1.0E-50f ;
double dVar = 1.0E-50 ;
BindVariable(v, & iVar,_SC( " iVar " )); // 绑定一个整形变量
BindVariable(v, & sVar, " sVar " ); // 绑定一个字符串变量
BindVariable(v, & s, " s " ,VAR_ACCESS_READ_WRITE); // 绑定一个只读字符串
BindVariable(v, & fVar, " fVar " ); // 绑定一个float类型变量
BindVariable(v, & dVar, " dVar " ); // 绑定一个double类型变量
// 脚本文件中代码
print(iVar + 1 ); // 访问整形全局变量
print(sVar); // 访问字符串
s = " aaa " ; // error: 无法更改只读字符串
// ..
// 包含头文件
#include " sqGlobalVariable.h "
// ...
// 绑定全局变量
// 使用方法:
// BindVariable(VM,变量地址,绑定名称,[读写权限])
int iVar = 777 ;
std:: string sVar = " This is a string " ;
char * s = " This is a const string " ;
float fVar = 1.0E-50f ;
double dVar = 1.0E-50 ;
BindVariable(v, & iVar,_SC( " iVar " )); // 绑定一个整形变量
BindVariable(v, & sVar, " sVar " ); // 绑定一个字符串变量
BindVariable(v, & s, " s " ,VAR_ACCESS_READ_WRITE); // 绑定一个只读字符串
BindVariable(v, & fVar, " fVar " ); // 绑定一个float类型变量
BindVariable(v, & dVar, " dVar " ); // 绑定一个double类型变量
// 脚本文件中代码
print(iVar + 1 ); // 访问整形全局变量
print(sVar); // 访问字符串
s = " aaa " ; // error: 无法更改只读字符串
// ..
源代码在这里:
sqGlobalVariable.h
#ifndef _SQGLOBALVARIABLE_H_
#define _SQGLOBALVARIABLE_H_
#include < squirrel.h >
#include < string >
#if defined(_MSC_VER) || defined(__BORLANDC__)
#include < tchar.h >
#ifndef UNICODE
#define SCSNPRINTF _snprintf
#define SCPUTS puts
#else
#define SCSNPRINTF _snwprintf
#define SCPUTS _putws
#endif
#else
#define _T(n) n
#define SCSNPRINTF snprintf
#include < stdio.h > // for snprintf
#define SCPUTS puts
#endif
typedef enum VarAccessType
{
VAR_ACCESS_READ_WRITE = 0 ,
VAR_ACCESS_READ_ONLY = 1 << 0 ,
VAR_ACCESS_CONSTANT = 1 << 1 ,
VAR_ACCESS_STATIC = 1 << 2
}VarAccessType;
typedef enum ScriptVarType
{
VAR_TYPE_NONE =- 1 ,
VAR_TYPE_CHAR,
VAR_TYPE_INT,
VAR_TYPE_FLOAT,
VAR_TYPE_DOUBLE,
VAR_TYPE_BOOL,
VAR_TYPE_CONST_STRING,
VAR_TYPE_STRING,
VAR_TYPE_USER_POINTER,
VAR_TYPE_INSTANCE
}ScriptVarType;
template < typename T >
struct TypeInfo {
const SQChar * typeName;
enum {TypeID = VAR_TYPE_NONE,Size = 0 };
};
// === Common Variable Types ===
template <>
struct TypeInfo < char > {
const SQChar * typeName;
TypeInfo() : typeName(_T( " char " )) {}
enum {TypeID = VAR_TYPE_CHAR,Size = sizeof ( char )};
operator ScriptVarType() { return ScriptVarType(TypeID); }
};
template <>
struct TypeInfo < int > {
const SQChar * typeName;
TypeInfo() : typeName(_T( " int " )) {}
enum {TypeID = VAR_TYPE_INT,Size = sizeof ( int )};
operator ScriptVarType() { return ScriptVarType(TypeID); }
};
template <>
struct TypeInfo < float > {
const SQChar * typeName;
TypeInfo() : typeName(_T( " float " )) {}
enum {TypeID = VAR_TYPE_FLOAT,Size = sizeof ( float )};
operator ScriptVarType() { return ScriptVarType(TypeID); }
};
template <>
struct TypeInfo < double > {
const SQChar * typeName;
TypeInfo() : typeName(_T( " double " )) {}
enum {TypeID = VAR_TYPE_DOUBLE,Size = sizeof ( double )};
operator ScriptVarType() { return ScriptVarType(TypeID); }
};
template <>
struct TypeInfo < bool > {
const SQChar * typeName;
TypeInfo() : typeName(_T( " bool " )) {}
enum {TypeID = VAR_TYPE_BOOL,Size = sizeof ( bool )};
operator ScriptVarType() { return ScriptVarType(TypeID); }
};
template <>
struct TypeInfo < std:: string > {
const SQChar * typeName;
TypeInfo() : typeName(_T( " string " )) {}
enum {TypeID = VAR_TYPE_STRING,Size = sizeof (std:: string )};
operator ScriptVarType() { return ScriptVarType(TypeID); }
};
template <>
struct TypeInfo < SQUserPointer > {
const SQChar * typeName;
TypeInfo() : typeName(_T( " SQUserPointer " )) {}
enum {TypeID = VAR_TYPE_USER_POINTER,Size = sizeof (SQUserPointer)};
operator ScriptVarType() { return ScriptVarType(TypeID); }
};
template <>
struct TypeInfo < const SQChar *> {
const SQChar * typeName;
TypeInfo() : typeName(_T( " const SQChar * " )) {}
enum {TypeID = VAR_TYPE_CONST_STRING,Size = sizeof ( const SQChar * )};
operator ScriptVarType() { return ScriptVarType(TypeID); }
};
// See VarRef and ClassType<> below: for instance assignment.
typedef void ( * CopyVarFunc)( void * dst, void * src);
// Internal use only.
inline void AttachToStackObject(HSQUIRRELVM vm, int idx,HSQOBJECT & so)
{
HSQOBJECT t;
sq_getstackobj(vm,idx, & t);
sq_addref(vm, & t);
sq_release(vm, & so);
so = t;
}
inline HSQOBJECT GetRootTable(HSQUIRRELVM vm)
{
static bool bInit = false ;
static HSQOBJECT root;
if ( ! bInit){
sq_resetobject( & root); // new object
AttachToStackObject(vm, - 1 ,root);
sq_pop(vm, 1 );
bInit = true ;
}
return root;
}
inline bool GetSlot(HSQUIRRELVM vm, const HSQOBJECT & so, const SQChar * name)
{
sq_pushobject(vm,so);
sq_pushstring(vm,name, - 1 );
return SQ_SUCCEEDED(sq_get(vm, - 2 )); // ? true : false;
}
inline HSQOBJECT GetValue(HSQUIRRELVM vm, const HSQOBJECT & so, const SQChar * key)
{
// SquirrelObject ret;
HSQOBJECT ret; sq_resetobject( & ret);
if (GetSlot(vm,so,key)) {
AttachToStackObject(vm, - 1 ,ret);
sq_pop(vm, 1 );
}
sq_pop(vm, 1 );
return ret;
}
bool SetValue(HSQUIRRELVM vm, const HSQOBJECT & so, const SQChar * key, const HSQOBJECT & val)
{
// _SETVALUE_STR_BEGIN
bool ret = false ;
SQInteger top = sq_gettop(vm);
sq_pushobject(vm,so);
sq_pushstring(vm,key, - 1 );
sq_pushobject(vm,val);
// _SETVALUE_STR_END
ret = SQ_SUCCEEDED(sq_rawset(vm, - 3 ));
sq_settop(vm,top);
return ret;
}
bool SetValue(HSQUIRRELVM vm, const HSQOBJECT & so,SQInteger key, const SQChar * s)
{
// _SETVALUE_INT_BEGIN
bool ret = false ;
SQInteger top = sq_gettop(vm);
sq_pushobject(vm,so);
sq_pushinteger(vm,key);
sq_pushstring(vm,s, - 1 );
// _SETVALUE_INT_END
ret = SQ_SUCCEEDED(sq_rawset(vm, - 3 ));
sq_settop(vm,top);
return ret;
}
inline HSQOBJECT CreateTable(HSQUIRRELVM vm)
{
// SquirrelObject ret;
HSQOBJECT ret; sq_resetobject( & ret);
sq_newtable(vm);
AttachToStackObject(vm, - 1 ,ret);
sq_pop(vm, 1 );
return ret;
}
#define SQ_PLUS_TYPE_TABLE _T("__SqTypes")
struct VarRef
{
// In this case 'offsetOrAddrOrConst' is simpler than using an anonymous union.
void * offsetOrAddrOrConst; // Instance member variable offset from 'this' pointer base (as size_t), or address if static variable (void *), or constant value.
ScriptVarType type; // Variable type (from enum above).
SQUserPointer instanceType; // Unique ID for the containing class instance (for instance vars only). When the var is an instance, its type is encoded in copyFunc.
CopyVarFunc copyFunc; // Function pointer to copy variables (for instance variables only).
short size; // Currently for debugging only (size of item when pointer to item is dereferenced). Could be used for variable max string buffer length.
short access; // VarAccessType.
const SQChar * typeName; // Type name string (to create instances by name).
VarRef()
:
offsetOrAddrOrConst( 0 ),
type(VAR_TYPE_NONE),
instanceType((SQUserPointer) - 1 ),
copyFunc( 0 ),
size( 0 ),
access(VAR_ACCESS_READ_WRITE)
{}
VarRef(
HSQUIRRELVM vm,
const HSQOBJECT & so,
void * _offsetOrAddrOrConst,
ScriptVarType _type,
SQUserPointer _instanceType,
CopyVarFunc _copyFunc,
int _size,
VarAccessType _access,
const SQChar * _typeName
)
:offsetOrAddrOrConst(_offsetOrAddrOrConst), type(_type), instanceType(_instanceType), copyFunc(_copyFunc), size(_size), access(_access), typeName(_typeName)
{
// SquirrelObject typeTable = SquirrelVM::GetRootTable().GetValue(SQ_PLUS_TYPE_TABLE);
HSQOBJECT typeTable = GetValue(vm,so,SQ_PLUS_TYPE_TABLE);
if (sq_isnull(typeTable)) {
// typeTable = SquirrelVM::CreateTable();
typeTable = CreateTable(vm);
// SquirrelObject root = SquirrelVM::GetRootTable();
HSQOBJECT root = GetRootTable(vm);
// root.SetValue(SQ_PLUS_TYPE_TABLE,typeTable);
SetValue(vm,root,SQ_PLUS_TYPE_TABLE,typeTable);
} // if
// typeTable.SetValue(INT((size_t)copyFunc),typeName);
SetValue(vm,typeTable,(SQInteger)copyFunc,typeName);
}
};
typedef VarRef * VarRefPtr;
struct StackHandler {
StackHandler(HSQUIRRELVM v) {
_top = sq_gettop(v);
this -> v = v;
}
char GetChar( int idx) {
SQInteger x = SQInteger( 0 );
if (idx > 0 && idx <= _top) {
sq_getinteger(v,idx, & x);
}
return char (x);
}
float GetFloat( int idx) {
SQFloat x = SQFloat( 0 );
if (idx > 0 && idx <= _top) {
sq_getfloat(v,idx, & x);
}
return float (x);
}
double GetDouble( int idx) {
SQFloat x = SQFloat( 0 );
if (idx > 0 && idx <= _top) {
sq_getfloat(v,idx, & x);
}
return double (x);
}
int GetInt( int idx) {
SQInteger x = 0 ;
if (idx > 0 && idx <= _top) {
sq_getinteger(v,idx, & x);
}
return int (x);
}
HSQOBJECT GetObjectHandle( int idx) {
HSQOBJECT x;
if (idx > 0 && idx <= _top) {
sq_resetobject( & x);
sq_getstackobj(v,idx, & x);
}
return x;
}
const SQChar * GetString( int idx)
{
const SQChar * x = NULL;
if (idx > 0 && idx <= _top) {
sq_getstring(v,idx, & x);
}
return x;
}
SQUserPointer GetUserPointer( int idx)
{
SQUserPointer x = 0 ;
if (idx > 0 && idx <= _top) {
sq_getuserpointer(v,idx, & x);
}
return x;
}
SQUserPointer GetInstanceUp( int idx,SQUserPointer tag)
{
SQUserPointer self;
if (SQ_FAILED(sq_getinstanceup(v,idx,(SQUserPointer * ) & self,tag)))
return NULL;
return self;
}
SQUserPointer GetUserData( int idx,SQUserPointer tag = 0 )
{
SQUserPointer otag;
SQUserPointer up;
if (idx > 0 && idx <= _top) {
if (SQ_SUCCEEDED(sq_getuserdata(v,idx, & up, & otag))) {
if (tag == otag)
return up;
}
}
return NULL;
}
bool GetBool( int idx)
{
SQBool ret;
if (idx > 0 && idx <= _top) {
if (SQ_SUCCEEDED(sq_getbool(v,idx, & ret)))
return ret != 0 ;
}
return false ;
}
int GetType( int idx)
{
if (idx > 0 && idx <= _top) {
return ( int )sq_gettype(v,idx);
}
return - 1 ;
}
int GetParamCount() {
return ( int )_top;
}
SQInteger Return( const SQChar * s)
{
sq_pushstring(v,s, - 1 );
return 1 ;
}
SQInteger Return( const std:: string & s)
{
sq_pushstring(v,s.c_str(), - 1 );
return 1 ;
}
SQInteger Return( float f)
{
sq_pushfloat(v,SQFloat(f));
return 1 ;
}
SQInteger Return( double d)
{
sq_pushfloat(v,SQFloat(d));
return 1 ;
}
SQInteger Return( int i)
{
sq_pushinteger(v,SQInteger(i));
return 1 ;
}
SQInteger Return( char c)
{
sq_pushinteger(v,SQInteger(c));
return 1 ;
}
SQInteger Return( bool b)
{
sq_pushbool(v,SQBool(b));
return 1 ;
}
SQInteger Return(SQUserPointer p) {
sq_pushuserpointer(v,p);
return 1 ;
}
SQInteger Return(HSQOBJECT & o)
{
sq_pushobject(v,o);
return 1 ;
}
SQInteger Return() { return 0 ; }
SQInteger ThrowError( const SQChar * error) {
return sq_throwerror(v,error);
}
HSQUIRRELVM GetVMPtr() { return v; }
private :
SQInteger _top;
HSQUIRRELVM v;
};
inline bool NewUserData(HSQUIRRELVM vm, const HSQOBJECT & so, const SQChar * key,unsigned size,SQUserPointer * typetag = 0 ) {
// _SETVALUE_STR_BEGIN
bool ret = false ;
SQInteger top = sq_gettop(vm);
sq_pushobject(vm,so); \
sq_pushstring(vm,key, - 1 );
sq_newuserdata(vm,size);
if (typetag) sq_settypetag(vm, - 1 ,typetag);
// _SETVALUE_STR_END
ret = SQ_SUCCEEDED(sq_rawset(vm, - 3 ));
sq_settop(vm,top);
return ret;
}
inline bool GetUserData(HSQUIRRELVM vm, const HSQOBJECT & so, const SQChar * key,SQUserPointer * data,SQUserPointer * typetag = 0 ) {
bool ret = false ;
if (GetSlot(vm,so,key)) {
sq_getuserdata(vm, - 1 ,data,typetag);
sq_pop(vm, 1 );
ret = true ;
} // if
sq_pop(vm, 1 );
return ret;
}
inline void getVarNameTag(SQChar * buff,unsigned maxSize, const SQChar * scriptName) {
// assert(maxSize > 3);
SQChar * d = buff;
d[ 0 ] = _SC( ' _ ' );
d[ 1 ] = _SC( ' v ' );
d = & d[ 2 ];
maxSize -= ( 2 + 1 ); // +1 = space for null.
unsigned pos = 0 ;
while (scriptName[pos] && pos < maxSize) {
d[pos] = scriptName[pos];
pos ++ ;
} // while
d[pos] = 0 ; // null terminate.
}
HSQOBJECT CreateFunction(HSQUIRRELVM vm,SQFUNCTION func, const SQChar * scriptFuncName, const SQChar * typeMask) {
sq_pushstring(vm,scriptFuncName, - 1 );
sq_newclosure(vm,func, 0 );
HSQOBJECT ret; sq_resetobject( & ret);
AttachToStackObject(vm, - 1 ,ret);
SQChar tm[ 64 ];
SQChar * ptm = tm;
int numParams = SQ_MATCHTYPEMASKSTRING;
if (typeMask) {
if (typeMask[ 0 ] == _SC( ' * ' )) {
ptm = 0 ; // Variable args: don't check parameters.
numParams = 0 ; // Clear SQ_MATCHTYPEMASKSTRING (does not mean match 0 params. See sq_setparamscheck()).
}
else {
if (SCSNPRINTF(tm, sizeof (tm),_SC( " t|y|x%s " ),typeMask) < 0 ) {
// throw _T("CreateFunction: typeMask string too long.");
sq_throwerror(vm,_SC( " CreateFunction: typeMask string too long. " ));
}
}
}
else { // <TODO> Need to check object type on stack: table, class, instance, etc.
SCSNPRINTF(tm, sizeof (tm),_SC( " %s " ),_SC( " t|y|x " )); // table, class, instance.
}
#if 0
sq_setparamscheck(_VM,numParams + 1 ,ptm); // Parameters are table+args (thus, the +1).
#else
if (ptm) {
sq_setparamscheck(vm,numParams,ptm); // Determine arg count from type string.
} // if
#endif
#ifdef _DEBUG
sq_setnativeclosurename(vm, - 1 ,scriptFuncName); // For debugging only.
#endif
sq_createslot(vm, - 3 ); // Create slot in table or class (assigning function to slot at scriptNameFunc).
return ret;
}
inline VarRefPtr createVarRef(HSQUIRRELVM vm, const HSQOBJECT & so, const SQChar * scriptVarName) {
VarRefPtr pvr = 0 ;
SQChar scriptVarTagName[ 256 ];
getVarNameTag(scriptVarTagName, sizeof (scriptVarTagName),scriptVarName);
if ( ! GetUserData(vm,so,scriptVarTagName,(SQUserPointer * ) & pvr)) {
NewUserData(vm,so,scriptVarTagName, sizeof ( * pvr));
if ( ! GetUserData(vm,so,scriptVarTagName,(SQUserPointer * ) & pvr)){
// throw _T("Could not create UserData.");
sq_throwerror(vm,_SC( " Could not create UserData. " ));
}
} // if
return pvr;
}
bool RawGetSlot(HSQUIRRELVM vm,HSQOBJECT & so, const SQChar * name)
{
sq_pushobject(vm,so);
sq_pushstring(vm,name, - 1 );
return SQ_SUCCEEDED(sq_rawget(vm, - 2 ));
}
bool RawGetUserData(HSQUIRRELVM vm,HSQOBJECT & so, const SQChar * key,SQUserPointer * data,SQUserPointer * typetag = 0 ) {
bool ret = RawGetSlot(vm,so,key);
if (ret) {
sq_getuserdata(vm, - 1 ,data,typetag);
sq_pop(vm, 1 );
}
sq_pop(vm, 1 );
return ret;
}
int getVarInfo(HSQUIRRELVM vm,StackHandler & sa,VarRefPtr & vr) {
HSQOBJECT htable = sa.GetObjectHandle( 1 );
// SquirrelObject table(htable);
sq_addref(vm, & htable);
#ifdef _DEBUG
SQObjectType type = (SQObjectType)sa.GetType( 2 );
#endif
const SQChar * el = sa.GetString( 2 );
// ScriptStringVar256 varNameTag;
SQChar varNameTag[ 256 ];
getVarNameTag(varNameTag, sizeof (varNameTag),el);
SQUserPointer data = 0 ;
if ( ! RawGetUserData(vm,htable,varNameTag, & data)) {
// return sa.ThrowError(_T("getVarInfo: Could not retrieve UserData")); // Results in variable not being found error.
sq_throwerror(vm,_SC( " getVarInfo: Could not retrieve UserData " ));
return SQ_ERROR;
}
vr = (VarRefPtr)data;
return SQ_OK;
}
bool CreateNativeClassInstance(HSQUIRRELVM v, const SQChar * classname,SQUserPointer ud,SQRELEASEHOOK hook)
{
SQInteger oldtop = sq_gettop(v);
sq_pushroottable(v);
sq_pushstring(v,classname, - 1 );
// Get the class (created with sq_newclass()).
if (SQ_FAILED(sq_rawget(v, - 2 ))){
sq_settop(v,oldtop);
return false ;
}
// sq_pushroottable(v);
if (SQ_FAILED(sq_createinstance(v, - 1 ))) {
sq_settop(v,oldtop);
return false ;
}
sq_remove(v, - 3 ); // removes the root table
sq_remove(v, - 2 ); // removes the class
if (SQ_FAILED(sq_setinstanceup(v, - 1 ,ud))) {
sq_settop(v,oldtop);
return false ;
}
sq_setreleasehook(v, - 1 ,hook);
return true ;
}
SQInteger setVar(StackHandler & sa,VarRef * vr, void * data) {
SQChar msg[ 256 ];
if (vr -> access & (VAR_ACCESS_READ_ONLY | VAR_ACCESS_CONSTANT)) {
const SQChar * el = sa.GetString( 2 );
SCSNPRINTF(msg, sizeof (msg),_SC( " setVar(): Cannot write to constant: %s " ),el);
// throw msg;
sq_throwerror(sa.GetVMPtr(),msg);
return SQ_ERROR;
} // if
switch (vr -> type) {
case TypeInfo < char > ::TypeID: {
char * val = ( char * )data; // Address
if (val) {
* val = sa.GetChar( 3 );
return sa.Return( * val);
} // if
break ;
} // case
case TypeInfo < int > ::TypeID: {
int * val = ( int * )data; // Address
if (val) {
* val = sa.GetInt( 3 );
return sa.Return( * 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 < double > ::TypeID: {
double * val = ( double * )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 );
return sa.Return( * val);
} // if
break ;
} // case
case TypeInfo < std:: string > ::TypeID: {
std:: string * val = (std:: string * )data; // Address
if (val) {
const SQChar * strVal = sa.GetString( 3 );
* val = strVal;
return sa.Return( * val);
} // if
break ;
} // case
case VAR_TYPE_INSTANCE: {
HSQUIRRELVM v = sa.GetVMPtr();
// vr->copyFunc is the LHS variable type: the RHS var's type is ClassType<>::type() (both point to ClassType<>::copy()).
// src will be null if the LHS and RHS types don't match.
SQUserPointer src = sa.GetInstanceUp( 3 ,(SQUserPointer)vr -> copyFunc); // Effectively performs: ClassType<>::type() == ClassType<>getCopyFunc().
if ( ! src){
// throw _T("INSTANCE type assignment mismatch");
sq_throwerror(sa.GetVMPtr(),_SC( " INSTANCE type assignment mismatch " ));
return SQ_ERROR;
}
vr -> copyFunc(data,src);
return 0 ;
}
case TypeInfo < SQUserPointer > ::TypeID: {
const SQChar * el = sa.GetString( 2 );
SCSNPRINTF(msg, sizeof (msg),_SC( " setVar(): Cannot write to an SQUserPointer: %s " ),el);
// throw msg;
sq_throwerror(sa.GetVMPtr(),msg);
return SQ_ERROR;
}
} // switch
return SQ_ERROR;
} // setVar
SQInteger getVar(StackHandler & sa,VarRef * vr, void * data) {
switch (vr -> type) {
case TypeInfo < char > ::TypeID: {
if ( ! (vr -> access & VAR_ACCESS_CONSTANT)) {
char * val = ( char * )data; // Address
if (val) {
return sa.Return( * val);
} // if
}
else {
char * val = ( char * ) & data; // Constant value
return sa.Return( * val);
} // if
break ;
} // case
case TypeInfo < int > ::TypeID: {
if ( ! (vr -> access & VAR_ACCESS_CONSTANT)) {
int * val = ( int * )data; // Address
if (val) {
return sa.Return( * val);
} // if
}
else {
int * val = ( int * ) & data; // Constant value
return sa.Return( * val);
} // if
break ;
} // case
case TypeInfo < float > ::TypeID: {
if ( ! (vr -> 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 < double > ::TypeID: {
if ( ! (vr -> access & VAR_ACCESS_CONSTANT)) {
double * val = ( double * )data; // Address
if (val) {
return sa.Return( * val);
} // if
}
else {
double * val = ( double * ) & data; // Constant value
return sa.Return( * val);
} // if
break ;
} // case
case TypeInfo < bool > ::TypeID: {
if ( ! (vr -> access & VAR_ACCESS_CONSTANT)) {
bool * val = ( bool * )data; // Address
if (val) return sa.Return( * val);
}
else {
bool * val = ( bool * ) & data; // Constant value
return sa.Return( * val);
} // if
break ;
} // case
case TypeInfo < std:: string > ::TypeID: {
if ( ! (vr -> access & VAR_ACCESS_CONSTANT)) {
std:: string * val = (std:: string * )data; // Address
if (val) {
return sa.Return( * val);
} // if
}
else {
std:: string * val = (std:: string * ) & data; // Constant value
return sa.Return( * val);
} // if
break ;
} // case
case VAR_TYPE_INSTANCE:
if ( ! CreateNativeClassInstance(sa.GetVMPtr(),vr -> typeName,data, 0 )) { // data = address. Allocates memory.
// ScriptStringVar256 msg;
SQChar msg[ 256 ] = _SC( " \0 " );
SCSNPRINTF(msg, sizeof (msg),_T( " getVar(): Could not create instance: %s " ),vr -> typeName);
throw msg;
} // if
return 1 ;
case TypeInfo < SQUserPointer > ::TypeID:
return sa.Return(data); // The address of member variable, not the variable itself.
case TypeInfo < const SQChar *> ::TypeID: {
if ( ! (vr -> access & VAR_ACCESS_CONSTANT)) {
// throw _T("getVar(): Invalid type+access: 'const SQChar *' without VAR_ACCESS_CONSTANT");
sq_throwerror(sa.GetVMPtr(),_SC( " getVar(): Invalid type+access: 'const SQChar *' without VAR_ACCESS_CONSTANT " ));
return SQ_ERROR;
}
else {
const SQChar * sptr = * (SQChar ** )data;
return sa.Return(sptr); // Address
} // if
break ;
} // case
} // switch
return SQ_ERROR;
} // getVar
SQInteger setVarFunc(HSQUIRRELVM v) {
StackHandler sa(v);
if (sa.GetType( 1 ) == OT_TABLE) {
VarRefPtr vr;
int res = getVarInfo(v,sa,vr);
if (res != SQ_OK) return res;
return setVar(sa,vr,vr -> offsetOrAddrOrConst);
}
return SQ_ERROR;
}
SQInteger getVarFunc(HSQUIRRELVM v) {
StackHandler sa(v);
if (sa.GetType( 1 ) == OT_TABLE) {
VarRefPtr vr;
int res = getVarInfo(v,sa,vr);
if (res != SQ_OK) return res;
return getVar(sa,vr,vr -> offsetOrAddrOrConst);
}
return SQ_ERROR;
}
inline void createTableSetGetHandlers(HSQUIRRELVM vm, const HSQOBJECT & so) {
// SquirrelObject delegate = so.GetDelegate();
HSQOBJECT delegate ; sq_resetobject( & delegate );
if (so._type == OT_TABLE || so._type == OT_USERDATA){
SQInteger top = sq_gettop(vm);
sq_pushobject(vm,so);
sq_getdelegate(vm, - 1 );
AttachToStackObject(vm, - 1 , delegate );
sq_settop(vm,top);
}
bool bExists = GetSlot(vm,so,_SC( " _set " )); sq_pop(vm, 1 );
if ( ! bExists) {
// delegate = SquirrelVM::CreateTable();
sq_newtable(vm);
AttachToStackObject(vm, - 1 , delegate );
sq_pop(vm, 1 );
// SquirrelVM::CreateFunction(delegate,(SQFUNCTION)setVarFunc,_T("_set"),_T("sn|b|s")); // String var name = number(int or float) or bool or string.
sq_pushobject(vm, delegate ); // ==>PushObject()
CreateFunction(vm,setVarFunc,_SC( " _set " ),_SC( " sn|b|s " ));
sq_pop(vm, 1 );
// SquirrelVM::CreateFunction(delegate,(SQFUNCTION)getVarFunc,_T("_get"),_T("s")); // String var name.
sq_pushobject(vm, delegate );
CreateFunction(vm,getVarFunc,_SC( " _get " ),_SC( " s " ));
sq_pop(vm, 1 );
// so.SetDelegate(delegate);
if ( delegate ._type == OT_TABLE ||
delegate ._type == OT_NULL) {
switch (so._type) {
case OT_USERDATA:
case OT_TABLE:
sq_pushobject(vm,so);
sq_pushobject(vm, delegate );
sq_setdelegate(vm, - 2 );
break ;
}
}
} // if
} // createTableSetGetHandlers
// === Class Type Helper class: returns a unique number for each class type ===
template < typename T >
struct ClassType_t {
static SQUserPointer type( void ) { return (SQUserPointer) & copy; }
static CopyVarFunc getCopyFunc( void ) { return (CopyVarFunc) & copy; }
static void copy(T * dst,T * src) {
* dst = * src;
} // copy
};
template < typename T >
void BindVariable(HSQUIRRELVM vm,T * var, const SQChar * scriptVarName,VarAccessType access = VAR_ACCESS_READ_WRITE) {
HSQOBJECT root = GetRootTable(vm);
VarRefPtr pvr = createVarRef(vm,root,scriptVarName);
* pvr = VarRef(vm,root,var,TypeInfo < T > (), 0 ,ClassType_t < T > ::getCopyFunc(), sizeof ( * var),access,TypeInfo < T > ().typeName);
createTableSetGetHandlers(vm,root);
} // BindVariable
// special for const string
template <>
void BindVariable < char *> (HSQUIRRELVM vm, char ** var, const SQChar * scriptVarName, VarAccessType /* access */ ) {
HSQOBJECT root = GetRootTable(vm);
VarRefPtr pvr = createVarRef(vm,root,scriptVarName);
* pvr = VarRef(vm,root,var,TypeInfo < const char *> (), 0 ,ClassType_t < const char *> ::getCopyFunc(), sizeof ( * var),VAR_ACCESS_CONSTANT,TypeInfo < const char *> ().typeName);
createTableSetGetHandlers(vm,root);
} // BindVariable
#endif // _SQGLOBALVARIABLE_H_
#define _SQGLOBALVARIABLE_H_
#include < squirrel.h >
#include < string >
#if defined(_MSC_VER) || defined(__BORLANDC__)
#include < tchar.h >
#ifndef UNICODE
#define SCSNPRINTF _snprintf
#define SCPUTS puts
#else
#define SCSNPRINTF _snwprintf
#define SCPUTS _putws
#endif
#else
#define _T(n) n
#define SCSNPRINTF snprintf
#include < stdio.h > // for snprintf
#define SCPUTS puts
#endif
typedef enum VarAccessType
{
VAR_ACCESS_READ_WRITE = 0 ,
VAR_ACCESS_READ_ONLY = 1 << 0 ,
VAR_ACCESS_CONSTANT = 1 << 1 ,
VAR_ACCESS_STATIC = 1 << 2
}VarAccessType;
typedef enum ScriptVarType
{
VAR_TYPE_NONE =- 1 ,
VAR_TYPE_CHAR,
VAR_TYPE_INT,
VAR_TYPE_FLOAT,
VAR_TYPE_DOUBLE,
VAR_TYPE_BOOL,
VAR_TYPE_CONST_STRING,
VAR_TYPE_STRING,
VAR_TYPE_USER_POINTER,
VAR_TYPE_INSTANCE
}ScriptVarType;
template < typename T >
struct TypeInfo {
const SQChar * typeName;
enum {TypeID = VAR_TYPE_NONE,Size = 0 };
};
// === Common Variable Types ===
template <>
struct TypeInfo < char > {
const SQChar * typeName;
TypeInfo() : typeName(_T( " char " )) {}
enum {TypeID = VAR_TYPE_CHAR,Size = sizeof ( char )};
operator ScriptVarType() { return ScriptVarType(TypeID); }
};
template <>
struct TypeInfo < int > {
const SQChar * typeName;
TypeInfo() : typeName(_T( " int " )) {}
enum {TypeID = VAR_TYPE_INT,Size = sizeof ( int )};
operator ScriptVarType() { return ScriptVarType(TypeID); }
};
template <>
struct TypeInfo < float > {
const SQChar * typeName;
TypeInfo() : typeName(_T( " float " )) {}
enum {TypeID = VAR_TYPE_FLOAT,Size = sizeof ( float )};
operator ScriptVarType() { return ScriptVarType(TypeID); }
};
template <>
struct TypeInfo < double > {
const SQChar * typeName;
TypeInfo() : typeName(_T( " double " )) {}
enum {TypeID = VAR_TYPE_DOUBLE,Size = sizeof ( double )};
operator ScriptVarType() { return ScriptVarType(TypeID); }
};
template <>
struct TypeInfo < bool > {
const SQChar * typeName;
TypeInfo() : typeName(_T( " bool " )) {}
enum {TypeID = VAR_TYPE_BOOL,Size = sizeof ( bool )};
operator ScriptVarType() { return ScriptVarType(TypeID); }
};
template <>
struct TypeInfo < std:: string > {
const SQChar * typeName;
TypeInfo() : typeName(_T( " string " )) {}
enum {TypeID = VAR_TYPE_STRING,Size = sizeof (std:: string )};
operator ScriptVarType() { return ScriptVarType(TypeID); }
};
template <>
struct TypeInfo < SQUserPointer > {
const SQChar * typeName;
TypeInfo() : typeName(_T( " SQUserPointer " )) {}
enum {TypeID = VAR_TYPE_USER_POINTER,Size = sizeof (SQUserPointer)};
operator ScriptVarType() { return ScriptVarType(TypeID); }
};
template <>
struct TypeInfo < const SQChar *> {
const SQChar * typeName;
TypeInfo() : typeName(_T( " const SQChar * " )) {}
enum {TypeID = VAR_TYPE_CONST_STRING,Size = sizeof ( const SQChar * )};
operator ScriptVarType() { return ScriptVarType(TypeID); }
};
// See VarRef and ClassType<> below: for instance assignment.
typedef void ( * CopyVarFunc)( void * dst, void * src);
// Internal use only.
inline void AttachToStackObject(HSQUIRRELVM vm, int idx,HSQOBJECT & so)
{
HSQOBJECT t;
sq_getstackobj(vm,idx, & t);
sq_addref(vm, & t);
sq_release(vm, & so);
so = t;
}
inline HSQOBJECT GetRootTable(HSQUIRRELVM vm)
{
static bool bInit = false ;
static HSQOBJECT root;
if ( ! bInit){
sq_resetobject( & root); // new object
AttachToStackObject(vm, - 1 ,root);
sq_pop(vm, 1 );
bInit = true ;
}
return root;
}
inline bool GetSlot(HSQUIRRELVM vm, const HSQOBJECT & so, const SQChar * name)
{
sq_pushobject(vm,so);
sq_pushstring(vm,name, - 1 );
return SQ_SUCCEEDED(sq_get(vm, - 2 )); // ? true : false;
}
inline HSQOBJECT GetValue(HSQUIRRELVM vm, const HSQOBJECT & so, const SQChar * key)
{
// SquirrelObject ret;
HSQOBJECT ret; sq_resetobject( & ret);
if (GetSlot(vm,so,key)) {
AttachToStackObject(vm, - 1 ,ret);
sq_pop(vm, 1 );
}
sq_pop(vm, 1 );
return ret;
}
bool SetValue(HSQUIRRELVM vm, const HSQOBJECT & so, const SQChar * key, const HSQOBJECT & val)
{
// _SETVALUE_STR_BEGIN
bool ret = false ;
SQInteger top = sq_gettop(vm);
sq_pushobject(vm,so);
sq_pushstring(vm,key, - 1 );
sq_pushobject(vm,val);
// _SETVALUE_STR_END
ret = SQ_SUCCEEDED(sq_rawset(vm, - 3 ));
sq_settop(vm,top);
return ret;
}
bool SetValue(HSQUIRRELVM vm, const HSQOBJECT & so,SQInteger key, const SQChar * s)
{
// _SETVALUE_INT_BEGIN
bool ret = false ;
SQInteger top = sq_gettop(vm);
sq_pushobject(vm,so);
sq_pushinteger(vm,key);
sq_pushstring(vm,s, - 1 );
// _SETVALUE_INT_END
ret = SQ_SUCCEEDED(sq_rawset(vm, - 3 ));
sq_settop(vm,top);
return ret;
}
inline HSQOBJECT CreateTable(HSQUIRRELVM vm)
{
// SquirrelObject ret;
HSQOBJECT ret; sq_resetobject( & ret);
sq_newtable(vm);
AttachToStackObject(vm, - 1 ,ret);
sq_pop(vm, 1 );
return ret;
}
#define SQ_PLUS_TYPE_TABLE _T("__SqTypes")
struct VarRef
{
// In this case 'offsetOrAddrOrConst' is simpler than using an anonymous union.
void * offsetOrAddrOrConst; // Instance member variable offset from 'this' pointer base (as size_t), or address if static variable (void *), or constant value.
ScriptVarType type; // Variable type (from enum above).
SQUserPointer instanceType; // Unique ID for the containing class instance (for instance vars only). When the var is an instance, its type is encoded in copyFunc.
CopyVarFunc copyFunc; // Function pointer to copy variables (for instance variables only).
short size; // Currently for debugging only (size of item when pointer to item is dereferenced). Could be used for variable max string buffer length.
short access; // VarAccessType.
const SQChar * typeName; // Type name string (to create instances by name).
VarRef()
:
offsetOrAddrOrConst( 0 ),
type(VAR_TYPE_NONE),
instanceType((SQUserPointer) - 1 ),
copyFunc( 0 ),
size( 0 ),
access(VAR_ACCESS_READ_WRITE)
{}
VarRef(
HSQUIRRELVM vm,
const HSQOBJECT & so,
void * _offsetOrAddrOrConst,
ScriptVarType _type,
SQUserPointer _instanceType,
CopyVarFunc _copyFunc,
int _size,
VarAccessType _access,
const SQChar * _typeName
)
:offsetOrAddrOrConst(_offsetOrAddrOrConst), type(_type), instanceType(_instanceType), copyFunc(_copyFunc), size(_size), access(_access), typeName(_typeName)
{
// SquirrelObject typeTable = SquirrelVM::GetRootTable().GetValue(SQ_PLUS_TYPE_TABLE);
HSQOBJECT typeTable = GetValue(vm,so,SQ_PLUS_TYPE_TABLE);
if (sq_isnull(typeTable)) {
// typeTable = SquirrelVM::CreateTable();
typeTable = CreateTable(vm);
// SquirrelObject root = SquirrelVM::GetRootTable();
HSQOBJECT root = GetRootTable(vm);
// root.SetValue(SQ_PLUS_TYPE_TABLE,typeTable);
SetValue(vm,root,SQ_PLUS_TYPE_TABLE,typeTable);
} // if
// typeTable.SetValue(INT((size_t)copyFunc),typeName);
SetValue(vm,typeTable,(SQInteger)copyFunc,typeName);
}
};
typedef VarRef * VarRefPtr;
struct StackHandler {
StackHandler(HSQUIRRELVM v) {
_top = sq_gettop(v);
this -> v = v;
}
char GetChar( int idx) {
SQInteger x = SQInteger( 0 );
if (idx > 0 && idx <= _top) {
sq_getinteger(v,idx, & x);
}
return char (x);
}
float GetFloat( int idx) {
SQFloat x = SQFloat( 0 );
if (idx > 0 && idx <= _top) {
sq_getfloat(v,idx, & x);
}
return float (x);
}
double GetDouble( int idx) {
SQFloat x = SQFloat( 0 );
if (idx > 0 && idx <= _top) {
sq_getfloat(v,idx, & x);
}
return double (x);
}
int GetInt( int idx) {
SQInteger x = 0 ;
if (idx > 0 && idx <= _top) {
sq_getinteger(v,idx, & x);
}
return int (x);
}
HSQOBJECT GetObjectHandle( int idx) {
HSQOBJECT x;
if (idx > 0 && idx <= _top) {
sq_resetobject( & x);
sq_getstackobj(v,idx, & x);
}
return x;
}
const SQChar * GetString( int idx)
{
const SQChar * x = NULL;
if (idx > 0 && idx <= _top) {
sq_getstring(v,idx, & x);
}
return x;
}
SQUserPointer GetUserPointer( int idx)
{
SQUserPointer x = 0 ;
if (idx > 0 && idx <= _top) {
sq_getuserpointer(v,idx, & x);
}
return x;
}
SQUserPointer GetInstanceUp( int idx,SQUserPointer tag)
{
SQUserPointer self;
if (SQ_FAILED(sq_getinstanceup(v,idx,(SQUserPointer * ) & self,tag)))
return NULL;
return self;
}
SQUserPointer GetUserData( int idx,SQUserPointer tag = 0 )
{
SQUserPointer otag;
SQUserPointer up;
if (idx > 0 && idx <= _top) {
if (SQ_SUCCEEDED(sq_getuserdata(v,idx, & up, & otag))) {
if (tag == otag)
return up;
}
}
return NULL;
}
bool GetBool( int idx)
{
SQBool ret;
if (idx > 0 && idx <= _top) {
if (SQ_SUCCEEDED(sq_getbool(v,idx, & ret)))
return ret != 0 ;
}
return false ;
}
int GetType( int idx)
{
if (idx > 0 && idx <= _top) {
return ( int )sq_gettype(v,idx);
}
return - 1 ;
}
int GetParamCount() {
return ( int )_top;
}
SQInteger Return( const SQChar * s)
{
sq_pushstring(v,s, - 1 );
return 1 ;
}
SQInteger Return( const std:: string & s)
{
sq_pushstring(v,s.c_str(), - 1 );
return 1 ;
}
SQInteger Return( float f)
{
sq_pushfloat(v,SQFloat(f));
return 1 ;
}
SQInteger Return( double d)
{
sq_pushfloat(v,SQFloat(d));
return 1 ;
}
SQInteger Return( int i)
{
sq_pushinteger(v,SQInteger(i));
return 1 ;
}
SQInteger Return( char c)
{
sq_pushinteger(v,SQInteger(c));
return 1 ;
}
SQInteger Return( bool b)
{
sq_pushbool(v,SQBool(b));
return 1 ;
}
SQInteger Return(SQUserPointer p) {
sq_pushuserpointer(v,p);
return 1 ;
}
SQInteger Return(HSQOBJECT & o)
{
sq_pushobject(v,o);
return 1 ;
}
SQInteger Return() { return 0 ; }
SQInteger ThrowError( const SQChar * error) {
return sq_throwerror(v,error);
}
HSQUIRRELVM GetVMPtr() { return v; }
private :
SQInteger _top;
HSQUIRRELVM v;
};
inline bool NewUserData(HSQUIRRELVM vm, const HSQOBJECT & so, const SQChar * key,unsigned size,SQUserPointer * typetag = 0 ) {
// _SETVALUE_STR_BEGIN
bool ret = false ;
SQInteger top = sq_gettop(vm);
sq_pushobject(vm,so); \
sq_pushstring(vm,key, - 1 );
sq_newuserdata(vm,size);
if (typetag) sq_settypetag(vm, - 1 ,typetag);
// _SETVALUE_STR_END
ret = SQ_SUCCEEDED(sq_rawset(vm, - 3 ));
sq_settop(vm,top);
return ret;
}
inline bool GetUserData(HSQUIRRELVM vm, const HSQOBJECT & so, const SQChar * key,SQUserPointer * data,SQUserPointer * typetag = 0 ) {
bool ret = false ;
if (GetSlot(vm,so,key)) {
sq_getuserdata(vm, - 1 ,data,typetag);
sq_pop(vm, 1 );
ret = true ;
} // if
sq_pop(vm, 1 );
return ret;
}
inline void getVarNameTag(SQChar * buff,unsigned maxSize, const SQChar * scriptName) {
// assert(maxSize > 3);
SQChar * d = buff;
d[ 0 ] = _SC( ' _ ' );
d[ 1 ] = _SC( ' v ' );
d = & d[ 2 ];
maxSize -= ( 2 + 1 ); // +1 = space for null.
unsigned pos = 0 ;
while (scriptName[pos] && pos < maxSize) {
d[pos] = scriptName[pos];
pos ++ ;
} // while
d[pos] = 0 ; // null terminate.
}
HSQOBJECT CreateFunction(HSQUIRRELVM vm,SQFUNCTION func, const SQChar * scriptFuncName, const SQChar * typeMask) {
sq_pushstring(vm,scriptFuncName, - 1 );
sq_newclosure(vm,func, 0 );
HSQOBJECT ret; sq_resetobject( & ret);
AttachToStackObject(vm, - 1 ,ret);
SQChar tm[ 64 ];
SQChar * ptm = tm;
int numParams = SQ_MATCHTYPEMASKSTRING;
if (typeMask) {
if (typeMask[ 0 ] == _SC( ' * ' )) {
ptm = 0 ; // Variable args: don't check parameters.
numParams = 0 ; // Clear SQ_MATCHTYPEMASKSTRING (does not mean match 0 params. See sq_setparamscheck()).
}
else {
if (SCSNPRINTF(tm, sizeof (tm),_SC( " t|y|x%s " ),typeMask) < 0 ) {
// throw _T("CreateFunction: typeMask string too long.");
sq_throwerror(vm,_SC( " CreateFunction: typeMask string too long. " ));
}
}
}
else { // <TODO> Need to check object type on stack: table, class, instance, etc.
SCSNPRINTF(tm, sizeof (tm),_SC( " %s " ),_SC( " t|y|x " )); // table, class, instance.
}
#if 0
sq_setparamscheck(_VM,numParams + 1 ,ptm); // Parameters are table+args (thus, the +1).
#else
if (ptm) {
sq_setparamscheck(vm,numParams,ptm); // Determine arg count from type string.
} // if
#endif
#ifdef _DEBUG
sq_setnativeclosurename(vm, - 1 ,scriptFuncName); // For debugging only.
#endif
sq_createslot(vm, - 3 ); // Create slot in table or class (assigning function to slot at scriptNameFunc).
return ret;
}
inline VarRefPtr createVarRef(HSQUIRRELVM vm, const HSQOBJECT & so, const SQChar * scriptVarName) {
VarRefPtr pvr = 0 ;
SQChar scriptVarTagName[ 256 ];
getVarNameTag(scriptVarTagName, sizeof (scriptVarTagName),scriptVarName);
if ( ! GetUserData(vm,so,scriptVarTagName,(SQUserPointer * ) & pvr)) {
NewUserData(vm,so,scriptVarTagName, sizeof ( * pvr));
if ( ! GetUserData(vm,so,scriptVarTagName,(SQUserPointer * ) & pvr)){
// throw _T("Could not create UserData.");
sq_throwerror(vm,_SC( " Could not create UserData. " ));
}
} // if
return pvr;
}
bool RawGetSlot(HSQUIRRELVM vm,HSQOBJECT & so, const SQChar * name)
{
sq_pushobject(vm,so);
sq_pushstring(vm,name, - 1 );
return SQ_SUCCEEDED(sq_rawget(vm, - 2 ));
}
bool RawGetUserData(HSQUIRRELVM vm,HSQOBJECT & so, const SQChar * key,SQUserPointer * data,SQUserPointer * typetag = 0 ) {
bool ret = RawGetSlot(vm,so,key);
if (ret) {
sq_getuserdata(vm, - 1 ,data,typetag);
sq_pop(vm, 1 );
}
sq_pop(vm, 1 );
return ret;
}
int getVarInfo(HSQUIRRELVM vm,StackHandler & sa,VarRefPtr & vr) {
HSQOBJECT htable = sa.GetObjectHandle( 1 );
// SquirrelObject table(htable);
sq_addref(vm, & htable);
#ifdef _DEBUG
SQObjectType type = (SQObjectType)sa.GetType( 2 );
#endif
const SQChar * el = sa.GetString( 2 );
// ScriptStringVar256 varNameTag;
SQChar varNameTag[ 256 ];
getVarNameTag(varNameTag, sizeof (varNameTag),el);
SQUserPointer data = 0 ;
if ( ! RawGetUserData(vm,htable,varNameTag, & data)) {
// return sa.ThrowError(_T("getVarInfo: Could not retrieve UserData")); // Results in variable not being found error.
sq_throwerror(vm,_SC( " getVarInfo: Could not retrieve UserData " ));
return SQ_ERROR;
}
vr = (VarRefPtr)data;
return SQ_OK;
}
bool CreateNativeClassInstance(HSQUIRRELVM v, const SQChar * classname,SQUserPointer ud,SQRELEASEHOOK hook)
{
SQInteger oldtop = sq_gettop(v);
sq_pushroottable(v);
sq_pushstring(v,classname, - 1 );
// Get the class (created with sq_newclass()).
if (SQ_FAILED(sq_rawget(v, - 2 ))){
sq_settop(v,oldtop);
return false ;
}
// sq_pushroottable(v);
if (SQ_FAILED(sq_createinstance(v, - 1 ))) {
sq_settop(v,oldtop);
return false ;
}
sq_remove(v, - 3 ); // removes the root table
sq_remove(v, - 2 ); // removes the class
if (SQ_FAILED(sq_setinstanceup(v, - 1 ,ud))) {
sq_settop(v,oldtop);
return false ;
}
sq_setreleasehook(v, - 1 ,hook);
return true ;
}
SQInteger setVar(StackHandler & sa,VarRef * vr, void * data) {
SQChar msg[ 256 ];
if (vr -> access & (VAR_ACCESS_READ_ONLY | VAR_ACCESS_CONSTANT)) {
const SQChar * el = sa.GetString( 2 );
SCSNPRINTF(msg, sizeof (msg),_SC( " setVar(): Cannot write to constant: %s " ),el);
// throw msg;
sq_throwerror(sa.GetVMPtr(),msg);
return SQ_ERROR;
} // if
switch (vr -> type) {
case TypeInfo < char > ::TypeID: {
char * val = ( char * )data; // Address
if (val) {
* val = sa.GetChar( 3 );
return sa.Return( * val);
} // if
break ;
} // case
case TypeInfo < int > ::TypeID: {
int * val = ( int * )data; // Address
if (val) {
* val = sa.GetInt( 3 );
return sa.Return( * 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 < double > ::TypeID: {
double * val = ( double * )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 );
return sa.Return( * val);
} // if
break ;
} // case
case TypeInfo < std:: string > ::TypeID: {
std:: string * val = (std:: string * )data; // Address
if (val) {
const SQChar * strVal = sa.GetString( 3 );
* val = strVal;
return sa.Return( * val);
} // if
break ;
} // case
case VAR_TYPE_INSTANCE: {
HSQUIRRELVM v = sa.GetVMPtr();
// vr->copyFunc is the LHS variable type: the RHS var's type is ClassType<>::type() (both point to ClassType<>::copy()).
// src will be null if the LHS and RHS types don't match.
SQUserPointer src = sa.GetInstanceUp( 3 ,(SQUserPointer)vr -> copyFunc); // Effectively performs: ClassType<>::type() == ClassType<>getCopyFunc().
if ( ! src){
// throw _T("INSTANCE type assignment mismatch");
sq_throwerror(sa.GetVMPtr(),_SC( " INSTANCE type assignment mismatch " ));
return SQ_ERROR;
}
vr -> copyFunc(data,src);
return 0 ;
}
case TypeInfo < SQUserPointer > ::TypeID: {
const SQChar * el = sa.GetString( 2 );
SCSNPRINTF(msg, sizeof (msg),_SC( " setVar(): Cannot write to an SQUserPointer: %s " ),el);
// throw msg;
sq_throwerror(sa.GetVMPtr(),msg);
return SQ_ERROR;
}
} // switch
return SQ_ERROR;
} // setVar
SQInteger getVar(StackHandler & sa,VarRef * vr, void * data) {
switch (vr -> type) {
case TypeInfo < char > ::TypeID: {
if ( ! (vr -> access & VAR_ACCESS_CONSTANT)) {
char * val = ( char * )data; // Address
if (val) {
return sa.Return( * val);
} // if
}
else {
char * val = ( char * ) & data; // Constant value
return sa.Return( * val);
} // if
break ;
} // case
case TypeInfo < int > ::TypeID: {
if ( ! (vr -> access & VAR_ACCESS_CONSTANT)) {
int * val = ( int * )data; // Address
if (val) {
return sa.Return( * val);
} // if
}
else {
int * val = ( int * ) & data; // Constant value
return sa.Return( * val);
} // if
break ;
} // case
case TypeInfo < float > ::TypeID: {
if ( ! (vr -> 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 < double > ::TypeID: {
if ( ! (vr -> access & VAR_ACCESS_CONSTANT)) {
double * val = ( double * )data; // Address
if (val) {
return sa.Return( * val);
} // if
}
else {
double * val = ( double * ) & data; // Constant value
return sa.Return( * val);
} // if
break ;
} // case
case TypeInfo < bool > ::TypeID: {
if ( ! (vr -> access & VAR_ACCESS_CONSTANT)) {
bool * val = ( bool * )data; // Address
if (val) return sa.Return( * val);
}
else {
bool * val = ( bool * ) & data; // Constant value
return sa.Return( * val);
} // if
break ;
} // case
case TypeInfo < std:: string > ::TypeID: {
if ( ! (vr -> access & VAR_ACCESS_CONSTANT)) {
std:: string * val = (std:: string * )data; // Address
if (val) {
return sa.Return( * val);
} // if
}
else {
std:: string * val = (std:: string * ) & data; // Constant value
return sa.Return( * val);
} // if
break ;
} // case
case VAR_TYPE_INSTANCE:
if ( ! CreateNativeClassInstance(sa.GetVMPtr(),vr -> typeName,data, 0 )) { // data = address. Allocates memory.
// ScriptStringVar256 msg;
SQChar msg[ 256 ] = _SC( " \0 " );
SCSNPRINTF(msg, sizeof (msg),_T( " getVar(): Could not create instance: %s " ),vr -> typeName);
throw msg;
} // if
return 1 ;
case TypeInfo < SQUserPointer > ::TypeID:
return sa.Return(data); // The address of member variable, not the variable itself.
case TypeInfo < const SQChar *> ::TypeID: {
if ( ! (vr -> access & VAR_ACCESS_CONSTANT)) {
// throw _T("getVar(): Invalid type+access: 'const SQChar *' without VAR_ACCESS_CONSTANT");
sq_throwerror(sa.GetVMPtr(),_SC( " getVar(): Invalid type+access: 'const SQChar *' without VAR_ACCESS_CONSTANT " ));
return SQ_ERROR;
}
else {
const SQChar * sptr = * (SQChar ** )data;
return sa.Return(sptr); // Address
} // if
break ;
} // case
} // switch
return SQ_ERROR;
} // getVar
SQInteger setVarFunc(HSQUIRRELVM v) {
StackHandler sa(v);
if (sa.GetType( 1 ) == OT_TABLE) {
VarRefPtr vr;
int res = getVarInfo(v,sa,vr);
if (res != SQ_OK) return res;
return setVar(sa,vr,vr -> offsetOrAddrOrConst);
}
return SQ_ERROR;
}
SQInteger getVarFunc(HSQUIRRELVM v) {
StackHandler sa(v);
if (sa.GetType( 1 ) == OT_TABLE) {
VarRefPtr vr;
int res = getVarInfo(v,sa,vr);
if (res != SQ_OK) return res;
return getVar(sa,vr,vr -> offsetOrAddrOrConst);
}
return SQ_ERROR;
}
inline void createTableSetGetHandlers(HSQUIRRELVM vm, const HSQOBJECT & so) {
// SquirrelObject delegate = so.GetDelegate();
HSQOBJECT delegate ; sq_resetobject( & delegate );
if (so._type == OT_TABLE || so._type == OT_USERDATA){
SQInteger top = sq_gettop(vm);
sq_pushobject(vm,so);
sq_getdelegate(vm, - 1 );
AttachToStackObject(vm, - 1 , delegate );
sq_settop(vm,top);
}
bool bExists = GetSlot(vm,so,_SC( " _set " )); sq_pop(vm, 1 );
if ( ! bExists) {
// delegate = SquirrelVM::CreateTable();
sq_newtable(vm);
AttachToStackObject(vm, - 1 , delegate );
sq_pop(vm, 1 );
// SquirrelVM::CreateFunction(delegate,(SQFUNCTION)setVarFunc,_T("_set"),_T("sn|b|s")); // String var name = number(int or float) or bool or string.
sq_pushobject(vm, delegate ); // ==>PushObject()
CreateFunction(vm,setVarFunc,_SC( " _set " ),_SC( " sn|b|s " ));
sq_pop(vm, 1 );
// SquirrelVM::CreateFunction(delegate,(SQFUNCTION)getVarFunc,_T("_get"),_T("s")); // String var name.
sq_pushobject(vm, delegate );
CreateFunction(vm,getVarFunc,_SC( " _get " ),_SC( " s " ));
sq_pop(vm, 1 );
// so.SetDelegate(delegate);
if ( delegate ._type == OT_TABLE ||
delegate ._type == OT_NULL) {
switch (so._type) {
case OT_USERDATA:
case OT_TABLE:
sq_pushobject(vm,so);
sq_pushobject(vm, delegate );
sq_setdelegate(vm, - 2 );
break ;
}
}
} // if
} // createTableSetGetHandlers
// === Class Type Helper class: returns a unique number for each class type ===
template < typename T >
struct ClassType_t {
static SQUserPointer type( void ) { return (SQUserPointer) & copy; }
static CopyVarFunc getCopyFunc( void ) { return (CopyVarFunc) & copy; }
static void copy(T * dst,T * src) {
* dst = * src;
} // copy
};
template < typename T >
void BindVariable(HSQUIRRELVM vm,T * var, const SQChar * scriptVarName,VarAccessType access = VAR_ACCESS_READ_WRITE) {
HSQOBJECT root = GetRootTable(vm);
VarRefPtr pvr = createVarRef(vm,root,scriptVarName);
* pvr = VarRef(vm,root,var,TypeInfo < T > (), 0 ,ClassType_t < T > ::getCopyFunc(), sizeof ( * var),access,TypeInfo < T > ().typeName);
createTableSetGetHandlers(vm,root);
} // BindVariable
// special for const string
template <>
void BindVariable < char *> (HSQUIRRELVM vm, char ** var, const SQChar * scriptVarName, VarAccessType /* access */ ) {
HSQOBJECT root = GetRootTable(vm);
VarRefPtr pvr = createVarRef(vm,root,scriptVarName);
* pvr = VarRef(vm,root,var,TypeInfo < const char *> (), 0 ,ClassType_t < const char *> ::getCopyFunc(), sizeof ( * var),VAR_ACCESS_CONSTANT,TypeInfo < const char *> ().typeName);
createTableSetGetHandlers(vm,root);
} // BindVariable
#endif // _SQGLOBALVARIABLE_H_