src/squirrel.cpp
author truelight
Thu, 15 Mar 2007 22:22:51 +0000
branchnoai
changeset 9426 b90c0d1a36b7
parent 9422 33efcc5f1b09
child 9434 2e71647c2c1c
permissions -rw-r--r--
(svn r9229) [NoAI] -Change: move more header-mess from .hpp to .cpp
/* $Id$ */

/** @file squirrel.cpp the implementation of the Squirrel class. It handles all Squirrel-stuff and gives a nice API back to work with. */

#ifdef _UNICODE
/* Disable unicode for squirrel to allow compilation with MINGW
 * and simplify coding for WIN32 (squirrel headers miss a lot of "string" functions)
 */
#undef _UNICODE
#endif
#include <squirrel.h>
#include <sqstdio.h>
#include <stdarg.h>
#include "stdafx.h"
#include "debug.h"
#include "squirrel.hpp"

void Squirrel::CompileError(HSQUIRRELVM vm, const SQChar *desc, const SQChar *source, SQInteger line, SQInteger column)
{
#ifdef _SQ64
	printf("Error %s:%ld/%ld: %s\n", source, line, column, desc);
#else
	printf("Error %s:%d/%d: %s\n", source, line, column, desc);
#endif
}

void Squirrel::RunError(HSQUIRRELVM vm, const char *error)
{
	printf("%s\n", error);
}

SQInteger Squirrel::_RunError(HSQUIRRELVM vm)
{
	const SQChar *sErr = 0;

	if (sq_gettop(vm) >= 1) {
		if (SQ_SUCCEEDED(sq_getstring(vm, -1, &sErr))) {
			Squirrel::RunError(vm, sErr);
		}
	}

	Squirrel::RunError(vm, "Unknown error");
	return 0;
}

void Squirrel::PrintFunc(HSQUIRRELVM vm, const SQChar *s, ...)
{
	va_list arglist;
	va_start(arglist, s);
	vprintf(s, arglist);
	va_end(arglist);
	printf("\n");
}

void Squirrel::AddMethod(const char *method_name, SQFUNCTION proc, uint nparam, const char *params)
{
	sq_pushstring(this->vm, method_name, -1);
	sq_newclosure(this->vm, proc, 0);
	sq_setparamscheck(this->vm, nparam, params);
	sq_setnativeclosurename(this->vm, -1, method_name);
	sq_createslot(this->vm, -3);
}

void Squirrel::AddMethod(const char *method_name, SQFUNCTION proc)
{
	sq_pushstring(this->vm, method_name, -1);
	sq_newclosure(this->vm, proc, 0);
	sq_setnativeclosurename(this->vm, -1, method_name);
	sq_createslot(this->vm, -3);
}

void Squirrel::AddMethod(const char *method_name, SQFUNCTION proc, void *userdata, int size)
{
	sq_pushstring(this->vm, method_name, -1);

	void *ptr;
	ptr = sq_newuserdata(vm, size);
	memcpy(ptr, userdata, size);

	sq_newclosure(this->vm, proc, 1);
	sq_setnativeclosurename(this->vm, -1, method_name);
	sq_createslot(this->vm, -3);
}

void Squirrel::AddClassBegin(const char *class_name)
{
	sq_pushroottable(this->vm);
	sq_pushstring(this->vm, class_name, -1);
	sq_newclass(this->vm, SQFalse);
}

void Squirrel::AddClassEnd()
{
	sq_createslot(vm, -3);
}

bool Squirrel::MethodExists(HSQOBJECT instance, const char *method_name)
{
	int top = sq_gettop(this->vm);
	/* Go to the instance-root */
	sq_pushobject(this->vm, instance);
	/* Find the function-name inside the script */
	sq_pushstring(this->vm, method_name, -1);
	if (SQ_FAILED(sq_get(this->vm, -2))) {
		sq_settop(this->vm, top);
		return false;
	}
	sq_settop(this->vm, top);
	return true;
}

void Squirrel::CallMethod(HSQOBJECT instance, const char *method_name, HSQOBJECT *ret)
{
	/* Store the current top */
	int top = sq_gettop(this->vm);
	/* Go to the instance-root */
	sq_pushobject(this->vm, instance);
	/* Find the function-name inside the script */
	sq_pushstring(this->vm, method_name, -1);
	if (SQ_FAILED(sq_get(this->vm, -2))) {
		DEBUG(misc, 0, "[squirrel] Could not find '%s' in the class", method_name);
		sq_settop(this->vm, top);
		return;
	}
	/* Call the method */
	sq_pushobject(this->vm, instance);
	sq_call(this->vm, 1, ret == NULL ? SQFalse : SQTrue, SQFalse);
	if (ret != NULL) sq_getstackobj(vm, -1, ret);
	/* Reset the top */
	sq_settop(this->vm, top);
}

bool Squirrel::CreateClassInstance(const char *class_name, void *real_instance, HSQOBJECT *instance)
{
	int oldtop = sq_gettop(this->vm);

	/* First, find the class */
	sq_pushroottable(this->vm);
	sq_pushstring(this->vm, class_name, -1);
	if (SQ_FAILED(sq_get(this->vm, -2))) {
		DEBUG(misc, 0, "[squirrel] Failed to find class by the name '%s'", class_name);
		sq_settop(this->vm, oldtop);
		return false;
	}

	/* Create the instance */
	if (SQ_FAILED(sq_createinstance(this->vm, -1))) {
		DEBUG(misc, 0, "[squirrel] Failed to create instance for class '%s'", class_name);
		sq_settop(this->vm, oldtop);
		return false;
	}

	if (instance != NULL) {
		/* Find our instance */
		sq_getstackobj(this->vm, -1, instance);
		/* Add a reference to it, so it survives for ever */
		sq_addref(this->vm, instance);
	}
	/* Store it in the class */
	sq_setinstanceup(this->vm, -1, real_instance);

	/* Reset the top */
	sq_settop(this->vm, oldtop);

	return true;
}

Squirrel::Squirrel()
{
	this->vm = sq_open(1024);

	/* Handle compile-errors ourself, so we can display it nicely */
	sq_setcompilererrorhandler(this->vm, &Squirrel::CompileError);
	sq_notifyallexceptions(this->vm, SQTrue);
	/* Set a good print-function */
	sq_setprintfunc(this->vm, &Squirrel::PrintFunc);
	/* Handle runtime-errors ourself, so we can display it nicely */
	sq_newclosure(this->vm, &Squirrel::_RunError, 0);
	sq_seterrorhandler(this->vm);

	sq_pushroottable(this->vm);
}

bool Squirrel::LoadScript(const char *script)
{
	/* Load and run the script */
	if (SQ_FAILED(sqstd_dofile(this->vm, script, SQFalse, SQTrue))) {
		DEBUG(misc, 0, "[squirrel] Failed to compile '%s'", script);
		return false;
	}

	return true;
}

Squirrel::~Squirrel()
{
	/* Clean up the stuff */
	sq_pop(this->vm, 1);
	sq_close(this->vm);
}