Squirrel 3.0beta 中绑定全局变量
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)© }
static CopyVarFunc getCopyFunc(void) { return (CopyVarFunc)© }
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)© }
static CopyVarFunc getCopyFunc(void) { return (CopyVarFunc)© }
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_