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