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"
36 #include <sqdbg/sqrdbg.h>
38 static HSQREMOTEDBG debugger = NULL;
44 HSQUIRRELVM global_vm = NULL;
46 static void printfunc(HSQUIRRELVM, const char* str, ...)
50 va_start(arglist, str);
51 vsprintf(buf, str, arglist);
52 Console::output << (const char*) buf << std::flush;
56 void init_squirrel(bool enable_debugger)
58 global_vm = sq_open(64);
60 throw std::runtime_error("Couldn't initialize squirrel vm");
64 sq_enabledebuginfo(global_vm, SQTrue);
65 debugger = sq_rdbg_init(global_vm, 1234, SQFalse);
67 throw SquirrelError(global_vm, "Couldn't initialize squirrel debugger");
69 sq_enabledebuginfo(global_vm, SQTrue);
70 log_info << "Waiting for debug client..." << std::endl;
71 if(SQ_FAILED(sq_rdbg_waitforconnections(debugger)))
72 throw SquirrelError(global_vm, "Waiting for debug clients failed");
73 log_info << "debug client connected." << std::endl;
77 sq_pushroottable(global_vm);
78 if(sqstd_register_bloblib(global_vm) < 0)
79 throw SquirrelError(global_vm, "Couldn't register blob lib");
80 if(sqstd_register_mathlib(global_vm) < 0)
81 throw SquirrelError(global_vm, "Couldn't register math lib");
82 if(sqstd_register_stringlib(global_vm) < 0)
83 throw SquirrelError(global_vm, "Couldn't register string lib");
84 // register supertux API
85 register_supertux_wrapper(global_vm);
87 // TODO remove this at some point... it shoud just be functions not an object
88 expose_object(global_vm, -1, new Scripting::Level(), "Level", true);
92 // register print function
93 sq_setprintfunc(global_vm, printfunc);
94 // register default error handlers
95 sqstd_seterrorhandlers(global_vm);
97 // try to load default script
99 std::string filename = "scripts/default.nut";
100 IFileStream stream(filename);
101 Scripting::compile_and_run(global_vm, stream, filename);
102 } catch(std::exception& e) {
103 log_warning << "Couldn't load default.nut: " << e.what() << std::endl;
110 if(debugger != NULL) {
111 sq_rdbg_shutdown(debugger);
119 void update_debugger()
123 sq_rdbg_update(debugger);
127 std::string squirrel2string(HSQUIRRELVM v, int i)
129 std::ostringstream os;
130 switch(sq_gettype(v, i))
137 sq_getbool(v, i, &p);
146 sq_getinteger(v, i, &val);
152 sq_getfloat(v, i, &val);
158 sq_getstring(v, i, &val);
159 os << "\"" << val << "\"";
165 sq_pushnull(v); //null iterator
166 while(SQ_SUCCEEDED(sq_next(v,i-1)))
173 //here -1 is the value and -2 is the key
174 os << squirrel2string(v, -2) << " => "
175 << squirrel2string(v, -1);
177 sq_pop(v,2); //pops key and val before the nex iteration
186 sq_pushnull(v); //null iterator
187 while(SQ_SUCCEEDED(sq_next(v,i-1)))
194 //here -1 is the value and -2 is the key
195 // we ignore the key, since that is just the index in an array
196 os << squirrel2string(v, -1);
198 sq_pop(v,2); //pops key and val before the nex iteration
210 case OT_NATIVECLOSURE:
211 os << "<native closure>";
238 void print_squirrel_stack(HSQUIRRELVM v)
240 printf("--------------------------------------------------------------\n");
241 int count = sq_gettop(v);
242 for(int i = 1; i <= count; ++i) {
244 switch(sq_gettype(v, i))
251 sq_getinteger(v, i, &val);
252 printf("integer (%d)", val);
257 sq_getfloat(v, i, &val);
258 printf("float (%f)", val);
263 sq_getstring(v, i, &val);
264 printf("string (%s)", val);
277 printf("closure(function)");
279 case OT_NATIVECLOSURE:
280 printf("native closure(C function)");
286 printf("userpointer");
301 printf("unknown?!?");
306 printf("--------------------------------------------------------------\n");
309 static SQInteger squirrel_read_char(SQUserPointer file)
311 std::istream* in = reinterpret_cast<std::istream*> (file);
318 void compile_script(HSQUIRRELVM vm, std::istream& in, const std::string& sourcename)
320 if(SQ_FAILED(sq_compile(vm, squirrel_read_char, &in, sourcename.c_str(), true)))
321 throw SquirrelError(vm, "Couldn't parse script");
324 void compile_and_run(HSQUIRRELVM vm, std::istream& in,
325 const std::string& sourcename)
327 compile_script(vm, in, sourcename);
329 int oldtop = sq_gettop(vm);
332 sq_pushroottable(vm);
333 if(SQ_FAILED(sq_call(vm, 1, SQFalse, SQTrue)))
334 throw SquirrelError(vm, "Couldn't start script");
336 sq_settop(vm, oldtop);
340 // we can remove the closure in case the script was not suspended
341 if(sq_getvmstate(vm) != SQ_VMSTATE_SUSPENDED) {
342 sq_settop(vm, oldtop-1);
346 HSQOBJECT create_thread(HSQUIRRELVM vm)
348 HSQUIRRELVM new_vm = sq_newthread(vm, 64);
350 throw SquirrelError(vm, "Couldn't create new VM");
353 sq_resetobject(&vm_object);
354 if(SQ_FAILED(sq_getstackobj(vm, -1, &vm_object)))
355 throw SquirrelError(vm, "Couldn't get squirrel thread from stack");
356 sq_addref(vm, &vm_object);
363 HSQOBJECT vm_to_object(HSQUIRRELVM vm)
366 sq_resetobject(&object);
367 object._unVal.pThread = vm;
368 object._type = OT_THREAD;
373 HSQUIRRELVM object_to_vm(HSQOBJECT object)
375 if(object._type != OT_THREAD)
378 return object._unVal.pThread;