1 #include "sqplus.h"
2 #include <stdio.h>
3 
4 namespace SqPlus {
5 
getVarInfo(StackHandler & sa,VarRefPtr & vr)6 static SQInteger getVarInfo(StackHandler & sa,VarRefPtr & vr) {
7   HSQOBJECT htable = sa.GetObjectHandle(1);
8   SquirrelObject table(htable);
9 #ifdef _DEBUG
10   SQObjectType type = (SQObjectType)sa.GetType(2);
11 #endif
12   const SQChar * el = sa.GetString(2);
13   ScriptStringVar256 varNameTag;
14   getVarNameTag(varNameTag,sizeof(varNameTag),el);
15   SQUserPointer data=0;
16   if (!table.RawGetUserData(varNameTag,&data)) {
17 //    throw SquirrelError("getVarInfo: Could not retrieve UserData");
18     return sa.ThrowError(sqT("getVarInfo: Could not retrieve UserData")); // Results in variable not being found error.
19   } // if
20   vr = (VarRefPtr)data;
21   return SQ_OK;
22 } // getVarInfo
23 
getInstanceVarInfo(StackHandler & sa,VarRefPtr & vr,SQUserPointer & data)24 static SQInteger getInstanceVarInfo(StackHandler & sa,VarRefPtr & vr,SQUserPointer & data) {
25   HSQOBJECT ho = sa.GetObjectHandle(1);
26   SquirrelObject instance(ho);
27 #ifdef _DEBUG
28   SQObjectType type = (SQObjectType)sa.GetType(2);
29 #endif
30   const SQChar * el = sa.GetString(2);
31   ScriptStringVar256 varNameTag;
32   getVarNameTag(varNameTag,sizeof(varNameTag),el);
33   SQUserPointer ivrData=0;
34   if (!instance.RawGetUserData(varNameTag,&ivrData)) {
35 //    throw SquirrelError("getInstanceVarInfo: Could not retrieve UserData");
36     return sa.ThrowError(sqT("getInstanceVarInfo: Could not retrieve UserData")); // Results in variable not being found error.
37   } // if
38   vr = (VarRefPtr)ivrData;
39   unsigned char * up;
40   if (!(vr->access & (VAR_ACCESS_STATIC|VAR_ACCESS_CONSTANT))) {
41 #ifdef SQ_USE_CLASS_INHERITANCE
42     SQUserPointer typetag; instance.GetTypeTag(&typetag);
43     if (typetag != vr->instanceType) {
44       SquirrelObject typeTable = instance.GetValue(SQ_CLASS_OBJECT_TABLE_NAME);
45       up = (unsigned char *)typeTable.GetUserPointer(INT_T((size_t)vr->instanceType)); // <TODO> 64-bit compatible version.
46       if (!up) {
47         throw SquirrelError(sqT("Invalid Instance Type"));
48       } // if
49     } else {
50       up = (unsigned char *)instance.GetInstanceUP(0);
51     } // if
52 #else
53     up = (unsigned char *)instance.GetInstanceUP(0);
54 #endif
55     up += (size_t)vr->offsetOrAddrOrConst;         // Offset
56   } else {
57     up = (unsigned char *)vr->offsetOrAddrOrConst; // Address
58   } // if
59   data = up;
60   return SQ_OK;
61 } // getInstanceVarInfo
62 
setVar(StackHandler & sa,VarRef * vr,void * data)63 static SQInteger setVar(StackHandler & sa,VarRef * vr,void * data) {
64   if (vr->access & (VAR_ACCESS_READ_ONLY|VAR_ACCESS_CONSTANT)) {
65     ScriptStringVar256 msg;
66     const SQChar * el = sa.GetString(2);
67     SCSNPRINTF(msg.s,sizeof(msg.s),sqT("setVar(): Cannot write to constant: %s"),el);
68     throw SquirrelError(msg.s);
69   } // if
70   switch (vr->type) {
71   case TypeInfo<INT_T>::TypeID: {
72     INT_T * val = (INT_T *)data; // Address
73     if (val) {
74       *val = sa.GetInt(3);
75       return sa.Return(*val);
76     } // if
77     break;
78   } // case
79   case TypeInfo<FLOAT_T>::TypeID: {
80     FLOAT_T * val = (FLOAT_T *)data; // Address
81     if (val) {
82       *val = sa.GetFloat(3);
83       return sa.Return(*val);
84     } // if
85     break;
86   } // case
87   case TypeInfo<bool>::TypeID: {
88     bool * val = (bool *)data; // Address
89     if (val) {
90       *val = sa.GetBool(3) ? true : false;
91       return sa.Return(*val);
92     } // if
93     break;
94   } // case
95   case VAR_TYPE_INSTANCE: {
96     // C::B patch: Comment out unused variable
97     //HSQUIRRELVM v = sa.GetVMPtr();
98     // vr->copyFunc is the LHS variable type: the RHS var's type is ClassType<>::type() (both point to ClassType<>::copy()).
99     // src will be null if the LHS and RHS types don't match.
100     SQUserPointer src = sa.GetInstanceUp(3,(SQUserPointer)vr->copyFunc); // Effectively performs: ClassType<>::type() == ClassType<>getCopyFunc().
101     if (!src) throw SquirrelError(sqT("INSTANCE type assignment mismatch"));
102     vr->copyFunc(data,src);
103 #if 0 // Return an instance on the stack (allocates memory)
104     if (!CreateNativeClassInstance(sa.GetVMPtr(),vr->typeName,data,0)) { // data = address
105       ScriptStringVar256 msg;
106       SCSNPRINTF(msg.s,sizeof(msg),sqT("getVar(): Could not create instance: %s"),vr->typeName);
107       throw SquirrelError(msg.s);
108     } // if
109     return 1;
110 #else // Don't return on stack.
111     return 0;
112 #endif
113   }
114   case TypeInfo<SQUserPointer>::TypeID: {
115     ScriptStringVar256 msg;
116     const SQChar * el = sa.GetString(2);
117     SCSNPRINTF(msg.s,sizeof(msg.s),sqT("setVar(): Cannot write to an SQUserPointer: %s"),el);
118     throw SquirrelError(msg.s);
119   } // case
120   case TypeInfo<ScriptStringVarBase>::TypeID: {
121     ScriptStringVarBase * val = (ScriptStringVarBase *)data; // Address
122     if (val) {
123       const SQChar * strVal = sa.GetString(3);
124       if (strVal) {
125         *val = strVal;
126         return sa.Return(val->s);
127       } // if
128     } // if
129     break;
130   } // case
131   // C::B patch: Handle all switch cases
132   default: break;
133   } // switch
134   return SQ_ERROR;
135 } // setVar
136 
getVar(StackHandler & sa,VarRef * vr,void * data)137 static SQInteger getVar(StackHandler & sa,VarRef * vr,void * data) {
138   switch (vr->type) {
139   case TypeInfo<INT_T>::TypeID: {
140     if (!(vr->access & VAR_ACCESS_CONSTANT)) {
141       INT_T * val = (INT_T *)data; // Address
142       if (val) {
143         return sa.Return(*val);
144       } // if
145     } else {
146       INT_T * val = (INT_T *)&data; // Constant value
147       return sa.Return(*val);
148     } // if
149     break;
150   } // case
151   case TypeInfo<FLOAT_T>::TypeID: {
152     if (!(vr->access & VAR_ACCESS_CONSTANT)) {
153       FLOAT_T * val = (FLOAT_T *)data; // Address
154       if (val) {
155         return sa.Return(*val);
156       } // if
157     } else {
158       FLOAT_T * val = (FLOAT_T *)&data; // Constant value
159       return sa.Return(*val);
160     } // if
161     break;
162   } // case
163   case TypeInfo<bool>::TypeID: {
164     if (!(vr->access & VAR_ACCESS_CONSTANT)) {
165       bool * val = (bool *)data; // Address
166       if (val) {
167         return sa.Return(*val);
168       } // if
169     } else {
170       bool * val = (bool *)&data; // Constant value
171       return sa.Return(*val);
172     } // if
173     break;
174   } // case
175   case VAR_TYPE_INSTANCE:
176     if (!CreateNativeClassInstance(sa.GetVMPtr(),vr->typeName,data,0)) { // data = address. Allocates memory.
177       ScriptStringVar256 msg;
178       SCSNPRINTF(msg.s,sizeof(msg.s),sqT("getVar(): Could not create instance: %s"),vr->typeName);
179       throw SquirrelError(msg.s);
180     } // if
181     return 1;
182   case TypeInfo<SQUserPointer>::TypeID: {
183     return sa.Return(data); // The address of member variable, not the variable itself.
184   } // case
185   case TypeInfo<ScriptStringVarBase>::TypeID: {
186     if (!(vr->access & VAR_ACCESS_CONSTANT)) {
187       ScriptStringVarBase * val = (ScriptStringVarBase *)data; // Address
188       if (val) {
189         return sa.Return(val->s);
190       } // if
191     } else {
192       throw SquirrelError(sqT("getVar(): Invalid type+access: 'ScriptStringVarBase' with VAR_ACCESS_CONSTANT (use VAR_ACCESS_READ_ONLY instead)"));
193     } // if
194     break;
195   } // case
196   case TypeInfo<const SQChar *>::TypeID: {
197     if (!(vr->access & VAR_ACCESS_CONSTANT)) {
198       throw SquirrelError(sqT("getVar(): Invalid type+access: 'const SQChar *' without VAR_ACCESS_CONSTANT"));
199     } else {
200       return sa.Return((const SQChar *)data); // Address
201     } // if
202     break;
203   } // case
204   // C::B patch: Handle all switch cases
205   default: break;
206   } // switch
207   return SQ_ERROR;
208 } // getVar
209 
210 // === Global Vars ===
211 
setVarFunc(HSQUIRRELVM v)212 SQInteger setVarFunc(HSQUIRRELVM v) {
213   StackHandler sa(v);
214   if (sa.GetType(1) == OT_TABLE) {
215     VarRefPtr vr;
216     SQInteger res = getVarInfo(sa,vr);
217     if (res != SQ_OK) return res;
218     return setVar(sa,vr,vr->offsetOrAddrOrConst);
219   } // if
220   return SQ_ERROR;
221 } // setVarFunc
222 
getVarFunc(HSQUIRRELVM v)223 SQInteger getVarFunc(HSQUIRRELVM v) {
224   StackHandler sa(v);
225   if (sa.GetType(1) == OT_TABLE) {
226     VarRefPtr vr;
227     SQInteger res = getVarInfo(sa,vr);
228     if (res != SQ_OK) return res;
229     return getVar(sa,vr,vr->offsetOrAddrOrConst);
230   } // if
231   return SQ_ERROR;
232 } // getVarFunc
233 
234 // === Instance Vars ===
235 
setInstanceVarFunc(HSQUIRRELVM v)236 SQInteger setInstanceVarFunc(HSQUIRRELVM v) {
237   StackHandler sa(v);
238   if (sa.GetType(1) == OT_INSTANCE) {
239     VarRefPtr vr;
240     void * data;
241     SQInteger res = getInstanceVarInfo(sa,vr,data);
242     if (res != SQ_OK) return res;
243     return setVar(sa,vr,data);
244   } // if
245   return SQ_ERROR;
246 } // setInstanceVarFunc
247 
getInstanceVarFunc(HSQUIRRELVM v)248 SQInteger getInstanceVarFunc(HSQUIRRELVM v) {
249   StackHandler sa(v);
250   if (sa.GetType(1) == OT_INSTANCE) {
251     VarRefPtr vr;
252     void * data;
253     SQInteger res = getInstanceVarInfo(sa,vr,data);
254     if (res != SQ_OK) return res;
255     return getVar(sa,vr,data);
256   } // if
257   return SQ_ERROR;
258 } // getInstanceVarFunc
259 
260 // === Classes ===
261 
CreateClass(HSQUIRRELVM v,SquirrelObject & newClass,SQUserPointer classType,const SQChar * name,const SQChar * baseName)262 BOOL_T CreateClass(HSQUIRRELVM v,SquirrelObject & newClass,SQUserPointer classType,const SQChar * name,const SQChar * baseName) {
263   // C::B patch: Comment out unused variable
264   //SQInteger n = 0;
265   SQInteger oldtop = sq_gettop(v);
266   sq_pushroottable(v);
267   sq_pushstring(v,name,-1);
268   if (baseName) {
269     sq_pushstring(v,baseName,-1);
270     if (SQ_FAILED(sq_get(v,-3))) { // Make sure the base exists if specified by baseName.
271       sq_settop(v,oldtop);
272       return FALSE;
273     } // if
274   } // if
275   if (SQ_FAILED(sq_newclass(v,baseName ? 1 : 0))) { // Will inherit from base class on stack from sq_get() above.
276     sq_settop(v,oldtop);
277     return FALSE;
278   } // if
279   newClass.AttachToStackObject(-1);
280   sq_settypetag(v,-1,classType);
281   sq_createslot(v,-3);
282   sq_pop(v,1);
283   return TRUE;
284 } // CreateClass
285 
RegisterClassType(HSQUIRRELVM v,const SQChar * scriptClassName,SQUserPointer classType,SQFUNCTION constructor)286 SquirrelObject RegisterClassType(HSQUIRRELVM v,const SQChar * scriptClassName,SQUserPointer classType,SQFUNCTION constructor) {
287   SQInteger top = sq_gettop(v);
288   SquirrelObject newClass;
289   if (CreateClass(v,newClass,classType,scriptClassName)) {
290     SquirrelVM::CreateFunction(newClass,constructor,sqT("constructor"));
291   } // if
292   sq_settop(v,top);
293   return newClass;
294 } // RegisterClassType
295 
296 }; // namespace SqPlus
297 
298 // sqPlus
299