1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2025-06-16 07:07:13 +02:00

Added external Sqrat library.

This commit is contained in:
Sandu Liviu Catalin
2015-11-01 10:06:54 +02:00
parent c3b811cfff
commit 08f7f396c9
24 changed files with 20311 additions and 0 deletions

20
external/Sqrat/License.txt vendored Normal file
View File

@ -0,0 +1,20 @@
Copyright (c) 2009 Brandon Jones
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.

373
external/Sqrat/sqratThread.cpp vendored Normal file
View File

@ -0,0 +1,373 @@
//
// SqratThread: Sqrat threading module
//
//
// Copyright (c) 2009 Brandon Jones
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//#include "sqratlib/sqratBase.h"
#include "sqratThread.h"
#include <time.h>
#include <string.h>
static HSQAPI sq;
//
// Thread lib utility functions (not visible externally)
//
static SQFloat sqrat_clock() {
return ((SQFloat)clock())/(SQFloat)CLOCKS_PER_SEC;
}
static SQInteger sqrat_strlen(const SQChar* str) {
#if defined(_UNICODE)
return static_cast<SQInteger>(wcslen(str) * sizeof(SQChar));
#else
return static_cast<SQInteger>(strlen(str) * sizeof(SQChar));
#endif
}
static void sqrat_pushtaskarray(HSQUIRRELVM v) {
HSQOBJECT taskarray;
sq->pushroottable(v);
sq->pushstring(v,_SC("__sqrat_taskarray__"),-1);
if(SQ_FAILED(sq->get(v, -2))) {
// Not found, create a new namespace
sq->pushstring(v,_SC("__sqrat_taskarray__"),-1);
sq->newarray(v, 0);
sq->getstackobj(v,-1,&taskarray); // Save namespace for later use
sq->newslot(v, -3, 0);
sq->pop(v, 1); // pop root table
sq->pushobject(v, taskarray); // push the newly bound array
} else {
sq->remove(v, -2); // pop sqrat table
}
}
static SQRESULT sqrat_pushclosure(HSQUIRRELVM v, const SQChar* script) {
if(SQ_FAILED(sq->compilebuffer(v, script, sqrat_strlen(script), _SC(""), true))) {
return SQ_ERROR;
}
sq->pushroottable(v);
if(SQ_FAILED(sq->call(v, 1, 0, 1))) {
sq->remove(v, -1); // remove compiled closure
return SQ_ERROR;
}
sq->remove(v, -2); // remove compiled closure
return SQ_OK;
}
static SQInteger sqrat_schedule_argcall(HSQUIRRELVM v) {
SQInteger nparams = sq->gettop(v) - 2; // Get the number of parameters provided
// The task table is the last argument (free variable), so we can operate on immediately
sq->pushstring(v, _SC("args"), -1);
sq->newarray(v, 0); // Create the array for the arguments
// Loop through all arguments and push them into the arg array
for(SQInteger i = 0; i < nparams; ++i) {
sq->push(v, i+2);
sq->arrayappend(v, -2);
}
sq->newslot(v, -3, 0); // Push the arg array into the task table
return 0;
}
// This is a horrid way to get this functionality in there, but I can't find any alternatives right now.
static SQRESULT sqrat_pushsleep(HSQUIRRELVM v) {
SQChar* sleep_script = _SC(" \
__sqratsleep__ <- function(timeout) { \
local begin = clock(); \
local now; \
do { \
::suspend(); \
now = clock(); \
} while( (now - begin) < timeout ); \
} \
");
if(SQ_FAILED(sq->compilebuffer(v, sleep_script, sqrat_strlen(sleep_script), _SC(""), true))) {
return SQ_ERROR;
}
sq->pushroottable(v);
if(SQ_FAILED(sq->call(v, 1, 0, 1))) {
sq->remove(v, -1); // remove compiled closure
return SQ_ERROR;
}
sq->remove(v, -1); // remove compiled closure
sq->pushroottable(v);
sq->pushstring(v, _SC("__sqratsleep__"), -1);
SQRESULT res = sq->get(v, -2);
sq->remove(v, -2); // remove root table
return res;
}
//
// Thread lib main functions
//
static SQRESULT sqrat_sleep(HSQUIRRELVM v, SQFloat timeout) {
return sq->suspendvm(v);
// Get "::suspend"
/*HSQOBJECT suspend;
sq->pushroottable(v);
sq->pushstring(v, _SC("suspend"), -1);
if(SQ_FAILED(sq->get(v, -2))) {
return SQ_ERROR;
}
sq->getstackobj(v, -1, &suspend);
sq->pop(v, 2);
// Loop ::suspend until the appropriate time has passed
SQFloat timeStart = sqrat_clock();
SQFloat timeNow = 0;
while(timeNow - timeStart < timeout) {
sq->pushobject(v, suspend);
sq->pushroottable(v);
if(SQ_FAILED(sq->call(v, 1, 0, 1))) {
return SQ_ERROR;
}
timeNow = sqrat_clock();
}
return SQ_OK;*/
}
static void sqrat_schedule(HSQUIRRELVM v, SQInteger idx) {
HSQOBJECT thread;
HSQOBJECT func;
HSQOBJECT task;
sq->getstackobj(v, idx, &func);
SQInteger stksize = 256; // TODO: Allow initial stack size to be configurable
sqrat_pushtaskarray(v); // Push the task array
// Create the task
sq->newtable(v);
sq->getstackobj(v, -1, &task);
// Create the thread and add it to the task table
sq->pushstring(v, _SC("thread"), -1);
sq->newthread(v, stksize);
sq->getstackobj(v, -1, &thread);
sq->newslot(v, -3, 0);
// Push the function to be called onto the thread stack
sq->pushobject(v, func);
sq->move(thread._unVal.pThread, v, -1);
sq->pop(v, 1);
// Args will be pushed later, in the closure
sq->arrayappend(v, -2); // Add the task to the task array
sq->pushobject(v, task); // Push the task object as a free variable for the temporary closure
sq->newclosure(v, sqrat_schedule_argcall, 1); // push a temporary closure used to retrieve call args
}
// Wow... this has to be one of the ugliest functions I've ever writter. Ever.
// Building complex logic with the squirrel stack really sucks.
static void sqrat_run(HSQUIRRELVM v) {
HSQOBJECT taskArray;
HSQOBJECT thread;
HSQUIRRELVM threadVm;
SQInteger nparams; // Number of parameters to pass to a function
SQInteger arrayidx; //Cached index of the task array
// Push the tasklist
sqrat_pushtaskarray(v); // Push the task array to the stack
sq->getstackobj(v, -1, &taskArray);
arrayidx = sq->gettop(v); // Cache the stack location of the task array
SQInteger tasklistSize = sq->getsize(v, arrayidx); // Query the initial size of the task array
do {
SQInteger i = 0;
// This outer while is to allow us to pick up any new tasks that are added during the loop,
// but still give us an opportunity to sleep after running through the initial tasks
while(i < tasklistSize) {
for(; i < tasklistSize; ++i) {
sq->pushinteger(v, i);
if(SQ_FAILED(sq->get(v, -2))) { // Get the task
sq->arrayremove(v, -2, i);
sq->pop(v, 1);
--tasklistSize;
--i;
continue;
}
// Now that we have the task, get the thread
sq->pushstring(v, _SC("thread"), -1);
if(SQ_FAILED(sq->get(v, -2))) {
sq->arrayremove(v, -3, i);
sq->pop(v, 1);
--tasklistSize;
--i;
continue;
}
sq->getstackobj(v, -1, &thread);
sq->pop(v, 1);
threadVm = thread._unVal.pThread;
if(sq->getvmstate(threadVm) == SQ_VMSTATE_IDLE) { // New thread? If so we need to call it
// Function to be called is already pushed to the thread (happens in schedule)
sq->pushroottable(threadVm); // Pus the threads root table
sq->pushstring(v, _SC("args"), -1);
if(SQ_FAILED(sq->get(v, -2))) { // Check to see if we have arguments for this thread
nparams = 0; // No arguments
} else {
nparams = sq->getsize(v, -1); // Get the number of args in the arg array
// Push the arguments onto the thread stack
for(SQInteger a = 0; a < nparams; ++a) {
sq->pushinteger(v, a);
if(SQ_FAILED(sq->get(v, -2))) {
sq->pushnull(threadVm); // Is this the best way to handle this?
} else {
sq->move(threadVm, v, -1);
sq->pop(v, 1);
}
}
sq->pop(v, 1); // Pop the arg array
}
sq->call(threadVm, nparams+1, 0, 1); // Call the thread
} else {
// If the thread is suspended, wake it up.
// This function changed in Squirrel 2.2.3,
// removing the last parameter makes it compatible with 2.2.2 and earlier
sq->wakeupvm(threadVm, 0, 0, 1, 0);
}
if(sq->getvmstate(threadVm) == SQ_VMSTATE_IDLE) { // Check to see if the thread is finished (idle again)
sq->arrayremove(v, -2, i); // Remove the task from the task array
--tasklistSize; // Adjust the for variables to account for the removal
--i;
}
sq->pop(v, 1); // Pop off the task
}
// Yield to system if needed
tasklistSize = sq->getsize(v, arrayidx); // Get the task
}
} while(tasklistSize > 0); // Loop until we have no more pending tasks
}
//
// Script interface functions
//
static SQInteger sqratbase_sleep(HSQUIRRELVM v) {
SQFloat timeout;
sq->getfloat(v, -1, &timeout);
sqrat_sleep(v, timeout);
return 0;
}
static SQInteger sqratbase_schedule(HSQUIRRELVM v) {
sqrat_schedule(v, -1);
return 1;
}
static SQInteger sqratbase_run(HSQUIRRELVM v) {
sqrat_run(v);
return 0;
}
// This is a squirrel only function, since there's really no need to
// expose a native api for it. Just use the VM that you would have passed
// in anyway!
static SQInteger sqratbase_getthread(HSQUIRRELVM v) {
// For the record, this way of doing things really sucks.
// I would love a better way of retrieving this object!
HSQOBJECT threadObj;
threadObj._type = OT_THREAD;
threadObj._unVal.pThread = v;
sq->pushobject(v, threadObj);
sq->weakref(v, -1);
sq->remove(v, -2);
return 1;
}
//
// Module registration
//
SQRESULT sqmodule_load(HSQUIRRELVM v, HSQAPI api) {
sq = api;
sq->pushstring(v, _SC("schedule"), -1);
sq->newclosure(v, &sqratbase_schedule, 0);
sq->newslot(v, -3, 0);
sq->pushstring(v, _SC("run"), -1);
sq->newclosure(v, &sqratbase_run, 0);
sq->newslot(v, -3, 0);
sq->pushstring(v, _SC("getthread"), -1);
sq->newclosure(v, &sqratbase_getthread, 0);
sq->newslot(v, -3, 0);
// Would rather do this...
/*sq->pushstring(v, _SC("sleep"), -1);
sq->newclosure(v, &sqratbase_sleep, 0);
sq->newslot(v, -3, 0);*/
// Than this...
sq->pushstring(v, _SC("sleep"), -1);
if(SQ_FAILED(sqrat_pushsleep(v))) {
sq->pop(v, 1);
} else {
sq->newslot(v, -3, 0);
}
return SQ_OK;
}

308
external/Sqrat/sqratimport.cpp vendored Normal file
View File

@ -0,0 +1,308 @@
//
// SqratImport: Supports importing of squirrel modules
//
//
// Copyright (c) 2009 Brandon Jones
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
#include "sqratimport.h"
#include "sqmodule.h"
//#include "sqratlib/sqratBase.h"
#include <sqstdio.h>
#include <string>
#if defined(_WIN32)
#include <windows.h>
#elif defined(__unix)
#include <dlfcn.h>
#endif
typedef SQRESULT (*SQMODULELOAD)(HSQUIRRELVM v, HSQAPI sq);
static HSQAPI sqapi = NULL;
// Create and populate the HSQAPI structure with function pointers
// If new functions are added to the Squirrel API, they should be added here too
static HSQAPI sqrat_newapi() {
HSQAPI sq = (HSQAPI)sq_malloc(sizeof(sq_api));
/*vm*/
sq->open = sq_open;
sq->newthread = sq_newthread;
sq->seterrorhandler = sq_seterrorhandler;
sq->close = sq_close;
sq->setforeignptr = sq_setforeignptr;
sq->getforeignptr = sq_getforeignptr;
sq->setprintfunc = sq_setprintfunc;
sq->getprintfunc = sq_getprintfunc;
sq->suspendvm = sq_suspendvm;
sq->wakeupvm = sq_wakeupvm;
sq->getvmstate = sq_getvmstate;
/*compiler*/
sq->compile = sq_compile;
sq->compilebuffer = sq_compilebuffer;
sq->enabledebuginfo = sq_enabledebuginfo;
sq->notifyallexceptions = sq_notifyallexceptions;
sq->setcompilererrorhandler = sq_setcompilererrorhandler;
/*stack operations*/
sq->push = sq_push;
sq->pop = sq_pop;
sq->poptop = sq_poptop;
sq->remove = sq_remove;
sq->gettop = sq_gettop;
sq->settop = sq_settop;
sq->reservestack = sq_reservestack;
sq->cmp = sq_cmp;
sq->move = sq_move;
/*object creation handling*/
sq->newuserdata = sq_newuserdata;
sq->newtable = sq_newtable;
sq->newarray = sq_newarray;
sq->newclosure = sq_newclosure;
sq->setparamscheck = sq_setparamscheck;
sq->bindenv = sq_bindenv;
sq->pushstring = sq_pushstring;
sq->pushfloat = sq_pushfloat;
sq->pushinteger = sq_pushinteger;
sq->pushbool = sq_pushbool;
sq->pushuserpointer = sq_pushuserpointer;
sq->pushnull = sq_pushnull;
sq->gettype = sq_gettype;
sq->getsize = sq_getsize;
sq->getbase = sq_getbase;
sq->instanceof = sq_instanceof;
sq->tostring = sq_tostring;
sq->tobool = sq_tobool;
sq->getstring = sq_getstring;
sq->getinteger = sq_getinteger;
sq->getthread = sq_getthread;
sq->getbool = sq_getbool;
sq->getuserpointer = sq_getuserpointer;
sq->getuserdata = sq_getuserdata;
sq->settypetag = sq_settypetag;
sq->gettypetag = sq_gettypetag;
sq->setreleasehook = sq_setreleasehook;
sq->getscratchpad = sq_getscratchpad;
sq->getclosureinfo = sq_getclosureinfo;
sq->setnativeclosurename = sq_setnativeclosurename;
sq->setinstanceup = sq_setinstanceup;
sq->getinstanceup = sq_getinstanceup;
sq->setclassudsize = sq_setclassudsize;
sq->newclass = sq_newclass;
sq->createinstance = sq_createinstance;
sq->setattributes = sq_setattributes;
sq->getattributes = sq_getattributes;
sq->getclass = sq_getclass;
sq->weakref = sq_weakref;
sq->getdefaultdelegate = sq_getdefaultdelegate;
/*object manipulation*/
sq->pushroottable = sq_pushroottable;
sq->pushregistrytable = sq_pushregistrytable;
sq->pushconsttable = sq_pushconsttable;
sq->setroottable = sq_setroottable;
sq->setconsttable = sq_setconsttable;
sq->newslot = sq_newslot;
sq->deleteslot = sq_deleteslot;
sq->set = sq_set;
sq->get = sq_get;
sq->rawset = sq_rawset;
sq->rawget = sq_rawget;
sq->rawdeleteslot = sq_rawdeleteslot;
sq->arrayappend = sq_arrayappend;
sq->arraypop = sq_arraypop;
sq->arrayresize = sq_arrayresize;
sq->arrayreverse = sq_arrayreverse;
sq->arrayremove = sq_arrayremove;
sq->arrayinsert = sq_arrayinsert;
sq->setdelegate = sq_setdelegate;
sq->getdelegate = sq_getdelegate;
sq->clone = sq_clone;
sq->setfreevariable = sq_setfreevariable;
sq->next = sq_next;
sq->getweakrefval = sq_getweakrefval;
sq->clear = sq_clear;
/*calls*/
sq->call = sq_call;
sq->resume = sq_resume;
sq->getlocal = sq_getlocal;
sq->getfreevariable = sq_getfreevariable;
sq->throwerror = sq_throwerror;
sq->reseterror = sq_reseterror;
sq->getlasterror = sq_getlasterror;
/*raw object handling*/
sq->getstackobj = sq_getstackobj;
sq->pushobject = sq_pushobject;
sq->addref = sq_addref;
sq->release = sq_release;
sq->resetobject = sq_resetobject;
sq->objtostring = sq_objtostring;
sq->objtobool = sq_objtobool;
sq->objtointeger = sq_objtointeger;
sq->objtofloat = sq_objtofloat;
sq->getobjtypetag = sq_getobjtypetag;
/*GC*/
sq->collectgarbage = sq_collectgarbage;
/*serialization*/
sq->writeclosure = sq_writeclosure;
sq->readclosure = sq_readclosure;
/*mem allocation*/
sq->malloc = sq_malloc;
sq->realloc = sq_realloc;
sq->free = sq_free;
/*debug*/
sq->stackinfos = sq_stackinfos;
sq->setdebughook = sq_setdebughook;
return sq;
}
static SQRESULT sqrat_importscript(HSQUIRRELVM v, const SQChar* moduleName) {
std::basic_string<SQChar> filename(moduleName);
filename += _SC(".nut");
if(SQ_FAILED(sqstd_loadfile(v, moduleName, true))) {
if(SQ_FAILED(sqstd_loadfile(v, filename.c_str(), true))) {
return SQ_ERROR;
}
}
sq_push(v, -2);
sq_call(v, 1, false, true);
return SQ_OK;
}
static SQRESULT sqrat_importbin(HSQUIRRELVM v, const SQChar* moduleName) {
#ifdef SQUNICODE
#warning sqrat_importbin() Not Implemented
return SQ_ERROR;
#else
SQMODULELOAD modLoad = 0;
#if defined(_WIN32)
HMODULE mod;
mod = GetModuleHandle(moduleName);
if(mod == NULL) {
mod = LoadLibrary(moduleName);
if(mod == NULL) {
return SQ_ERROR;
}
}
modLoad = (SQMODULELOAD)GetProcAddress(mod, "sqmodule_load");
if(modLoad == NULL) {
FreeLibrary(mod);
return SQ_ERROR;
}
#elif defined(__unix)
/* adding .so to moduleName? */
void *mod = dlopen(moduleName, RTLD_NOW | RTLD_LOCAL | RTLD_NOLOAD); //RTLD_NOLOAD flag is not specified in POSIX.1-2001..so not the best solution :(
if (mod == NULL) {
mod = dlopen(moduleName, RTLD_NOW | RTLD_LOCAL);
if (mod == NULL)
return SQ_ERROR;
}
modLoad = (SQMODULELOAD) dlsym(mod, "sqmodule_load");
if (modLoad == NULL) {
dlclose(mod);
return SQ_ERROR;
}
#endif
if(sqapi == NULL) {
sqapi = sqrat_newapi(); // Caching this for multiple imports is probably a very good idea
}
SQRESULT res = modLoad(v, sqapi);
return res;
#endif
}
SQRESULT sqrat_import(HSQUIRRELVM v) {
const SQChar* moduleName;
HSQOBJECT table;
SQRESULT res = SQ_OK;
sq_getstring(v, -2, &moduleName);
sq_getstackobj(v, -1, &table);
sq_addref(v, &table);
sq_settop(v, 0); // Clear Stack
sq_pushobject(v, table); // Push the target table onto the stack
if(SQ_FAILED(sqrat_importscript(v, moduleName))) {
res = sqrat_importbin(v, moduleName);
}
sq_settop(v, 0); // Clean up the stack (just in case the module load leaves it messy)
sq_pushobject(v, table); // return the target table
sq_release(v, &table);
return res;
}
static SQInteger sqratbase_import(HSQUIRRELVM v) {
SQInteger args = sq_gettop(v);
switch(args) {
case 2:
sq_pushroottable(v);
break;
case 3:
// should already have the desired table pushed onto the stack
break;
default:
// Error, unexpected number of arguments
break;
}
sqrat_import(v);
return 1;
}
SQRESULT sqrat_register_importlib(HSQUIRRELVM v) {
sq_pushroottable(v);
sq_pushstring(v, _SC("import"), -1);
sq_newclosure(v, &sqratbase_import, 0);
sq_newslot(v, -3, 0);
sq_pop(v, 1); // pop sqrat table
return SQ_OK;
}