2 // Copyright (C) 2006 Matthias Braun <matze@braunis.de>
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.
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.
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/>.
17 #include "scripting/squirrel_util.hpp"
23 #include <sqstdblob.h>
24 #include <sqstdmath.h>
25 #include <sqstdstring.h>
28 #include "physfs/ifile_stream.hpp"
29 #include "supertux/console.hpp"
30 #include "util/log.hpp"
34 static HSQREMOTEDBG debugger = NULL;
39 HSQUIRRELVM global_vm = NULL;
41 static void printfunc(HSQUIRRELVM, const char* str, ...)
45 va_start(arglist, str);
46 vsprintf(buf, str, arglist);
47 Console::output << (const char*) buf << std::flush;
51 void init_squirrel(bool enable_debugger)
53 global_vm = sq_open(64);
55 throw std::runtime_error("Couldn't initialize squirrel vm");
59 sq_enabledebuginfo(global_vm, SQTrue);
60 debugger = sq_rdbg_init(global_vm, 1234, SQFalse);
62 throw SquirrelError(global_vm, "Couldn't initialize squirrel debugger");
64 sq_enabledebuginfo(global_vm, SQTrue);
65 log_info << "Waiting for debug client..." << std::endl;
66 if(SQ_FAILED(sq_rdbg_waitforconnections(debugger)))
67 throw SquirrelError(global_vm, "Waiting for debug clients failed");
68 log_info << "debug client connected." << std::endl;
72 sq_pushroottable(global_vm);
73 if(SQ_FAILED(sqstd_register_bloblib(global_vm)))
74 throw SquirrelError(global_vm, "Couldn't register blob lib");
75 if(SQ_FAILED(sqstd_register_mathlib(global_vm)))
76 throw SquirrelError(global_vm, "Couldn't register math lib");
77 if(SQ_FAILED(sqstd_register_stringlib(global_vm)))
78 throw SquirrelError(global_vm, "Couldn't register string lib");
80 // remove rand and srand calls from sqstdmath, we'll provide our own
81 sq_pushstring(global_vm, "srand", -1);
82 sq_deleteslot(global_vm, -2, SQFalse);
83 sq_pushstring(global_vm, "rand", -1);
84 sq_deleteslot(global_vm, -2, SQFalse);
86 // register supertux API
87 register_supertux_wrapper(global_vm);
91 // register print function
92 sq_setprintfunc(global_vm, printfunc);
93 // register default error handlers
94 sqstd_seterrorhandlers(global_vm);
96 // try to load default script
98 std::string filename = "scripts/default.nut";
99 IFileStream stream(filename);
100 Scripting::compile_and_run(global_vm, stream, filename);
101 } catch(std::exception& e) {
102 log_warning << "Couldn't load default.nut: " << e.what() << std::endl;
109 if(debugger != NULL) {
110 sq_rdbg_shutdown(debugger);
121 void update_debugger()
125 sq_rdbg_update(debugger);
129 std::string squirrel2string(HSQUIRRELVM v, SQInteger i)
131 std::ostringstream os;
132 switch(sq_gettype(v, i))
139 sq_getbool(v, i, &p);
148 sq_getinteger(v, i, &val);
154 sq_getfloat(v, i, &val);
160 sq_getstring(v, i, &val);
161 os << "\"" << val << "\"";
167 sq_pushnull(v); //null iterator
168 while(SQ_SUCCEEDED(sq_next(v,i-1)))
175 //here -1 is the value and -2 is the key
176 os << squirrel2string(v, -2) << " => "
177 << squirrel2string(v, -1);
179 sq_pop(v,2); //pops key and val before the nex iteration
188 sq_pushnull(v); //null iterator
189 while(SQ_SUCCEEDED(sq_next(v,i-1)))
196 //here -1 is the value and -2 is the key
197 // we ignore the key, since that is just the index in an array
198 os << squirrel2string(v, -1);
200 sq_pop(v,2); //pops key and val before the nex iteration
212 case OT_NATIVECLOSURE:
213 os << "<native closure>";
240 void print_squirrel_stack(HSQUIRRELVM v)
242 printf("--------------------------------------------------------------\n");
243 int count = sq_gettop(v);
244 for(int i = 1; i <= count; ++i) {
246 switch(sq_gettype(v, i))
253 sq_getinteger(v, i, &val);
254 printf("integer (%d)", static_cast<int> (val));
259 sq_getfloat(v, i, &val);
260 printf("float (%f)", val);
265 sq_getstring(v, i, &val);
266 printf("string (%s)", val);
279 printf("closure(function)");
281 case OT_NATIVECLOSURE:
282 printf("native closure(C function)");
288 printf("userpointer");
303 printf("unknown?!?");
308 printf("--------------------------------------------------------------\n");
311 static SQInteger squirrel_read_char(SQUserPointer file)
313 std::istream* in = reinterpret_cast<std::istream*> (file);
320 void compile_script(HSQUIRRELVM vm, std::istream& in, const std::string& sourcename)
322 if(SQ_FAILED(sq_compile(vm, squirrel_read_char, &in, sourcename.c_str(), true)))
323 throw SquirrelError(vm, "Couldn't parse script");
326 void compile_and_run(HSQUIRRELVM vm, std::istream& in,
327 const std::string& sourcename)
329 compile_script(vm, in, sourcename);
331 SQInteger oldtop = sq_gettop(vm);
334 sq_pushroottable(vm);
335 if(SQ_FAILED(sq_call(vm, 1, SQFalse, SQTrue)))
336 throw SquirrelError(vm, "Couldn't start script");
338 sq_settop(vm, oldtop);
342 // we can remove the closure in case the script was not suspended
343 if(sq_getvmstate(vm) != SQ_VMSTATE_SUSPENDED) {
344 sq_settop(vm, oldtop-1);
348 HSQOBJECT create_thread(HSQUIRRELVM vm)
350 HSQUIRRELVM new_vm = sq_newthread(vm, 64);
352 throw SquirrelError(vm, "Couldn't create new VM");
355 sq_resetobject(&vm_object);
356 if(SQ_FAILED(sq_getstackobj(vm, -1, &vm_object)))
357 throw SquirrelError(vm, "Couldn't get squirrel thread from stack");
358 sq_addref(vm, &vm_object);
365 HSQOBJECT vm_to_object(HSQUIRRELVM vm)
368 sq_resetobject(&object);
369 object._unVal.pThread = vm;
370 object._type = OT_THREAD;
375 HSQUIRRELVM object_to_vm(HSQOBJECT object)
377 if(object._type != OT_THREAD)
380 return object._unVal.pThread;
383 // begin: serialization functions
385 void store_float(HSQUIRRELVM vm, const char* name, float val)
387 sq_pushstring(vm, name, -1);
388 sq_pushfloat(vm, val);
389 if(SQ_FAILED(sq_createslot(vm, -3)))
390 throw Scripting::SquirrelError(vm, "Couldn't add float value to table");
393 void store_int(HSQUIRRELVM vm, const char* name, int val)
395 sq_pushstring(vm, name, -1);
396 sq_pushinteger(vm, val);
397 if(SQ_FAILED(sq_createslot(vm, -3)))
398 throw Scripting::SquirrelError(vm, "Couldn't add int value to table");
401 void store_string(HSQUIRRELVM vm, const char* name, const std::string& val)
403 sq_pushstring(vm, name, -1);
404 sq_pushstring(vm, val.c_str(), val.length());
405 if(SQ_FAILED(sq_createslot(vm, -3)))
406 throw Scripting::SquirrelError(vm, "Couldn't add float value to table");
409 void store_bool(HSQUIRRELVM vm, const char* name, bool val)
411 sq_pushstring(vm, name, -1);
412 sq_pushbool(vm, val ? SQTrue : SQFalse);
413 if(SQ_FAILED(sq_createslot(vm, -3)))
414 throw Scripting::SquirrelError(vm, "Couldn't add float value to table");
417 bool has_float(HSQUIRRELVM vm, const char* name)
419 sq_pushstring(vm, name, -1);
420 if (SQ_FAILED(sq_get(vm, -2))) return false;
425 bool has_int(HSQUIRRELVM vm, const char* name)
427 return has_float(vm, name);
430 bool has_string(HSQUIRRELVM vm, const char* name)
432 return has_float(vm, name);
435 bool has_bool(HSQUIRRELVM vm, const char* name)
437 return has_float(vm, name);
440 float read_float(HSQUIRRELVM vm, const char* name)
442 sq_pushstring(vm, name, -1);
443 if(SQ_FAILED(sq_get(vm, -2))) {
444 std::ostringstream msg;
445 msg << "Couldn't get float value for '" << name << "' from table";
446 throw Scripting::SquirrelError(vm, msg.str());
450 if(SQ_FAILED(sq_getfloat(vm, -1, &result))) {
451 std::ostringstream msg;
452 msg << "Couldn't get float value for '" << name << "' from table";
453 throw Scripting::SquirrelError(vm, msg.str());
460 int read_int(HSQUIRRELVM vm, const char* name)
462 sq_pushstring(vm, name, -1);
463 if(SQ_FAILED(sq_get(vm, -2))) {
464 std::ostringstream msg;
465 msg << "Couldn't get int value for '" << name << "' from table";
466 throw Scripting::SquirrelError(vm, msg.str());
470 if(SQ_FAILED(sq_getinteger(vm, -1, &result))) {
471 std::ostringstream msg;
472 msg << "Couldn't get int value for '" << name << "' from table";
473 throw Scripting::SquirrelError(vm, msg.str());
480 std::string read_string(HSQUIRRELVM vm, const char* name)
482 sq_pushstring(vm, name, -1);
483 if(SQ_FAILED(sq_get(vm, -2))) {
484 std::ostringstream msg;
485 msg << "Couldn't get string value for '" << name << "' from table";
486 throw Scripting::SquirrelError(vm, msg.str());
490 if(SQ_FAILED(sq_getstring(vm, -1, &result))) {
491 std::ostringstream msg;
492 msg << "Couldn't get string value for '" << name << "' from table";
493 throw Scripting::SquirrelError(vm, msg.str());
497 return std::string(result);
500 bool read_bool(HSQUIRRELVM vm, const char* name)
502 sq_pushstring(vm, name, -1);
503 if(SQ_FAILED(sq_get(vm, -2))) {
504 std::ostringstream msg;
505 msg << "Couldn't get bool value for '" << name << "' from table";
506 throw Scripting::SquirrelError(vm, msg.str());
510 if(SQ_FAILED(sq_getbool(vm, -1, &result))) {
511 std::ostringstream msg;
512 msg << "Couldn't get bool value for '" << name << "' from table";
513 throw Scripting::SquirrelError(vm, msg.str());
517 return result == SQTrue;
520 bool get_float(HSQUIRRELVM vm, const char* name, float& val) {
521 if (!has_float(vm, name)) return false;
522 val = read_float(vm, name);
526 bool get_int(HSQUIRRELVM vm, const char* name, int& val) {
527 if (!has_int(vm, name)) return false;
528 val = read_int(vm, name);
532 bool get_string(HSQUIRRELVM vm, const char* name, std::string& val) {
533 if (!has_string(vm, name)) return false;
534 val = read_string(vm, name);
538 bool get_bool(HSQUIRRELVM vm, const char* name, bool& val) {
539 if (!has_bool(vm, name)) return false;
540 val = read_bool(vm, name);
544 // end: serialization functions