5fd15b42d184c30b0e1cd533954d2870575cbf9b
[supertux.git] / src / scripting / squirrel_util.cpp
1 //  SuperTux
2 //  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
3 //
4 //  This program is free software: you can redistribute it and/or modify
5 //  it under the terms of the GNU General Public License as published by
6 //  the Free Software Foundation, either version 3 of the License, or
7 //  (at your option) any later version.
8 //
9 //  This program is distributed in the hope that it will be useful,
10 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 //  GNU General Public License for more details.
13 //
14 //  You should have received a copy of the GNU General Public License
15 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
17 #include "scripting/squirrel_util.hpp"
18
19 #include <config.h>
20
21 #include <stdio.h>
22 #include <sqstdaux.h>
23 #include <sqstdblob.h>
24 #include <sqstdmath.h>
25 #include <sqstdstring.h>
26 #include <stdarg.h>
27
28 namespace scripting {
29
30 std::string squirrel2string(HSQUIRRELVM v, SQInteger i)
31 {
32   std::ostringstream os;
33   switch(sq_gettype(v, i))
34   {
35     case OT_NULL:
36       os << "<null>";
37       break;
38     case OT_BOOL: {
39       SQBool p;
40       sq_getbool(v, i, &p);
41       if (p)
42         os << "true";
43       else
44         os << "false";
45       break;
46     }
47     case OT_INTEGER: {
48       SQInteger val;
49       sq_getinteger(v, i, &val);
50       os << val;
51       break;
52     }
53     case OT_FLOAT: {
54       SQFloat val;
55       sq_getfloat(v, i, &val);
56       os << val;
57       break;
58     }
59     case OT_STRING: {
60       const SQChar* val;
61       sq_getstring(v, i, &val);
62       os << "\"" << val << "\"";
63       break;
64     }
65     case OT_TABLE: {
66       bool first = true;
67       os << "{";
68       sq_pushnull(v);  //null iterator
69       while(SQ_SUCCEEDED(sq_next(v,i-1)))
70       {
71         if (!first) {
72           os << ", ";
73         }
74         first = false;
75
76         //here -1 is the value and -2 is the key
77         os << squirrel2string(v, -2) << " => "
78            << squirrel2string(v, -1);
79
80         sq_pop(v,2); //pops key and val before the nex iteration
81       }
82       sq_pop(v, 1);
83       os << "}";
84       break;
85     }
86     case OT_ARRAY: {
87       bool first = true;
88       os << "[";
89       sq_pushnull(v);  //null iterator
90       while(SQ_SUCCEEDED(sq_next(v,i-1)))
91       {
92         if (!first) {
93           os << ", ";
94         }
95         first = false;
96
97         //here -1 is the value and -2 is the key
98         // we ignore the key, since that is just the index in an array
99         os << squirrel2string(v, -1);
100
101         sq_pop(v,2); //pops key and val before the nex iteration
102       }
103       sq_pop(v, 1);
104       os << "]";
105       break;
106     }
107     case OT_USERDATA:
108       os << "<userdata>";
109       break;
110     case OT_CLOSURE:
111       os << "<closure>";
112       break;
113     case OT_NATIVECLOSURE:
114       os << "<native closure>";
115       break;
116     case OT_GENERATOR:
117       os << "<generator>";
118       break;
119     case OT_USERPOINTER:
120       os << "userpointer";
121       break;
122     case OT_THREAD:
123       os << "<thread>";
124       break;
125     case OT_CLASS:
126       os << "<class>";
127       break;
128     case OT_INSTANCE:
129       os << "<instance>";
130       break;
131     case OT_WEAKREF:
132       os << "<weakref>";
133       break;
134     default:
135       os << "<unknown>";
136       break;
137   }
138   return os.str();
139 }
140
141 void print_squirrel_stack(HSQUIRRELVM v)
142 {
143   printf("--------------------------------------------------------------\n");
144   int count = sq_gettop(v);
145   for(int i = 1; i <= count; ++i) {
146     printf("%d: ",i);
147     switch(sq_gettype(v, i))
148     {
149       case OT_NULL:
150         printf("null");
151         break;
152       case OT_INTEGER: {
153         SQInteger val;
154         sq_getinteger(v, i, &val);
155         printf("integer (%d)", static_cast<int> (val));
156         break;
157       }
158       case OT_FLOAT: {
159         SQFloat val;
160         sq_getfloat(v, i, &val);
161         printf("float (%f)", val);
162         break;
163       }
164       case OT_STRING: {
165         const SQChar* val;
166         sq_getstring(v, i, &val);
167         printf("string (%s)", val);
168         break;
169       }
170       case OT_TABLE:
171         printf("table");
172         break;
173       case OT_ARRAY:
174         printf("array");
175         break;
176       case OT_USERDATA:
177         printf("userdata");
178         break;
179       case OT_CLOSURE:
180         printf("closure(function)");
181         break;
182       case OT_NATIVECLOSURE:
183         printf("native closure(C function)");
184         break;
185       case OT_GENERATOR:
186         printf("generator");
187         break;
188       case OT_USERPOINTER:
189         printf("userpointer");
190         break;
191       case OT_THREAD:
192         printf("thread");
193         break;
194       case OT_CLASS:
195         printf("class");
196         break;
197       case OT_INSTANCE:
198         printf("instance");
199         break;
200       case OT_WEAKREF:
201         printf("weakref");
202         break;
203       default:
204         printf("unknown?!?");
205         break;
206     }
207     printf("\n");
208   }
209   printf("--------------------------------------------------------------\n");
210 }
211
212 SQInteger squirrel_read_char(SQUserPointer file)
213 {
214   std::istream* in = reinterpret_cast<std::istream*> (file);
215   int c = in->get();
216   if(in->eof())
217     return 0;
218   return c;
219 }
220
221 void compile_script(HSQUIRRELVM vm, std::istream& in, const std::string& sourcename)
222 {
223   if(SQ_FAILED(sq_compile(vm, squirrel_read_char, &in, sourcename.c_str(), true)))
224     throw SquirrelError(vm, "Couldn't parse script");
225 }
226
227 void compile_and_run(HSQUIRRELVM vm, std::istream& in,
228                      const std::string& sourcename)
229 {
230   compile_script(vm, in, sourcename);
231
232   SQInteger oldtop = sq_gettop(vm);
233
234   try {
235     sq_pushroottable(vm);
236     if(SQ_FAILED(sq_call(vm, 1, SQFalse, SQTrue)))
237       throw SquirrelError(vm, "Couldn't start script");
238   } catch(...) {
239     sq_settop(vm, oldtop);
240     throw;
241   }
242
243   // we can remove the closure in case the script was not suspended
244   if(sq_getvmstate(vm) != SQ_VMSTATE_SUSPENDED) {
245     sq_settop(vm, oldtop-1);
246   }
247 }
248
249 HSQOBJECT create_thread(HSQUIRRELVM vm)
250 {
251   HSQUIRRELVM new_vm = sq_newthread(vm, 64);
252   if(new_vm == NULL)
253     throw SquirrelError(vm, "Couldn't create new VM");
254
255   HSQOBJECT vm_object;
256   sq_resetobject(&vm_object);
257   if(SQ_FAILED(sq_getstackobj(vm, -1, &vm_object)))
258     throw SquirrelError(vm, "Couldn't get squirrel thread from stack");
259   sq_addref(vm, &vm_object);
260
261   sq_pop(vm, 1);
262
263   return vm_object;
264 }
265
266 HSQOBJECT vm_to_object(HSQUIRRELVM vm)
267 {
268   HSQOBJECT object;
269   sq_resetobject(&object);
270   object._unVal.pThread = vm;
271   object._type = OT_THREAD;
272
273   return object;
274 }
275
276 HSQUIRRELVM object_to_vm(HSQOBJECT object)
277 {
278   if(object._type != OT_THREAD)
279     return NULL;
280
281   return object._unVal.pThread;
282 }
283
284 // begin: serialization functions
285
286 void store_float(HSQUIRRELVM vm, const char* name, float val)
287 {
288   sq_pushstring(vm, name, -1);
289   sq_pushfloat(vm, val);
290   if(SQ_FAILED(sq_createslot(vm, -3)))
291     throw scripting::SquirrelError(vm, "Couldn't add float value to table");
292 }
293
294 void store_int(HSQUIRRELVM vm, const char* name, int val)
295 {
296   sq_pushstring(vm, name, -1);
297   sq_pushinteger(vm, val);
298   if(SQ_FAILED(sq_createslot(vm, -3)))
299     throw scripting::SquirrelError(vm, "Couldn't add int value to table");
300 }
301
302 void store_string(HSQUIRRELVM vm, const char* name, const std::string& val)
303 {
304   sq_pushstring(vm, name, -1);
305   sq_pushstring(vm, val.c_str(), val.length());
306   if(SQ_FAILED(sq_createslot(vm, -3)))
307     throw scripting::SquirrelError(vm, "Couldn't add float value to table");
308 }
309
310 void store_bool(HSQUIRRELVM vm, const char* name, bool val)
311 {
312   sq_pushstring(vm, name, -1);
313   sq_pushbool(vm, val ? SQTrue : SQFalse);
314   if(SQ_FAILED(sq_createslot(vm, -3)))
315     throw scripting::SquirrelError(vm, "Couldn't add float value to table");
316 }
317
318 bool has_float(HSQUIRRELVM vm, const char* name)
319 {
320   sq_pushstring(vm, name, -1);
321   if (SQ_FAILED(sq_get(vm, -2))) return false;
322   sq_pop(vm, 1);
323   return true;
324 }
325
326 bool has_int(HSQUIRRELVM vm, const char* name)
327 {
328   return has_float(vm, name);
329 }
330
331 bool has_string(HSQUIRRELVM vm, const char* name)
332 {
333   return has_float(vm, name);
334 }
335
336 bool has_bool(HSQUIRRELVM vm, const char* name)
337 {
338   return has_float(vm, name);
339 }
340
341 float read_float(HSQUIRRELVM vm, const char* name)
342 {
343   sq_pushstring(vm, name, -1);
344   if(SQ_FAILED(sq_get(vm, -2))) {
345     std::ostringstream msg;
346     msg << "Couldn't get float value for '" << name << "' from table";
347     throw scripting::SquirrelError(vm, msg.str());
348   }
349
350   float result;
351   if(SQ_FAILED(sq_getfloat(vm, -1, &result))) {
352     std::ostringstream msg;
353     msg << "Couldn't get float value for '" << name << "' from table";
354     throw scripting::SquirrelError(vm, msg.str());
355   }
356   sq_pop(vm, 1);
357
358   return result;
359 }
360
361 int read_int(HSQUIRRELVM vm, const char* name)
362 {
363   sq_pushstring(vm, name, -1);
364   if(SQ_FAILED(sq_get(vm, -2))) {
365     std::ostringstream msg;
366     msg << "Couldn't get int value for '" << name << "' from table";
367     throw scripting::SquirrelError(vm, msg.str());
368   }
369
370   SQInteger result;
371   if(SQ_FAILED(sq_getinteger(vm, -1, &result))) {
372     std::ostringstream msg;
373     msg << "Couldn't get int value for '" << name << "' from table";
374     throw scripting::SquirrelError(vm, msg.str());
375   }
376   sq_pop(vm, 1);
377
378   return result;
379 }
380
381 std::string read_string(HSQUIRRELVM vm, const char* name)
382 {
383   sq_pushstring(vm, name, -1);
384   if(SQ_FAILED(sq_get(vm, -2))) {
385     std::ostringstream msg;
386     msg << "Couldn't get string value for '" << name << "' from table";
387     throw scripting::SquirrelError(vm, msg.str());
388   }
389
390   const char* result;
391   if(SQ_FAILED(sq_getstring(vm, -1, &result))) {
392     std::ostringstream msg;
393     msg << "Couldn't get string value for '" << name << "' from table";
394     throw scripting::SquirrelError(vm, msg.str());
395   }
396   sq_pop(vm, 1);
397
398   return std::string(result);
399 }
400
401 bool read_bool(HSQUIRRELVM vm, const char* name)
402 {
403   sq_pushstring(vm, name, -1);
404   if(SQ_FAILED(sq_get(vm, -2))) {
405     std::ostringstream msg;
406     msg << "Couldn't get bool value for '" << name << "' from table";
407     throw scripting::SquirrelError(vm, msg.str());
408   }
409
410   SQBool result;
411   if(SQ_FAILED(sq_getbool(vm, -1, &result))) {
412     std::ostringstream msg;
413     msg << "Couldn't get bool value for '" << name << "' from table";
414     throw scripting::SquirrelError(vm, msg.str());
415   }
416   sq_pop(vm, 1);
417
418   return result == SQTrue;
419 }
420
421 bool get_float(HSQUIRRELVM vm, const char* name, float& val) {
422   if (!has_float(vm, name)) return false;
423   val = read_float(vm, name);
424   return true;
425 }
426
427 bool get_int(HSQUIRRELVM vm, const char* name, int& val) {
428   if (!has_int(vm, name)) return false;
429   val = read_int(vm, name);
430   return true;
431 }
432
433 bool get_string(HSQUIRRELVM vm, const char* name, std::string& val) {
434   if (!has_string(vm, name)) return false;
435   val = read_string(vm, name);
436   return true;
437 }
438
439 bool get_bool(HSQUIRRELVM vm, const char* name, bool& val) {
440   if (!has_bool(vm, name)) return false;
441   val = read_bool(vm, name);
442   return true;
443 }
444
445 // end: serialization functions
446
447 }
448
449 /* EOF */