-// $Id$
-//
// SuperTux
// Copyright (C) 2006 Matthias Braun <matze@braunis.de>
//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+#include "scripting/squirrel_util.hpp"
+
#include <config.h>
-#include <stdexcept>
-#include <sstream>
-#include <stdarg.h>
-#include <squirrel.h>
-#include <sqstdmath.h>
+#include <stdio.h>
+#include <sqstdaux.h>
#include <sqstdblob.h>
+#include <sqstdmath.h>
#include <sqstdstring.h>
-#include <sqstdaux.h>
-#include <sqstdio.h>
-#include "squirrel_util.hpp"
-#include "log.hpp"
-#include "level.hpp"
-#include "physfs/physfs_stream.hpp"
-
-#ifdef ENABLE_SQDBG
-#include <sqdbg/sqrdbg.h>
-
-static HSQREMOTEDBG debugger = NULL;
-#endif
-
-namespace Scripting
-{
-
-HSQUIRRELVM global_vm = NULL;
-
-static void printfunc(HSQUIRRELVM, const char* str, ...)
-{
- char buf[4096];
- va_list arglist;
- va_start(arglist, str);
- vsprintf(buf, str, arglist);
- Console::output << (const char*) buf << std::flush;
- va_end(arglist);
-}
-
-void init_squirrel(bool enable_debugger)
-{
- global_vm = sq_open(64);
- if(global_vm == NULL)
- throw std::runtime_error("Couldn't initialize squirrel vm");
-
-#ifdef ENABLE_SQDBG
- if(enable_debugger) {
- sq_enabledebuginfo(global_vm, SQTrue);
- debugger = sq_rdbg_init(global_vm, 1234, SQFalse);
- if(debugger == NULL)
- throw SquirrelError(global_vm, "Couldn't initialize squirrel debugger");
-
- sq_enabledebuginfo(global_vm, SQTrue);
- log_info << "Waiting for debug client..." << std::endl;
- if(SQ_FAILED(sq_rdbg_waitforconnections(debugger)))
- throw SquirrelError(global_vm, "Waiting for debug clients failed");
- log_info << "debug client connected." << std::endl;
- }
-#endif
-
- sq_pushroottable(global_vm);
- if(sqstd_register_bloblib(global_vm) < 0)
- throw SquirrelError(global_vm, "Couldn't register blob lib");
- if(sqstd_register_mathlib(global_vm) < 0)
- throw SquirrelError(global_vm, "Couldn't register math lib");
- if(sqstd_register_stringlib(global_vm) < 0)
- throw SquirrelError(global_vm, "Couldn't register string lib");
- // register supertux API
- register_supertux_wrapper(global_vm);
-
- // TODO remove this at some point... it shoud just be functions not an object
- expose_object(global_vm, -1, new Scripting::Level(), "Level", true);
-
- sq_pop(global_vm, 1);
-
- // register print function
- sq_setprintfunc(global_vm, printfunc);
- // register default error handlers
- sqstd_seterrorhandlers(global_vm);
-
- // try to load default script
- try {
- std::string filename = "scripts/default.nut";
- IFileStream stream(filename);
- Scripting::compile_and_run(global_vm, stream, filename);
- } catch(std::exception& e) {
- log_warning << "Couldn't load default.nut: " << e.what() << std::endl;
- }
-}
+#include <stdarg.h>
-void exit_squirrel()
-{
-#ifdef ENABLE_SQDBG
- if(debugger != NULL) {
- sq_rdbg_shutdown(debugger);
- debugger = NULL;
- }
-#endif
- sq_close(global_vm);
- global_vm = NULL;
-}
+namespace scripting {
-void update_debugger()
-{
-#ifdef ENABLE_SQDBG
- if(debugger != NULL)
- sq_rdbg_update(debugger);
-#endif
-}
-
-std::string squirrel2string(HSQUIRRELVM v, int i)
+std::string squirrel2string(HSQUIRRELVM v, SQInteger i)
{
std::ostringstream os;
switch(sq_gettype(v, i))
- {
+ {
case OT_NULL:
- os << "<null>";
+ os << "<null>";
break;
case OT_BOOL: {
SQBool p;
- sq_getbool(v, i, &p);
- if (p)
- os << "true";
- else
- os << "false";
+ if (SQ_SUCCEEDED(sq_getbool(v, i, &p))) {
+ if (p)
+ os << "true";
+ else
+ os << "false";
+ }
break;
}
case OT_INTEGER: {
- int val;
+ SQInteger val;
sq_getinteger(v, i, &val);
os << val;
break;
}
case OT_FLOAT: {
- float val;
+ SQFloat val;
sq_getfloat(v, i, &val);
os << val;
break;
}
case OT_STRING: {
- const char* val;
+ const SQChar* val;
sq_getstring(v, i, &val);
os << "\"" << val << "\"";
- break;
+ break;
}
case OT_TABLE: {
bool first = true;
os << "{";
sq_pushnull(v); //null iterator
while(SQ_SUCCEEDED(sq_next(v,i-1)))
- {
- if (!first) {
- os << ", ";
- }
- first = false;
-
- //here -1 is the value and -2 is the key
- os << squirrel2string(v, -2) << " => "
- << squirrel2string(v, -1);
-
- sq_pop(v,2); //pops key and val before the nex iteration
+ {
+ if (!first) {
+ os << ", ";
}
+ first = false;
+
+ //here -1 is the value and -2 is the key
+ os << squirrel2string(v, -2) << " => "
+ << squirrel2string(v, -1);
+
+ sq_pop(v,2); //pops key and val before the nex iteration
+ }
sq_pop(v, 1);
os << "}";
break;
os << "[";
sq_pushnull(v); //null iterator
while(SQ_SUCCEEDED(sq_next(v,i-1)))
- {
- if (!first) {
- os << ", ";
- }
- first = false;
-
- //here -1 is the value and -2 is the key
- // we ignore the key, since that is just the index in an array
- os << squirrel2string(v, -1);
-
- sq_pop(v,2); //pops key and val before the nex iteration
+ {
+ if (!first) {
+ os << ", ";
}
+ first = false;
+
+ //here -1 is the value and -2 is the key
+ // we ignore the key, since that is just the index in an array
+ os << squirrel2string(v, -1);
+
+ sq_pop(v,2); //pops key and val before the nex iteration
+ }
sq_pop(v, 1);
os << "]";
break;
case OT_USERDATA:
os << "<userdata>";
break;
- case OT_CLOSURE:
+ case OT_CLOSURE:
os << "<closure>";
break;
case OT_NATIVECLOSURE:
default:
os << "<unknown>";
break;
- }
+ }
return os.str();
}
void print_squirrel_stack(HSQUIRRELVM v)
{
- printf("--------------------------------------------------------------\n");
- int count = sq_gettop(v);
- for(int i = 1; i <= count; ++i) {
- printf("%d: ",i);
- switch(sq_gettype(v, i))
- {
- case OT_NULL:
- printf("null");
- break;
- case OT_INTEGER: {
- int val;
- sq_getinteger(v, i, &val);
- printf("integer (%d)", val);
- break;
- }
- case OT_FLOAT: {
- float val;
- sq_getfloat(v, i, &val);
- printf("float (%f)", val);
- break;
- }
- case OT_STRING: {
- const char* val;
- sq_getstring(v, i, &val);
- printf("string (%s)", val);
- break;
- }
- case OT_TABLE:
- printf("table");
- break;
- case OT_ARRAY:
- printf("array");
- break;
- case OT_USERDATA:
- printf("userdata");
- break;
- case OT_CLOSURE:
- printf("closure(function)");
- break;
- case OT_NATIVECLOSURE:
- printf("native closure(C function)");
- break;
- case OT_GENERATOR:
- printf("generator");
- break;
- case OT_USERPOINTER:
- printf("userpointer");
- break;
- case OT_THREAD:
- printf("thread");
- break;
- case OT_CLASS:
- printf("class");
- break;
- case OT_INSTANCE:
- printf("instance");
- break;
- case OT_WEAKREF:
- printf("weakref");
- break;
- default:
- printf("unknown?!?");
- break;
- }
- printf("\n");
+ printf("--------------------------------------------------------------\n");
+ int count = sq_gettop(v);
+ for(int i = 1; i <= count; ++i) {
+ printf("%d: ",i);
+ switch(sq_gettype(v, i))
+ {
+ case OT_NULL:
+ printf("null");
+ break;
+ case OT_INTEGER: {
+ SQInteger val;
+ sq_getinteger(v, i, &val);
+ printf("integer (%d)", static_cast<int> (val));
+ break;
+ }
+ case OT_FLOAT: {
+ SQFloat val;
+ sq_getfloat(v, i, &val);
+ printf("float (%f)", val);
+ break;
+ }
+ case OT_STRING: {
+ const SQChar* val;
+ sq_getstring(v, i, &val);
+ printf("string (%s)", val);
+ break;
+ }
+ case OT_TABLE:
+ printf("table");
+ break;
+ case OT_ARRAY:
+ printf("array");
+ break;
+ case OT_USERDATA:
+ printf("userdata");
+ break;
+ case OT_CLOSURE:
+ printf("closure(function)");
+ break;
+ case OT_NATIVECLOSURE:
+ printf("native closure(C function)");
+ break;
+ case OT_GENERATOR:
+ printf("generator");
+ break;
+ case OT_USERPOINTER:
+ printf("userpointer");
+ break;
+ case OT_THREAD:
+ printf("thread");
+ break;
+ case OT_CLASS:
+ printf("class");
+ break;
+ case OT_INSTANCE:
+ printf("instance");
+ break;
+ case OT_WEAKREF:
+ printf("weakref");
+ break;
+ default:
+ printf("unknown?!?");
+ break;
}
- printf("--------------------------------------------------------------\n");
+ printf("\n");
+ }
+ printf("--------------------------------------------------------------\n");
}
-static SQInteger squirrel_read_char(SQUserPointer file)
+SQInteger squirrel_read_char(SQUserPointer file)
{
std::istream* in = reinterpret_cast<std::istream*> (file);
- char c = in->get();
+ int c = in->get();
if(in->eof())
return 0;
return c;
void compile_script(HSQUIRRELVM vm, std::istream& in, const std::string& sourcename)
{
if(SQ_FAILED(sq_compile(vm, squirrel_read_char, &in, sourcename.c_str(), true)))
- throw SquirrelError(vm, "Couldn't parse script");
+ throw SquirrelError(vm, "Couldn't parse script");
}
void compile_and_run(HSQUIRRELVM vm, std::istream& in,
const std::string& sourcename)
{
compile_script(vm, in, sourcename);
-
- int oldtop = sq_gettop(vm);
+
+ SQInteger oldtop = sq_gettop(vm);
try {
sq_pushroottable(vm);
if(SQ_FAILED(sq_getstackobj(vm, -1, &vm_object)))
throw SquirrelError(vm, "Couldn't get squirrel thread from stack");
sq_addref(vm, &vm_object);
-
+
sq_pop(vm, 1);
return vm_object;
return object._unVal.pThread;
}
+// begin: serialization functions
+
+void store_float(HSQUIRRELVM vm, const char* name, float val)
+{
+ sq_pushstring(vm, name, -1);
+ sq_pushfloat(vm, val);
+ if(SQ_FAILED(sq_createslot(vm, -3)))
+ throw scripting::SquirrelError(vm, "Couldn't add float value to table");
+}
+
+void store_int(HSQUIRRELVM vm, const char* name, int val)
+{
+ sq_pushstring(vm, name, -1);
+ sq_pushinteger(vm, val);
+ if(SQ_FAILED(sq_createslot(vm, -3)))
+ throw scripting::SquirrelError(vm, "Couldn't add int value to table");
+}
+
+void store_string(HSQUIRRELVM vm, const char* name, const std::string& val)
+{
+ sq_pushstring(vm, name, -1);
+ sq_pushstring(vm, val.c_str(), val.length());
+ if(SQ_FAILED(sq_createslot(vm, -3)))
+ throw scripting::SquirrelError(vm, "Couldn't add float value to table");
+}
+
+void store_bool(HSQUIRRELVM vm, const char* name, bool val)
+{
+ sq_pushstring(vm, name, -1);
+ sq_pushbool(vm, val ? SQTrue : SQFalse);
+ if(SQ_FAILED(sq_createslot(vm, -3)))
+ throw scripting::SquirrelError(vm, "Couldn't add float value to table");
+}
+
+bool has_float(HSQUIRRELVM vm, const char* name)
+{
+ sq_pushstring(vm, name, -1);
+ if (SQ_FAILED(sq_get(vm, -2))) return false;
+ sq_pop(vm, 1);
+ return true;
+}
+
+bool has_int(HSQUIRRELVM vm, const char* name)
+{
+ return has_float(vm, name);
+}
+
+bool has_string(HSQUIRRELVM vm, const char* name)
+{
+ return has_float(vm, name);
+}
+
+bool has_bool(HSQUIRRELVM vm, const char* name)
+{
+ return has_float(vm, name);
+}
+
+float read_float(HSQUIRRELVM vm, const char* name)
+{
+ sq_pushstring(vm, name, -1);
+ if(SQ_FAILED(sq_get(vm, -2))) {
+ std::ostringstream msg;
+ msg << "Couldn't get float value for '" << name << "' from table";
+ throw scripting::SquirrelError(vm, msg.str());
+ }
+
+ float result;
+ if(SQ_FAILED(sq_getfloat(vm, -1, &result))) {
+ std::ostringstream msg;
+ msg << "Couldn't get float value for '" << name << "' from table";
+ throw scripting::SquirrelError(vm, msg.str());
+ }
+ sq_pop(vm, 1);
+
+ return result;
+}
+
+int read_int(HSQUIRRELVM vm, const char* name)
+{
+ sq_pushstring(vm, name, -1);
+ if(SQ_FAILED(sq_get(vm, -2))) {
+ std::ostringstream msg;
+ msg << "Couldn't get int value for '" << name << "' from table";
+ throw scripting::SquirrelError(vm, msg.str());
+ }
+
+ SQInteger result;
+ if(SQ_FAILED(sq_getinteger(vm, -1, &result))) {
+ std::ostringstream msg;
+ msg << "Couldn't get int value for '" << name << "' from table";
+ throw scripting::SquirrelError(vm, msg.str());
+ }
+ sq_pop(vm, 1);
+
+ return result;
}
+
+std::string read_string(HSQUIRRELVM vm, const char* name)
+{
+ sq_pushstring(vm, name, -1);
+ if(SQ_FAILED(sq_get(vm, -2))) {
+ std::ostringstream msg;
+ msg << "Couldn't get string value for '" << name << "' from table";
+ throw scripting::SquirrelError(vm, msg.str());
+ }
+
+ const char* result;
+ if(SQ_FAILED(sq_getstring(vm, -1, &result))) {
+ std::ostringstream msg;
+ msg << "Couldn't get string value for '" << name << "' from table";
+ throw scripting::SquirrelError(vm, msg.str());
+ }
+ sq_pop(vm, 1);
+
+ return std::string(result);
+}
+
+bool read_bool(HSQUIRRELVM vm, const char* name)
+{
+ sq_pushstring(vm, name, -1);
+ if(SQ_FAILED(sq_get(vm, -2))) {
+ std::ostringstream msg;
+ msg << "Couldn't get bool value for '" << name << "' from table";
+ throw scripting::SquirrelError(vm, msg.str());
+ }
+
+ SQBool result;
+ if(SQ_FAILED(sq_getbool(vm, -1, &result))) {
+ std::ostringstream msg;
+ msg << "Couldn't get bool value for '" << name << "' from table";
+ throw scripting::SquirrelError(vm, msg.str());
+ }
+ sq_pop(vm, 1);
+
+ return result == SQTrue;
+}
+
+bool get_float(HSQUIRRELVM vm, const char* name, float& val) {
+ if (!has_float(vm, name)) return false;
+ val = read_float(vm, name);
+ return true;
+}
+
+bool get_int(HSQUIRRELVM vm, const char* name, int& val) {
+ if (!has_int(vm, name)) return false;
+ val = read_int(vm, name);
+ return true;
+}
+
+bool get_string(HSQUIRRELVM vm, const char* name, std::string& val) {
+ if (!has_string(vm, name)) return false;
+ val = read_string(vm, name);
+ return true;
+}
+
+bool get_bool(HSQUIRRELVM vm, const char* name, bool& val) {
+ if (!has_bool(vm, name)) return false;
+ val = read_bool(vm, name);
+ return true;
+}
+
+// end: serialization functions
+
+}
+
+/* EOF */