4 // Copyright (C) 2006 Matthias Braun <matze@braunis.de>
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 #include <sqstdmath.h>
26 #include <sqstdblob.h>
27 #include <sqstdstring.h>
30 #include "squirrel_util.hpp"
33 #include "physfs/physfs_stream.hpp"
34 #include "random_generator.hpp"
37 #include <sqdbg/sqrdbg.h>
39 static HSQREMOTEDBG debugger = NULL;
45 HSQUIRRELVM global_vm = NULL;
47 static void printfunc(HSQUIRRELVM, const char* str, ...)
51 va_start(arglist, str);
52 vsprintf(buf, str, arglist);
53 Console::output << (const char*) buf << std::flush;
57 void init_squirrel(bool enable_debugger)
59 global_vm = sq_open(64);
61 throw std::runtime_error("Couldn't initialize squirrel vm");
65 sq_enabledebuginfo(global_vm, SQTrue);
66 debugger = sq_rdbg_init(global_vm, 1234, SQFalse);
68 throw SquirrelError(global_vm, "Couldn't initialize squirrel debugger");
70 sq_enabledebuginfo(global_vm, SQTrue);
71 log_info << "Waiting for debug client..." << std::endl;
72 if(SQ_FAILED(sq_rdbg_waitforconnections(debugger)))
73 throw SquirrelError(global_vm, "Waiting for debug clients failed");
74 log_info << "debug client connected." << std::endl;
78 sq_pushroottable(global_vm);
79 if(SQ_FAILED(sqstd_register_bloblib(global_vm)))
80 throw SquirrelError(global_vm, "Couldn't register blob lib");
81 if(SQ_FAILED(sqstd_register_mathlib(global_vm)))
82 throw SquirrelError(global_vm, "Couldn't register math lib");
83 if(SQ_FAILED(sqstd_register_stringlib(global_vm)))
84 throw SquirrelError(global_vm, "Couldn't register string lib");
86 // remove rand and srand calls from sqstdmath, we'll provide our own
87 sq_pushstring(global_vm, "srand", -1);
88 sq_deleteslot(global_vm, -2, SQFalse);
89 sq_pushstring(global_vm, "rand", -1);
90 sq_deleteslot(global_vm, -2, SQFalse);
92 // register supertux API
93 register_supertux_wrapper(global_vm);
97 // register print function
98 sq_setprintfunc(global_vm, printfunc);
99 // register default error handlers
100 sqstd_seterrorhandlers(global_vm);
102 // try to load default script
104 std::string filename = "scripts/default.nut";
105 IFileStream stream(filename);
106 Scripting::compile_and_run(global_vm, stream, filename);
107 } catch(std::exception& e) {
108 log_warning << "Couldn't load default.nut: " << e.what() << std::endl;
115 if(debugger != NULL) {
116 sq_rdbg_shutdown(debugger);
127 void update_debugger()
131 sq_rdbg_update(debugger);
135 std::string squirrel2string(HSQUIRRELVM v, SQInteger i)
137 std::ostringstream os;
138 switch(sq_gettype(v, i))
145 sq_getbool(v, i, &p);
154 sq_getinteger(v, i, &val);
160 sq_getfloat(v, i, &val);
166 sq_getstring(v, i, &val);
167 os << "\"" << val << "\"";
173 sq_pushnull(v); //null iterator
174 while(SQ_SUCCEEDED(sq_next(v,i-1)))
181 //here -1 is the value and -2 is the key
182 os << squirrel2string(v, -2) << " => "
183 << squirrel2string(v, -1);
185 sq_pop(v,2); //pops key and val before the nex iteration
194 sq_pushnull(v); //null iterator
195 while(SQ_SUCCEEDED(sq_next(v,i-1)))
202 //here -1 is the value and -2 is the key
203 // we ignore the key, since that is just the index in an array
204 os << squirrel2string(v, -1);
206 sq_pop(v,2); //pops key and val before the nex iteration
218 case OT_NATIVECLOSURE:
219 os << "<native closure>";
246 void print_squirrel_stack(HSQUIRRELVM v)
248 printf("--------------------------------------------------------------\n");
249 int count = sq_gettop(v);
250 for(int i = 1; i <= count; ++i) {
252 switch(sq_gettype(v, i))
259 sq_getinteger(v, i, &val);
260 printf("integer (%d)", static_cast<int> (val));
265 sq_getfloat(v, i, &val);
266 printf("float (%f)", val);
271 sq_getstring(v, i, &val);
272 printf("string (%s)", val);
285 printf("closure(function)");
287 case OT_NATIVECLOSURE:
288 printf("native closure(C function)");
294 printf("userpointer");
309 printf("unknown?!?");
314 printf("--------------------------------------------------------------\n");
317 static SQInteger squirrel_read_char(SQUserPointer file)
319 std::istream* in = reinterpret_cast<std::istream*> (file);
326 void compile_script(HSQUIRRELVM vm, std::istream& in, const std::string& sourcename)
328 if(SQ_FAILED(sq_compile(vm, squirrel_read_char, &in, sourcename.c_str(), true)))
329 throw SquirrelError(vm, "Couldn't parse script");
332 void compile_and_run(HSQUIRRELVM vm, std::istream& in,
333 const std::string& sourcename)
335 compile_script(vm, in, sourcename);
337 SQInteger oldtop = sq_gettop(vm);
340 sq_pushroottable(vm);
341 if(SQ_FAILED(sq_call(vm, 1, SQFalse, SQTrue)))
342 throw SquirrelError(vm, "Couldn't start script");
344 sq_settop(vm, oldtop);
348 // we can remove the closure in case the script was not suspended
349 if(sq_getvmstate(vm) != SQ_VMSTATE_SUSPENDED) {
350 sq_settop(vm, oldtop-1);
354 HSQOBJECT create_thread(HSQUIRRELVM vm)
356 HSQUIRRELVM new_vm = sq_newthread(vm, 64);
358 throw SquirrelError(vm, "Couldn't create new VM");
361 sq_resetobject(&vm_object);
362 if(SQ_FAILED(sq_getstackobj(vm, -1, &vm_object)))
363 throw SquirrelError(vm, "Couldn't get squirrel thread from stack");
364 sq_addref(vm, &vm_object);
371 HSQOBJECT vm_to_object(HSQUIRRELVM vm)
374 sq_resetobject(&object);
375 object._unVal.pThread = vm;
376 object._type = OT_THREAD;
381 HSQUIRRELVM object_to_vm(HSQOBJECT object)
383 if(object._type != OT_THREAD)
386 return object._unVal.pThread;
389 // begin: serialization functions
391 void store_float(HSQUIRRELVM vm, const char* name, float val)
393 sq_pushstring(vm, name, -1);
394 sq_pushfloat(vm, val);
395 if(SQ_FAILED(sq_createslot(vm, -3)))
396 throw Scripting::SquirrelError(vm, "Couldn't add float value to table");
399 void store_int(HSQUIRRELVM vm, const char* name, int val)
401 sq_pushstring(vm, name, -1);
402 sq_pushinteger(vm, val);
403 if(SQ_FAILED(sq_createslot(vm, -3)))
404 throw Scripting::SquirrelError(vm, "Couldn't add int value to table");
407 void store_string(HSQUIRRELVM vm, const char* name, const std::string& val)
409 sq_pushstring(vm, name, -1);
410 sq_pushstring(vm, val.c_str(), val.length());
411 if(SQ_FAILED(sq_createslot(vm, -3)))
412 throw Scripting::SquirrelError(vm, "Couldn't add float value to table");
415 void store_bool(HSQUIRRELVM vm, const char* name, bool val)
417 sq_pushstring(vm, name, -1);
418 sq_pushbool(vm, val ? SQTrue : SQFalse);
419 if(SQ_FAILED(sq_createslot(vm, -3)))
420 throw Scripting::SquirrelError(vm, "Couldn't add float value to table");
423 bool has_float(HSQUIRRELVM vm, const char* name)
425 sq_pushstring(vm, name, -1);
426 if (SQ_FAILED(sq_get(vm, -2))) return false;
431 bool has_int(HSQUIRRELVM vm, const char* name)
433 return has_float(vm, name);
436 bool has_string(HSQUIRRELVM vm, const char* name)
438 return has_float(vm, name);
441 bool has_bool(HSQUIRRELVM vm, const char* name)
443 return has_float(vm, name);
446 float read_float(HSQUIRRELVM vm, const char* name)
448 sq_pushstring(vm, name, -1);
449 if(SQ_FAILED(sq_get(vm, -2))) {
450 std::ostringstream msg;
451 msg << "Couldn't get float value for '" << name << "' from table";
452 throw Scripting::SquirrelError(vm, msg.str());
456 if(SQ_FAILED(sq_getfloat(vm, -1, &result))) {
457 std::ostringstream msg;
458 msg << "Couldn't get float value for '" << name << "' from table";
459 throw Scripting::SquirrelError(vm, msg.str());
466 int read_int(HSQUIRRELVM vm, const char* name)
468 sq_pushstring(vm, name, -1);
469 if(SQ_FAILED(sq_get(vm, -2))) {
470 std::ostringstream msg;
471 msg << "Couldn't get int value for '" << name << "' from table";
472 throw Scripting::SquirrelError(vm, msg.str());
476 if(SQ_FAILED(sq_getinteger(vm, -1, &result))) {
477 std::ostringstream msg;
478 msg << "Couldn't get int value for '" << name << "' from table";
479 throw Scripting::SquirrelError(vm, msg.str());
487 std::string read_string(HSQUIRRELVM vm, const char* name)
489 sq_pushstring(vm, name, -1);
490 if(SQ_FAILED(sq_get(vm, -2))) {
491 std::ostringstream msg;
492 msg << "Couldn't get string value for '" << name << "' from table";
493 throw Scripting::SquirrelError(vm, msg.str());
497 if(SQ_FAILED(sq_getstring(vm, -1, &result))) {
498 std::ostringstream msg;
499 msg << "Couldn't get string value for '" << name << "' from table";
500 throw Scripting::SquirrelError(vm, msg.str());
504 return std::string(result);
507 bool read_bool(HSQUIRRELVM vm, const char* name)
509 sq_pushstring(vm, name, -1);
510 if(SQ_FAILED(sq_get(vm, -2))) {
511 std::ostringstream msg;
512 msg << "Couldn't get bool value for '" << name << "' from table";
513 throw Scripting::SquirrelError(vm, msg.str());
517 if(SQ_FAILED(sq_getbool(vm, -1, &result))) {
518 std::ostringstream msg;
519 msg << "Couldn't get bool value for '" << name << "' from table";
520 throw Scripting::SquirrelError(vm, msg.str());
524 return result == SQTrue;
527 bool get_float(HSQUIRRELVM vm, const char* name, float& val) {
528 if (!has_float(vm, name)) return false;
529 val = read_float(vm, name);
533 bool get_int(HSQUIRRELVM vm, const char* name, int& val) {
534 if (!has_int(vm, name)) return false;
535 val = read_int(vm, name);
539 bool get_string(HSQUIRRELVM vm, const char* name, std::string& val) {
540 if (!has_string(vm, name)) return false;
541 val = read_string(vm, name);
545 bool get_bool(HSQUIRRELVM vm, const char* name, bool& val) {
546 if (!has_bool(vm, name)) return false;
547 val = read_bool(vm, name);
551 // end: serialization functions