diff options
Diffstat (limited to 'engines/sword25/util/pluto')
27 files changed, 4591 insertions, 0 deletions
diff --git a/engines/sword25/util/pluto/CHANGELOG b/engines/sword25/util/pluto/CHANGELOG new file mode 100644 index 0000000000..e31ed26044 --- /dev/null +++ b/engines/sword25/util/pluto/CHANGELOG @@ -0,0 +1,38 @@ +$Id$ + +-- 2.4 -- +* Changed upval unboxing to allow upvals which contain func-housed cycles +* Added stack checking to all stack-growing functions +* Serialized debug information for functions + +-- 2.3 -- +* Added LUALIB_API declaration for luaopen_pluto + +-- 2.2 -- +* Rolled all internal Lua dependencies into the Pluto distribution +* Made the unit tests depend on dynamically loading Pluto + +-- 2.1 -- +* Various fixes to make the GC happy +* stack size always expanded where necessary +* fixed some memory leaks +* GC disabled during unpersist +* callstack initialized for traversal + +This changelog is maintained as of version 2.0alpha1. +Earlier versions are changelogged on the LuaForge site. + +-- 2.0 -- +* Fixed a few format changes to 5.1.3 +* Fixed myriad warnings +* GCC compliance: not incrementing cast results +* Fix for self-referring upvals +* Renamed loading function to work with Lua module system +* Loading tables with __newindex works +* unpersist makes buffer copy + +-- 2.0alpha1 -- +* Fixed all outstanding 5.0->5.1 conversion issues +* Made heavier use of size_t in preference to int +* Fixed GC/Upval issue (thanks to Eric Jacobs) + diff --git a/engines/sword25/util/pluto/FILEFORMAT b/engines/sword25/util/pluto/FILEFORMAT new file mode 100644 index 0000000000..b3f10ee603 --- /dev/null +++ b/engines/sword25/util/pluto/FILEFORMAT @@ -0,0 +1,168 @@ +$Id$ + +pluto_persist() produces a "hunk" of objects. Here's the file format adhered +to by the function, and expected by pluto_unpersist(). + +As a developer, I feel that where file format information is given it is of +utmost importance that that information precisely and accurately reflects the +actual operation of the application. Therefore, if you find any discrepancy +between this and actual operation, please lambast me thoroughly over email. + +Pseudo-C is used to express the file format. Padding is assumed to be +nonexistent. The keyword "one_of" is used to express a concept similar to +"union", except that its size is the size of the actual datatype chosen. Thus, +objects which contain, directly or indirectly, a one_of, may vary in size. + + +struct Object { + int firstTime; /* Whether this is the first time the object + is being referenced */ + one_of { + RealObject o; /* if firstTime == 1 */ + Reference r; /* if firstTime == 0 */ + }; +}; + +struct Reference { + int ref; /* The index the object was registered with */ +}; + +struct RealObject { + int type; /* The type of the object */ + one_of { + Boolean b; /* If type == LUA_TBOOLEAN */ + LightUserData l; /* If type == LUA_TLIGHTUSERDATA */ + Number n; /* If type == LUA_TNUMBER */ + String s; /* If type == LUA_TSTRING */ + Table t; /* If type == LUA_TTABLE */ + Function f; /* If type == LUA_TFUNCTION */ + Userdata u; /* If type == LUA_TUSERDATA */ + Thread th; /* If type == LUA_TTHREAD */ + Proto p; /* If type == LUA_TPROTO (from lobject.h) */ + Upval uv; /* If type == LUA_TUPVAL (from lobject.h) */ + }; /* The actual object */ +}; + +struct Boolean { + int32 bvalue; /* 0 for false, 1 for true */ +}; + +struct LightUserData { + void* luvalue; /* The actual, literal pointer */ +}; + +struct Number { + lua_Number nvalue; /* The actual number */ +}; + +struct String { + int length; /* The length of the string */ + char str[length]; /* The actual string (not null terminated) */ +}; + +struct Table { + int isspecial; /* 1 if SP is used; 0 otherwise */ + one_of { + Closure c; /* if isspecial == 1; closure to refill the table */ + LiteralTable t; /* if isspecial == 0; literal table info */ + }; +}; + +struct LiteralTable { + Object metatable; /* nil for default metatable */ + Pair p[]; /* key/value pairs */ + Object nil = nil; /* Nil reference to terminate */ +}; + +struct Pair { + Object key; + Object value; +}; + +struct Function { /* Actually a closure */ + lu_byte nups; /* Number of upvalues the function uses */ + Object proto; /* The proto this function uses */ + Object upvals[nups]; /* All upvalues */ + Object fenv; /* The FEnv (nil for the global table) +}; + +struct Upval { + Object obj; /* The object this upval refers to */ +} + +struct Userdata { + int isSpecial; /* 1 for special persistence, 0 for literal + one_of { + LiteralUserdata lu; /* if is_special is 0 */ + SpecialUserdata su; /* if is_special is 1 */ + }; +}; + +struct LiteralUserdata { + Object metatable; /* The metatable (nil for default) */ + int length; /* Size of the data */ + char data[length]; /* The actual data */ +}; + +struct SpecialUserdata { + int length; /* The size of the data */ + Object func; /* The closure used to fill the userdata */ +}; + +struct Thread { + int stacksize; /* The size of the stack filled with objects, + * including the "nil" that is hidden below + * the bottom of the stack visible to C */ + Object stack[stacksize];/* Indices of all stack values, bottom up */ + int callinfosize; /* Number of elements in the CallInfo stack */ + CallInfo callinfostack[callinfosize]; /* The CallInfo stack */ + int base; /* base = L->base - L->stack; */ + int top; /* top = L->top - L->stack; */ + OpenUpval openupvals[]; /* Upvalues to open */ + Object nil = nil; /* To terminate the open upvalues list */ +}; + +struct OpenUpval { + Object upval; /* The upvalue */ + int stackpos; /* The stack position to "reopen" it to */ + +}; + +struct CallInfo { + int base; /* base = ci->base - L->stack; */ + int top; /* top = ci->top - L->stack; */ + int pc; /* pc = ci->pc - proto->code; */ + int state; /* flags used by the CallInfo */ +}; + +struct Proto { + int sizek; /* Number of constants referenced */ + Object k[sizek]; /* Constants referenced */ + int sizep; /* Number of inner Protos referenced */ + Object p[sizep]; /* Inner Protos referenced */ + int sizecode; /* Number of instructions in code */ + Instruction code[sizecode]; /* The proto's code */ + ProtoDebug debuginfo; /* Debug information for the proto */ + lu_byte nups; /* Number of upvalues used */ + lu_byte numparams; /* Number of parameters taken */ + lu_byte is_vararg; /* 1 if function accepts varargs, 0 otherwise */ + lu_byte maxstacksize; /* Size of stack reserved for the function */ +}; + +struct ProtoDebug { + int sizeupvals; /* Number of upvalue names */ + Object upvals; /* Upvalue names */ + int sizelocvars; /* Number of local variable names */ + LocVar[sizelocvars]; /* Local variable names */ + Object source; /* The source code */ + int sizelineinfo; /* Number of opcode-line mappings */ + int lineinfo[sizelineinfo]; /* opcode-line mappings */ + int linedefined; /* Start of line range */ + int lastlinedefined; /* End of line range */ +}; + +struct LocVar { + Object name; /* Name of the local variable */ + int startpc; /* Point where variable is active */ + int endpc; /* Point where variable is dead */ +};
\ No newline at end of file diff --git a/engines/sword25/util/pluto/Makefile b/engines/sword25/util/pluto/Makefile new file mode 100644 index 0000000000..611ecc83d2 --- /dev/null +++ b/engines/sword25/util/pluto/Makefile @@ -0,0 +1,29 @@ +LDLIBS= -lm -ldl -llua +LDFLAGS = -rdynamic # -L../lua-5.1.3/src +# CFLAGS= -g3 -Wall -fprofile-arcs -ftest-coverage +CFLAGS= -g3 -Wall -ansi -pedantic + +LIBTOOL=libtool --tag=CC + +default: pluto.so pptest puptest + +%.lo: %.c + $(LIBTOOL) --mode=compile cc $(CFLAGS) -c $< + +pluto.so: pluto.lo pdep.lo lzio.lo + $(LIBTOOL) --mode=link cc -rpath /usr/local/lib/lua/5.1 -o libpluto.la $^ + mv .libs/libpluto.so.0.0.0 $@ + +test: pptest puptest pptest.lua puptest.lua pluto.so + ./pptest + ./puptest + +pptest: pptest.o + $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) + +puptest: puptest.o + $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) + +clean: + -rm -r *.so *.la *.lo .libs *.a *.o *.bb *.bbg *.da *.gcov pptest puptest test.plh + diff --git a/engines/sword25/util/pluto/README b/engines/sword25/util/pluto/README new file mode 100644 index 0000000000..838fce498b --- /dev/null +++ b/engines/sword25/util/pluto/README @@ -0,0 +1,133 @@ +$Id$ + +PLUTO - Heavy duty persistence for Lua + +Pluto is a library which allows users to write arbitrarily large portions +of the "Lua universe" into a flat file, and later read them back into the +same or a different Lua universe. Object references are appropriately +handled, such that the file contains everything needed to recreate the +objects in question. + +Pluto has the following major features: +* Can persist any Lua function +* Can persist threads +* Works with any Lua chunkreader/chunkwriter +* Support for "invariant" permanent objects, of all datatypes +* Can invoke metafunctions for custom persistence of tables and userdata + +Pluto 2.2 requires Lua 5.1.3. If you need to use Pluto with Lua +5.0, please use version 1.2 of Pluto. + +Starting with version 2.2, Pluto no longer depends on the Lua sources. +Instead, it subsumes the required headers into its own codebase. +As a result, it may not work properly with Lua version 5.1.4 or later. + +Pluto may have bugs. Users are advised to define lua_assert in +luaconf.h to something useful when compiling in debug mode, to catch +assertions by Pluto and Lua. + +The Pluto library consists of two public functions. + +int pluto_persist(lua_State *L, lua_Chunkwriter writer, void *ud) + +This function recursively persists the Lua object in stack position 2 +and all other objects which are directly or indirectly referenced by +it, except those referenced in the permanent object table. The data +is written using the chunk-writer given, and that writer is passed +the arbitrary pointer value ud. + +The Lua stack must contain exactly and only these two items, in order: + +1. A table of permanent objects, that should not be persisted. For each +permanent object, the object itself should be the key, and a unique +object of any type should be the value. Likely candidates for this table +include Lua functions (including those in the Lua libraries) that are +loaded at load-time. It must include all non-persistable objects that +are referenced by the object to be persisted. The table is not modified +by the function. Objects in this table are considered "opaque" and are +not examined or descended into. Objects should not appear in the table +multiple times; the result of doing this is undefined (though probably +harmless). NOTE: If you are planning to persist threads, keep in mind +that all yielded threads have coroutine.yield on the tops of their +stacks. Since it's a C function, it should be put here. For complex +permanents, it may be a good idea to use the __index meta-function of +the permanents table to "search" for permanents. + +2. The single object to be persisted. In many cases, this will be the +global table. For more flexibility, however, it may be something like a +table built for the occasion, with various values to keep track of. The +object may not be nil. + + +int pluto_unpersist(lua_State *L, lua_Chunkreader reader, void *ud) + +This function loads in a Lua object and places it on top of the stack. All +objects directly or indirectly referenced by it are also loaded. + +The Lua stack must contain, as its top value, a table of permanent +objects. This table should be like the permanent object table used when +persisting, but with the key and value of each pair reversed. These +objects are used as substitutes for those referenced in their positions +when persisting, and under most circumstances should be identical objects +to those referenced in the permanents table used for persisting. It's +okay for multiple keys to refer to the same object. + + +RUNNING PLUTO FROM LUA: +It is also possible to invoke pluto from a Lua script. The C function +pluto_open() will register pluto.persist and pluto.unpersist, lua functions +which operate on strings. The first takes a permanents table and a root +object, and returns a string; the second takes a permanents table and a +string, and returns the root object. + +An error will be raised if pluto.persist is called from a thread which is +itself referenced by the root object. + +SPECIAL PERSISTENCE: +Tables and userdata have special persistence semantics. These semantics are +keyed to the value of the object's metatable's __persist member, if any. This +member may be any of the following four values: +1. Boolean "true": The table or userdata is persisted literally; tables are +persisted member-by-member, and userdata are written out as literal data. +2. Boolean "false": An error is returned, indicating that the object cannot +be persisted. +3. A function: This function should take one argument, the object in question, +and return one result, a closure. This "fixup closure", in turn, will be +persisted, and during unpersistence will be called. The closure will be +responsible for recreating the object with the appropriate data, based on +its upvalues. +4. Nil, or no metatable. In the case of tables, the table is literally +persisted. In the case of userdata, an error is returned. + +Here's an example of special persistence for a simple 3d vector object: + +vec = { x = 2, y = 1, z = 4 } +setmetatable(vec, { __persist = function(oldtbl) + local x = oldtbl.x + local y = oldtbl.y + local z = oldtbl.z + local mt = getmetatable(oldtbl) + return function() + newtbl = {} + newtbl.x = x + newtbl.y = y + newtbl.z = z + setmetatable(newtbl, mt) + return newtbl + end +end }) + +Note how x, y, z, and the mt are explicitly pulled out of the table. It is +important that the fixup closure returned not reference the original table +directly, as that table would again be persisted as an upvalue, leading to an +infinite loop. Also note that the object's metatable is NOT automatically +persisted; it is necessary for the fixup closure to reset it, if it wants. + +LIMITATIONS/TODO: +* Light userdata are persisted literally, as their pointer values. This +may or may not be what you want. +* Closures of C functions may not be persisted. Once it becomes possible +to specify a C function "proto" as a permanent object, this restriction +will be relaxed. + +BUGS: None known. Emphasis on the 'known'. diff --git a/engines/sword25/util/pluto/THANKS b/engines/sword25/util/pluto/THANKS new file mode 100644 index 0000000000..fea3595dbf --- /dev/null +++ b/engines/sword25/util/pluto/THANKS @@ -0,0 +1,10 @@ +Pluto is surprisingly robust and useful. This would not be the case without +the hard work and helpfulness of the following people, mentioned in no +particular order: + +Ivko Stanilov +Goran Adrinek +Eric Jacobs +Anolan Milanes +Malte Thiesen + diff --git a/engines/sword25/util/pluto/pdep.c b/engines/sword25/util/pluto/pdep.c new file mode 100644 index 0000000000..a32c43b42d --- /dev/null +++ b/engines/sword25/util/pluto/pdep.c @@ -0,0 +1,112 @@ +/* This file is derived from the Lua source code. Please see lua.h for +the copyright statement. +*/ + +#include "pdep/pdep.h" + +#define api_incr_top(L) {api_check(L, L->top < L->ci->top); L->top++;} + +void pdep_pushobject (lua_State *L, const TValue *o) { + setobj2s(L, L->top, o); + api_incr_top(L); +} + +void *pdep_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { + global_State *g = G(L); + lua_assert((osize == 0) == (block == NULL)); + block = (*g->frealloc)(g->ud, block, osize, nsize); + lua_assert((nsize == 0) == (block == NULL)); + g->totalbytes = (g->totalbytes - osize) + nsize; + return block; +} + +void pdep_link (lua_State *L, GCObject *o, lu_byte tt) { + global_State *g = G(L); + o->gch.next = g->rootgc; + g->rootgc = o; + o->gch.marked = luaC_white(g); + o->gch.tt = tt; +} + +Proto *pdep_newproto (lua_State *L) { + Proto *f = pdep_new(L, Proto); + pdep_link(L, obj2gco(f), LUA_TPROTO); + f->k = NULL; + f->sizek = 0; + f->p = NULL; + f->sizep = 0; + f->code = NULL; + f->sizecode = 0; + f->sizelineinfo = 0; + f->sizeupvalues = 0; + f->nups = 0; + f->upvalues = NULL; + f->numparams = 0; + f->is_vararg = 0; + f->maxstacksize = 0; + f->lineinfo = NULL; + f->sizelocvars = 0; + f->locvars = NULL; + f->linedefined = 0; + f->lastlinedefined = 0; + f->source = NULL; + return f; +} + +Closure *pdep_newLclosure (lua_State *L, int nelems, Table *e) { + Closure *c = cast(Closure *, pdep_malloc(L, sizeLclosure(nelems))); + pdep_link(L, obj2gco(c), LUA_TFUNCTION); + c->l.isC = 0; + c->l.env = e; + c->l.nupvalues = cast_byte(nelems); + while (nelems--) c->l.upvals[nelems] = NULL; + return c; +} + +static void correctstack (lua_State *L, TValue *oldstack) { + CallInfo *ci; + GCObject *up; + L->top = (L->top - oldstack) + L->stack; + for (up = L->openupval; up != NULL; up = up->gch.next) + gco2uv(up)->v = (gco2uv(up)->v - oldstack) + L->stack; + for (ci = L->base_ci; ci <= L->ci; ci++) { + ci->top = (ci->top - oldstack) + L->stack; + ci->base = (ci->base - oldstack) + L->stack; + ci->func = (ci->func - oldstack) + L->stack; + } + L->base = (L->base - oldstack) + L->stack; +} + + +void pdep_reallocstack (lua_State *L, int newsize) { + TValue *oldstack = L->stack; + int realsize = newsize + 1 + EXTRA_STACK; + lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1); + pdep_reallocvector(L, L->stack, L->stacksize, realsize, TValue); + L->stacksize = realsize; + L->stack_last = L->stack+newsize; + correctstack(L, oldstack); +} + +void pdep_growstack (lua_State *L, int n) { + if (n <= L->stacksize) /* double size is enough? */ + pdep_reallocstack(L, 2*L->stacksize); + else + pdep_reallocstack(L, L->stacksize + n); +} + +void pdep_reallocCI (lua_State *L, int newsize) { + CallInfo *oldci = L->base_ci; + pdep_reallocvector(L, L->base_ci, L->size_ci, newsize, CallInfo); + L->size_ci = newsize; + L->ci = (L->ci - oldci) + L->base_ci; + L->end_ci = L->base_ci + L->size_ci - 1; +} + +TString *pdep_newlstr (lua_State *L, const char *str, size_t l) { + TString *res; + lua_pushlstring(L, str, l); + res = rawtsvalue(L->top-1); + lua_pop(L, 1); + return res; +} diff --git a/engines/sword25/util/pluto/pdep/README b/engines/sword25/util/pluto/pdep/README new file mode 100644 index 0000000000..3592754da0 --- /dev/null +++ b/engines/sword25/util/pluto/pdep/README @@ -0,0 +1,5 @@ +These files are directly copied from the Lua distribution, with the +exception of lzio.h, which is s/lua{ZM}/pdep/g and has an include removed. + +As such, unlike the rest of Pluto, they are released under the +same terms as Lua. See "lua.h" for the copyright notice. diff --git a/engines/sword25/util/pluto/pdep/lauxlib.h b/engines/sword25/util/pluto/pdep/lauxlib.h new file mode 100644 index 0000000000..34258235db --- /dev/null +++ b/engines/sword25/util/pluto/pdep/lauxlib.h @@ -0,0 +1,174 @@ +/* +** $Id: lauxlib.h,v 1.88.1.1 2007/12/27 13:02:25 roberto Exp $ +** Auxiliary functions for building Lua libraries +** See Copyright Notice in lua.h +*/ + + +#ifndef lauxlib_h +#define lauxlib_h + + +#include <stddef.h> +#include <stdio.h> + +#include "lua.h" + + +#if defined(LUA_COMPAT_GETN) +LUALIB_API int (luaL_getn) (lua_State *L, int t); +LUALIB_API void (luaL_setn) (lua_State *L, int t, int n); +#else +#define luaL_getn(L,i) ((int)lua_objlen(L, i)) +#define luaL_setn(L,i,j) ((void)0) /* no op! */ +#endif + +#if defined(LUA_COMPAT_OPENLIB) +#define luaI_openlib luaL_openlib +#endif + + +/* extra error code for `luaL_load' */ +#define LUA_ERRFILE (LUA_ERRERR+1) + + +typedef struct luaL_Reg { + const char *name; + lua_CFunction func; +} luaL_Reg; + + + +LUALIB_API void (luaI_openlib) (lua_State *L, const char *libname, + const luaL_Reg *l, int nup); +LUALIB_API void (luaL_register) (lua_State *L, const char *libname, + const luaL_Reg *l); +LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e); +LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e); +LUALIB_API int (luaL_typerror) (lua_State *L, int narg, const char *tname); +LUALIB_API int (luaL_argerror) (lua_State *L, int numarg, const char *extramsg); +LUALIB_API const char *(luaL_checklstring) (lua_State *L, int numArg, + size_t *l); +LUALIB_API const char *(luaL_optlstring) (lua_State *L, int numArg, + const char *def, size_t *l); +LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int numArg); +LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int nArg, lua_Number def); + +LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int numArg); +LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int nArg, + lua_Integer def); + +LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg); +LUALIB_API void (luaL_checktype) (lua_State *L, int narg, int t); +LUALIB_API void (luaL_checkany) (lua_State *L, int narg); + +LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname); +LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname); + +LUALIB_API void (luaL_where) (lua_State *L, int lvl); +LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...); + +LUALIB_API int (luaL_checkoption) (lua_State *L, int narg, const char *def, + const char *const lst[]); + +LUALIB_API int (luaL_ref) (lua_State *L, int t); +LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref); + +LUALIB_API int (luaL_loadfile) (lua_State *L, const char *filename); +LUALIB_API int (luaL_loadbuffer) (lua_State *L, const char *buff, size_t sz, + const char *name); +LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s); + +LUALIB_API lua_State *(luaL_newstate) (void); + + +LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p, + const char *r); + +LUALIB_API const char *(luaL_findtable) (lua_State *L, int idx, + const char *fname, int szhint); + + + + +/* +** =============================================================== +** some useful macros +** =============================================================== +*/ + +#define luaL_argcheck(L, cond,numarg,extramsg) \ + ((void)((cond) || luaL_argerror(L, (numarg), (extramsg)))) +#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL)) +#define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL)) +#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n))) +#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d))) +#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n))) +#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d))) + +#define luaL_typename(L,i) lua_typename(L, lua_type(L,(i))) + +#define luaL_dofile(L, fn) \ + (luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0)) + +#define luaL_dostring(L, s) \ + (luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0)) + +#define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n))) + +#define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n))) + +/* +** {====================================================== +** Generic Buffer manipulation +** ======================================================= +*/ + + + +typedef struct luaL_Buffer { + char *p; /* current position in buffer */ + int lvl; /* number of strings in the stack (level) */ + lua_State *L; + char buffer[LUAL_BUFFERSIZE]; +} luaL_Buffer; + +#define luaL_addchar(B,c) \ + ((void)((B)->p < ((B)->buffer+LUAL_BUFFERSIZE) || luaL_prepbuffer(B)), \ + (*(B)->p++ = (char)(c))) + +/* compatibility only */ +#define luaL_putchar(B,c) luaL_addchar(B,c) + +#define luaL_addsize(B,n) ((B)->p += (n)) + +LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B); +LUALIB_API char *(luaL_prepbuffer) (luaL_Buffer *B); +LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l); +LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s); +LUALIB_API void (luaL_addvalue) (luaL_Buffer *B); +LUALIB_API void (luaL_pushresult) (luaL_Buffer *B); + + +/* }====================================================== */ + + +/* compatibility with ref system */ + +/* pre-defined references */ +#define LUA_NOREF (-2) +#define LUA_REFNIL (-1) + +#define lua_ref(L,lock) ((lock) ? luaL_ref(L, LUA_REGISTRYINDEX) : \ + (lua_pushstring(L, "unlocked references are obsolete"), lua_error(L), 0)) + +#define lua_unref(L,ref) luaL_unref(L, LUA_REGISTRYINDEX, (ref)) + +#define lua_getref(L,ref) lua_rawgeti(L, LUA_REGISTRYINDEX, (ref)) + + +#define luaL_reg luaL_Reg + +#endif + + diff --git a/engines/sword25/util/pluto/pdep/ldo.h b/engines/sword25/util/pluto/pdep/ldo.h new file mode 100644 index 0000000000..98fddac59f --- /dev/null +++ b/engines/sword25/util/pluto/pdep/ldo.h @@ -0,0 +1,57 @@ +/* +** $Id: ldo.h,v 2.7.1.1 2007/12/27 13:02:25 roberto Exp $ +** Stack and Call structure of Lua +** See Copyright Notice in lua.h +*/ + +#ifndef ldo_h +#define ldo_h + + +#include "lobject.h" +#include "lstate.h" +#include "lzio.h" + + +#define luaD_checkstack(L,n) \ + if ((char *)L->stack_last - (char *)L->top <= (n)*(int)sizeof(TValue)) \ + luaD_growstack(L, n); \ + else condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK - 1)); + + +#define incr_top(L) {luaD_checkstack(L,1); L->top++;} + +#define savestack(L,p) ((char *)(p) - (char *)L->stack) +#define restorestack(L,n) ((TValue *)((char *)L->stack + (n))) + +#define saveci(L,p) ((char *)(p) - (char *)L->base_ci) +#define restoreci(L,n) ((CallInfo *)((char *)L->base_ci + (n))) + + +/* results from luaD_precall */ +#define PCRLUA 0 /* initiated a call to a Lua function */ +#define PCRC 1 /* did a call to a C function */ +#define PCRYIELD 2 /* C funtion yielded */ + + +/* type of protected functions, to be ran by `runprotected' */ +typedef void (*Pfunc) (lua_State *L, void *ud); + +LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name); +LUAI_FUNC void luaD_callhook (lua_State *L, int event, int line); +LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults); +LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); +LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u, + ptrdiff_t oldtop, ptrdiff_t ef); +LUAI_FUNC int luaD_poscall (lua_State *L, StkId firstResult); +LUAI_FUNC void luaD_reallocCI (lua_State *L, int newsize); +LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize); +LUAI_FUNC void luaD_growstack (lua_State *L, int n); + +LUAI_FUNC void luaD_throw (lua_State *L, int errcode); +LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud); + +LUAI_FUNC void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop); + +#endif + diff --git a/engines/sword25/util/pluto/pdep/lfunc.h b/engines/sword25/util/pluto/pdep/lfunc.h new file mode 100644 index 0000000000..a68cf5151c --- /dev/null +++ b/engines/sword25/util/pluto/pdep/lfunc.h @@ -0,0 +1,34 @@ +/* +** $Id: lfunc.h,v 2.4.1.1 2007/12/27 13:02:25 roberto Exp $ +** Auxiliary functions to manipulate prototypes and closures +** See Copyright Notice in lua.h +*/ + +#ifndef lfunc_h +#define lfunc_h + + +#include "lobject.h" + + +#define sizeCclosure(n) (cast(int, sizeof(CClosure)) + \ + cast(int, sizeof(TValue)*((n)-1))) + +#define sizeLclosure(n) (cast(int, sizeof(LClosure)) + \ + cast(int, sizeof(TValue *)*((n)-1))) + + +LUAI_FUNC Proto *luaF_newproto (lua_State *L); +LUAI_FUNC Closure *luaF_newCclosure (lua_State *L, int nelems, Table *e); +LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, int nelems, Table *e); +LUAI_FUNC UpVal *luaF_newupval (lua_State *L); +LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); +LUAI_FUNC void luaF_close (lua_State *L, StkId level); +LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); +LUAI_FUNC void luaF_freeclosure (lua_State *L, Closure *c); +LUAI_FUNC void luaF_freeupval (lua_State *L, UpVal *uv); +LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number, + int pc); + + +#endif diff --git a/engines/sword25/util/pluto/pdep/lgc.h b/engines/sword25/util/pluto/pdep/lgc.h new file mode 100644 index 0000000000..5a8dc605b3 --- /dev/null +++ b/engines/sword25/util/pluto/pdep/lgc.h @@ -0,0 +1,110 @@ +/* +** $Id: lgc.h,v 2.15.1.1 2007/12/27 13:02:25 roberto Exp $ +** Garbage Collector +** See Copyright Notice in lua.h +*/ + +#ifndef lgc_h +#define lgc_h + + +#include "lobject.h" + + +/* +** Possible states of the Garbage Collector +*/ +#define GCSpause 0 +#define GCSpropagate 1 +#define GCSsweepstring 2 +#define GCSsweep 3 +#define GCSfinalize 4 + + +/* +** some userful bit tricks +*/ +#define resetbits(x,m) ((x) &= cast(lu_byte, ~(m))) +#define setbits(x,m) ((x) |= (m)) +#define testbits(x,m) ((x) & (m)) +#define bitmask(b) (1<<(b)) +#define bit2mask(b1,b2) (bitmask(b1) | bitmask(b2)) +#define l_setbit(x,b) setbits(x, bitmask(b)) +#define resetbit(x,b) resetbits(x, bitmask(b)) +#define testbit(x,b) testbits(x, bitmask(b)) +#define set2bits(x,b1,b2) setbits(x, (bit2mask(b1, b2))) +#define reset2bits(x,b1,b2) resetbits(x, (bit2mask(b1, b2))) +#define test2bits(x,b1,b2) testbits(x, (bit2mask(b1, b2))) + + + +/* +** Layout for bit use in `marked' field: +** bit 0 - object is white (type 0) +** bit 1 - object is white (type 1) +** bit 2 - object is black +** bit 3 - for userdata: has been finalized +** bit 3 - for tables: has weak keys +** bit 4 - for tables: has weak values +** bit 5 - object is fixed (should not be collected) +** bit 6 - object is "super" fixed (only the main thread) +*/ + + +#define WHITE0BIT 0 +#define WHITE1BIT 1 +#define BLACKBIT 2 +#define FINALIZEDBIT 3 +#define KEYWEAKBIT 3 +#define VALUEWEAKBIT 4 +#define FIXEDBIT 5 +#define SFIXEDBIT 6 +#define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) + + +#define iswhite(x) test2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT) +#define isblack(x) testbit((x)->gch.marked, BLACKBIT) +#define isgray(x) (!isblack(x) && !iswhite(x)) + +#define otherwhite(g) (g->currentwhite ^ WHITEBITS) +#define isdead(g,v) ((v)->gch.marked & otherwhite(g) & WHITEBITS) + +#define changewhite(x) ((x)->gch.marked ^= WHITEBITS) +#define gray2black(x) l_setbit((x)->gch.marked, BLACKBIT) + +#define valiswhite(x) (iscollectable(x) && iswhite(gcvalue(x))) + +#define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS) + + +#define luaC_checkGC(L) { \ + condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK - 1)); \ + if (G(L)->totalbytes >= G(L)->GCthreshold) \ + luaC_step(L); } + + +#define luaC_barrier(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \ + luaC_barrierf(L,obj2gco(p),gcvalue(v)); } + +#define luaC_barriert(L,t,v) { if (valiswhite(v) && isblack(obj2gco(t))) \ + luaC_barrierback(L,t); } + +#define luaC_objbarrier(L,p,o) \ + { if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) \ + luaC_barrierf(L,obj2gco(p),obj2gco(o)); } + +#define luaC_objbarriert(L,t,o) \ + { if (iswhite(obj2gco(o)) && isblack(obj2gco(t))) luaC_barrierback(L,t); } + +LUAI_FUNC size_t luaC_separateudata (lua_State *L, int all); +LUAI_FUNC void luaC_callGCTM (lua_State *L); +LUAI_FUNC void luaC_freeall (lua_State *L); +LUAI_FUNC void luaC_step (lua_State *L); +LUAI_FUNC void luaC_fullgc (lua_State *L); +LUAI_FUNC void luaC_link (lua_State *L, GCObject *o, lu_byte tt); +LUAI_FUNC void luaC_linkupval (lua_State *L, UpVal *uv); +LUAI_FUNC void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v); +LUAI_FUNC void luaC_barrierback (lua_State *L, Table *t); + + +#endif diff --git a/engines/sword25/util/pluto/pdep/llimits.h b/engines/sword25/util/pluto/pdep/llimits.h new file mode 100644 index 0000000000..ca8dcb7224 --- /dev/null +++ b/engines/sword25/util/pluto/pdep/llimits.h @@ -0,0 +1,128 @@ +/* +** $Id: llimits.h,v 1.69.1.1 2007/12/27 13:02:25 roberto Exp $ +** Limits, basic types, and some other `installation-dependent' definitions +** See Copyright Notice in lua.h +*/ + +#ifndef llimits_h +#define llimits_h + + +#include <limits.h> +#include <stddef.h> + + +#include "lua.h" + + +typedef LUAI_UINT32 lu_int32; + +typedef LUAI_UMEM lu_mem; + +typedef LUAI_MEM l_mem; + + + +/* chars used as small naturals (so that `char' is reserved for characters) */ +typedef unsigned char lu_byte; + + +#define MAX_SIZET ((size_t)(~(size_t)0)-2) + +#define MAX_LUMEM ((lu_mem)(~(lu_mem)0)-2) + + +#define MAX_INT (INT_MAX-2) /* maximum value of an int (-2 for safety) */ + +/* +** conversion of pointer to integer +** this is for hashing only; there is no problem if the integer +** cannot hold the whole pointer value +*/ +#define IntPoint(p) ((unsigned int)(lu_mem)(p)) + + + +/* type to ensure maximum alignment */ +typedef LUAI_USER_ALIGNMENT_T L_Umaxalign; + + +/* result of a `usual argument conversion' over lua_Number */ +typedef LUAI_UACNUMBER l_uacNumber; + + +/* internal assertions for in-house debugging */ +#ifdef lua_assert + +#define check_exp(c,e) (lua_assert(c), (e)) +#define api_check(l,e) lua_assert(e) + +#else + +#define lua_assert(c) ((void)0) +#define check_exp(c,e) (e) +#define api_check luai_apicheck + +#endif + + +#ifndef UNUSED +#define UNUSED(x) ((void)(x)) /* to avoid warnings */ +#endif + + +#ifndef cast +#define cast(t, exp) ((t)(exp)) +#endif + +#define cast_byte(i) cast(lu_byte, (i)) +#define cast_num(i) cast(lua_Number, (i)) +#define cast_int(i) cast(int, (i)) + + + +/* +** type for virtual-machine instructions +** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h) +*/ +typedef lu_int32 Instruction; + + + +/* maximum stack for a Lua function */ +#define MAXSTACK 250 + + + +/* minimum size for the string table (must be power of 2) */ +#ifndef MINSTRTABSIZE +#define MINSTRTABSIZE 32 +#endif + + +/* minimum size for string buffer */ +#ifndef LUA_MINBUFFER +#define LUA_MINBUFFER 32 +#endif + + +#ifndef lua_lock +#define lua_lock(L) ((void) 0) +#define lua_unlock(L) ((void) 0) +#endif + +#ifndef luai_threadyield +#define luai_threadyield(L) {lua_unlock(L); lua_lock(L);} +#endif + + +/* +** macro to control inclusion of some hard tests on stack reallocation +*/ +#ifndef HARDSTACKTESTS +#define condhardstacktests(x) ((void)0) +#else +#define condhardstacktests(x) x +#endif + +#endif diff --git a/engines/sword25/util/pluto/pdep/lobject.h b/engines/sword25/util/pluto/pdep/lobject.h new file mode 100644 index 0000000000..e7199dfc68 --- /dev/null +++ b/engines/sword25/util/pluto/pdep/lobject.h @@ -0,0 +1,381 @@ +/* +** $Id: lobject.h,v 2.20.1.1 2007/12/27 13:02:25 roberto Exp $ +** Type definitions for Lua objects +** See Copyright Notice in lua.h +*/ + + +#ifndef lobject_h +#define lobject_h + + +#include <stdarg.h> + + +#include "llimits.h" +#include "lua.h" + + +/* tags for values visible from Lua */ +#define LAST_TAG LUA_TTHREAD + +#define NUM_TAGS (LAST_TAG+1) + + +/* +** Extra tags for non-values +*/ +#define LUA_TPROTO (LAST_TAG+1) +#define LUA_TUPVAL (LAST_TAG+2) +#define LUA_TDEADKEY (LAST_TAG+3) + + +/* +** Union of all collectable objects +*/ +typedef union GCObject GCObject; + + +/* +** Common Header for all collectable objects (in macro form, to be +** included in other objects) +*/ +#define CommonHeader GCObject *next; lu_byte tt; lu_byte marked + + +/* +** Common header in struct form +*/ +typedef struct GCheader { + CommonHeader; +} GCheader; + + + + +/* +** Union of all Lua values +*/ +typedef union { + GCObject *gc; + void *p; + lua_Number n; + int b; +} Value; + + +/* +** Tagged Values +*/ + +#define TValuefields Value value; int tt + +typedef struct lua_TValue { + TValuefields; +} TValue; + + +/* Macros to test type */ +#define ttisnil(o) (ttype(o) == LUA_TNIL) +#define ttisnumber(o) (ttype(o) == LUA_TNUMBER) +#define ttisstring(o) (ttype(o) == LUA_TSTRING) +#define ttistable(o) (ttype(o) == LUA_TTABLE) +#define ttisfunction(o) (ttype(o) == LUA_TFUNCTION) +#define ttisboolean(o) (ttype(o) == LUA_TBOOLEAN) +#define ttisuserdata(o) (ttype(o) == LUA_TUSERDATA) +#define ttisthread(o) (ttype(o) == LUA_TTHREAD) +#define ttislightuserdata(o) (ttype(o) == LUA_TLIGHTUSERDATA) + +/* Macros to access values */ +#define ttype(o) ((o)->tt) +#define gcvalue(o) check_exp(iscollectable(o), (o)->value.gc) +#define pvalue(o) check_exp(ttislightuserdata(o), (o)->value.p) +#define nvalue(o) check_exp(ttisnumber(o), (o)->value.n) +#define rawtsvalue(o) check_exp(ttisstring(o), &(o)->value.gc->ts) +#define tsvalue(o) (&rawtsvalue(o)->tsv) +#define rawuvalue(o) check_exp(ttisuserdata(o), &(o)->value.gc->u) +#define uvalue(o) (&rawuvalue(o)->uv) +#define clvalue(o) check_exp(ttisfunction(o), &(o)->value.gc->cl) +#define hvalue(o) check_exp(ttistable(o), &(o)->value.gc->h) +#define bvalue(o) check_exp(ttisboolean(o), (o)->value.b) +#define thvalue(o) check_exp(ttisthread(o), &(o)->value.gc->th) + +#define l_isfalse(o) (ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0)) + +/* +** for internal debug only +*/ +#define checkconsistency(obj) \ + lua_assert(!iscollectable(obj) || (ttype(obj) == (obj)->value.gc->gch.tt)) + +#define checkliveness(g,obj) \ + lua_assert(!iscollectable(obj) || \ + ((ttype(obj) == (obj)->value.gc->gch.tt) && !isdead(g, (obj)->value.gc))) + + +/* Macros to set values */ +#define setnilvalue(obj) ((obj)->tt=LUA_TNIL) + +#define setnvalue(obj,x) \ + { TValue *i_o=(obj); i_o->value.n=(x); i_o->tt=LUA_TNUMBER; } + +#define setpvalue(obj,x) \ + { TValue *i_o=(obj); i_o->value.p=(x); i_o->tt=LUA_TLIGHTUSERDATA; } + +#define setbvalue(obj,x) \ + { TValue *i_o=(obj); i_o->value.b=(x); i_o->tt=LUA_TBOOLEAN; } + +#define setsvalue(L,obj,x) \ + { TValue *i_o=(obj); \ + i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TSTRING; \ + checkliveness(G(L),i_o); } + +#define setuvalue(L,obj,x) \ + { TValue *i_o=(obj); \ + i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TUSERDATA; \ + checkliveness(G(L),i_o); } + +#define setthvalue(L,obj,x) \ + { TValue *i_o=(obj); \ + i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTHREAD; \ + checkliveness(G(L),i_o); } + +#define setclvalue(L,obj,x) \ + { TValue *i_o=(obj); \ + i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TFUNCTION; \ + checkliveness(G(L),i_o); } + +#define sethvalue(L,obj,x) \ + { TValue *i_o=(obj); \ + i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TTABLE; \ + checkliveness(G(L),i_o); } + +#define setptvalue(L,obj,x) \ + { TValue *i_o=(obj); \ + i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TPROTO; \ + checkliveness(G(L),i_o); } + + + + +#define setobj(L,obj1,obj2) \ + { const TValue *o2=(obj2); TValue *o1=(obj1); \ + o1->value = o2->value; o1->tt=o2->tt; \ + checkliveness(G(L),o1); } + + +/* +** different types of sets, according to destination +*/ + +/* from stack to (same) stack */ +#define setobjs2s setobj +/* to stack (not from same stack) */ +#define setobj2s setobj +#define setsvalue2s setsvalue +#define sethvalue2s sethvalue +#define setptvalue2s setptvalue +/* from table to same table */ +#define setobjt2t setobj +/* to table */ +#define setobj2t setobj +/* to new object */ +#define setobj2n setobj +#define setsvalue2n setsvalue + +#define setttype(obj, tt) (ttype(obj) = (tt)) + + +#define iscollectable(o) (ttype(o) >= LUA_TSTRING) + + + +typedef TValue *StkId; /* index to stack elements */ + + +/* +** String headers for string table +*/ +typedef union TString { + L_Umaxalign dummy; /* ensures maximum alignment for strings */ + struct { + CommonHeader; + lu_byte reserved; + unsigned int hash; + size_t len; + } tsv; +} TString; + + +#define getstr(ts) cast(const char *, (ts) + 1) +#define svalue(o) getstr(tsvalue(o)) + + + +typedef union Udata { + L_Umaxalign dummy; /* ensures maximum alignment for `local' udata */ + struct { + CommonHeader; + struct Table *metatable; + struct Table *env; + size_t len; + } uv; +} Udata; + + + + +/* +** Function Prototypes +*/ +typedef struct Proto { + CommonHeader; + TValue *k; /* constants used by the function */ + Instruction *code; + struct Proto **p; /* functions defined inside the function */ + int *lineinfo; /* map from opcodes to source lines */ + struct LocVar *locvars; /* information about local variables */ + TString **upvalues; /* upvalue names */ + TString *source; + int sizeupvalues; + int sizek; /* size of `k' */ + int sizecode; + int sizelineinfo; + int sizep; /* size of `p' */ + int sizelocvars; + int linedefined; + int lastlinedefined; + GCObject *gclist; + lu_byte nups; /* number of upvalues */ + lu_byte numparams; + lu_byte is_vararg; + lu_byte maxstacksize; +} Proto; + + +/* masks for new-style vararg */ +#define VARARG_HASARG 1 +#define VARARG_ISVARARG 2 +#define VARARG_NEEDSARG 4 + + +typedef struct LocVar { + TString *varname; + int startpc; /* first point where variable is active */ + int endpc; /* first point where variable is dead */ +} LocVar; + + + +/* +** Upvalues +*/ + +typedef struct UpVal { + CommonHeader; + TValue *v; /* points to stack or to its own value */ + union { + TValue value; /* the value (when closed) */ + struct { /* double linked list (when open) */ + struct UpVal *prev; + struct UpVal *next; + } l; + } u; +} UpVal; + + +/* +** Closures +*/ + +#define ClosureHeader \ + CommonHeader; lu_byte isC; lu_byte nupvalues; GCObject *gclist; \ + struct Table *env + +typedef struct CClosure { + ClosureHeader; + lua_CFunction f; + TValue upvalue[1]; +} CClosure; + + +typedef struct LClosure { + ClosureHeader; + struct Proto *p; + UpVal *upvals[1]; +} LClosure; + + +typedef union Closure { + CClosure c; + LClosure l; +} Closure; + + +#define iscfunction(o) (ttype(o) == LUA_TFUNCTION && clvalue(o)->c.isC) +#define isLfunction(o) (ttype(o) == LUA_TFUNCTION && !clvalue(o)->c.isC) + + +/* +** Tables +*/ + +typedef union TKey { + struct { + TValuefields; + struct Node *next; /* for chaining */ + } nk; + TValue tvk; +} TKey; + + +typedef struct Node { + TValue i_val; + TKey i_key; +} Node; + + +typedef struct Table { + CommonHeader; + lu_byte flags; /* 1<<p means tagmethod(p) is not present */ + lu_byte lsizenode; /* log2 of size of `node' array */ + struct Table *metatable; + TValue *array; /* array part */ + Node *node; + Node *lastfree; /* any free position is before this position */ + GCObject *gclist; + int sizearray; /* size of `array' array */ +} Table; + + + +/* +** `module' operation for hashing (size is always a power of 2) +*/ +#define lmod(s,size) \ + (check_exp((size&(size-1))==0, (cast(int, (s) & ((size)-1))))) + + +#define twoto(x) (1<<(x)) +#define sizenode(t) (twoto((t)->lsizenode)) + + +#define luaO_nilobject (&luaO_nilobject_) + +LUAI_DATA const TValue luaO_nilobject_; + +#define ceillog2(x) (luaO_log2((x)-1) + 1) + +LUAI_FUNC int luaO_log2 (unsigned int x); +LUAI_FUNC int luaO_int2fb (unsigned int x); +LUAI_FUNC int luaO_fb2int (int x); +LUAI_FUNC int luaO_rawequalObj (const TValue *t1, const TValue *t2); +LUAI_FUNC int luaO_str2d (const char *s, lua_Number *result); +LUAI_FUNC const char *luaO_pushvfstring (lua_State *L, const char *fmt, + va_list argp); +LUAI_FUNC const char *luaO_pushfstring (lua_State *L, const char *fmt, ...); +LUAI_FUNC void luaO_chunkid (char *out, const char *source, size_t len); + + +#endif + diff --git a/engines/sword25/util/pluto/pdep/lopcodes.h b/engines/sword25/util/pluto/pdep/lopcodes.h new file mode 100644 index 0000000000..41224d6ee1 --- /dev/null +++ b/engines/sword25/util/pluto/pdep/lopcodes.h @@ -0,0 +1,268 @@ +/* +** $Id: lopcodes.h,v 1.125.1.1 2007/12/27 13:02:25 roberto Exp $ +** Opcodes for Lua virtual machine +** See Copyright Notice in lua.h +*/ + +#ifndef lopcodes_h +#define lopcodes_h + +#include "llimits.h" + + +/*=========================================================================== + We assume that instructions are unsigned numbers. + All instructions have an opcode in the first 6 bits. + Instructions can have the following fields: + `A' : 8 bits + `B' : 9 bits + `C' : 9 bits + `Bx' : 18 bits (`B' and `C' together) + `sBx' : signed Bx + + A signed argument is represented in excess K; that is, the number + value is the unsigned value minus K. K is exactly the maximum value + for that argument (so that -max is represented by 0, and +max is + represented by 2*max), which is half the maximum for the corresponding + unsigned argument. +===========================================================================*/ + + +enum OpMode {iABC, iABx, iAsBx}; /* basic instruction format */ + + +/* +** size and position of opcode arguments. +*/ +#define SIZE_C 9 +#define SIZE_B 9 +#define SIZE_Bx (SIZE_C + SIZE_B) +#define SIZE_A 8 + +#define SIZE_OP 6 + +#define POS_OP 0 +#define POS_A (POS_OP + SIZE_OP) +#define POS_C (POS_A + SIZE_A) +#define POS_B (POS_C + SIZE_C) +#define POS_Bx POS_C + + +/* +** limits for opcode arguments. +** we use (signed) int to manipulate most arguments, +** so they must fit in LUAI_BITSINT-1 bits (-1 for sign) +*/ +#if SIZE_Bx < LUAI_BITSINT-1 +#define MAXARG_Bx ((1<<SIZE_Bx)-1) +#define MAXARG_sBx (MAXARG_Bx>>1) /* `sBx' is signed */ +#else +#define MAXARG_Bx MAX_INT +#define MAXARG_sBx MAX_INT +#endif + + +#define MAXARG_A ((1<<SIZE_A)-1) +#define MAXARG_B ((1<<SIZE_B)-1) +#define MAXARG_C ((1<<SIZE_C)-1) + + +/* creates a mask with `n' 1 bits at position `p' */ +#define MASK1(n,p) ((~((~(Instruction)0)<<n))<<p) + +/* creates a mask with `n' 0 bits at position `p' */ +#define MASK0(n,p) (~MASK1(n,p)) + +/* +** the following macros help to manipulate instructions +*/ + +#define GET_OPCODE(i) (cast(OpCode, ((i)>>POS_OP) & MASK1(SIZE_OP,0))) +#define SET_OPCODE(i,o) ((i) = (((i)&MASK0(SIZE_OP,POS_OP)) | \ + ((cast(Instruction, o)<<POS_OP)&MASK1(SIZE_OP,POS_OP)))) + +#define GETARG_A(i) (cast(int, ((i)>>POS_A) & MASK1(SIZE_A,0))) +#define SETARG_A(i,u) ((i) = (((i)&MASK0(SIZE_A,POS_A)) | \ + ((cast(Instruction, u)<<POS_A)&MASK1(SIZE_A,POS_A)))) + +#define GETARG_B(i) (cast(int, ((i)>>POS_B) & MASK1(SIZE_B,0))) +#define SETARG_B(i,b) ((i) = (((i)&MASK0(SIZE_B,POS_B)) | \ + ((cast(Instruction, b)<<POS_B)&MASK1(SIZE_B,POS_B)))) + +#define GETARG_C(i) (cast(int, ((i)>>POS_C) & MASK1(SIZE_C,0))) +#define SETARG_C(i,b) ((i) = (((i)&MASK0(SIZE_C,POS_C)) | \ + ((cast(Instruction, b)<<POS_C)&MASK1(SIZE_C,POS_C)))) + +#define GETARG_Bx(i) (cast(int, ((i)>>POS_Bx) & MASK1(SIZE_Bx,0))) +#define SETARG_Bx(i,b) ((i) = (((i)&MASK0(SIZE_Bx,POS_Bx)) | \ + ((cast(Instruction, b)<<POS_Bx)&MASK1(SIZE_Bx,POS_Bx)))) + +#define GETARG_sBx(i) (GETARG_Bx(i)-MAXARG_sBx) +#define SETARG_sBx(i,b) SETARG_Bx((i),cast(unsigned int, (b)+MAXARG_sBx)) + + +#define CREATE_ABC(o,a,b,c) ((cast(Instruction, o)<<POS_OP) \ + | (cast(Instruction, a)<<POS_A) \ + | (cast(Instruction, b)<<POS_B) \ + | (cast(Instruction, c)<<POS_C)) + +#define CREATE_ABx(o,a,bc) ((cast(Instruction, o)<<POS_OP) \ + | (cast(Instruction, a)<<POS_A) \ + | (cast(Instruction, bc)<<POS_Bx)) + + +/* +** Macros to operate RK indices +*/ + +/* this bit 1 means constant (0 means register) */ +#define BITRK (1 << (SIZE_B - 1)) + +/* test whether value is a constant */ +#define ISK(x) ((x) & BITRK) + +/* gets the index of the constant */ +#define INDEXK(r) ((int)(r) & ~BITRK) + +#define MAXINDEXRK (BITRK - 1) + +/* code a constant index as a RK value */ +#define RKASK(x) ((x) | BITRK) + + +/* +** invalid register that fits in 8 bits +*/ +#define NO_REG MAXARG_A + + +/* +** R(x) - register +** Kst(x) - constant (in constant table) +** RK(x) == if ISK(x) then Kst(INDEXK(x)) else R(x) +*/ + + +/* +** grep "ORDER OP" if you change these enums +*/ + +typedef enum { +/*---------------------------------------------------------------------- +name args description +------------------------------------------------------------------------*/ +OP_MOVE,/* A B R(A) := R(B) */ +OP_LOADK,/* A Bx R(A) := Kst(Bx) */ +OP_LOADBOOL,/* A B C R(A) := (Bool)B; if (C) pc++ */ +OP_LOADNIL,/* A B R(A) := ... := R(B) := nil */ +OP_GETUPVAL,/* A B R(A) := UpValue[B] */ + +OP_GETGLOBAL,/* A Bx R(A) := Gbl[Kst(Bx)] */ +OP_GETTABLE,/* A B C R(A) := R(B)[RK(C)] */ + +OP_SETGLOBAL,/* A Bx Gbl[Kst(Bx)] := R(A) */ +OP_SETUPVAL,/* A B UpValue[B] := R(A) */ +OP_SETTABLE,/* A B C R(A)[RK(B)] := RK(C) */ + +OP_NEWTABLE,/* A B C R(A) := {} (size = B,C) */ + +OP_SELF,/* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */ + +OP_ADD,/* A B C R(A) := RK(B) + RK(C) */ +OP_SUB,/* A B C R(A) := RK(B) - RK(C) */ +OP_MUL,/* A B C R(A) := RK(B) * RK(C) */ +OP_DIV,/* A B C R(A) := RK(B) / RK(C) */ +OP_MOD,/* A B C R(A) := RK(B) % RK(C) */ +OP_POW,/* A B C R(A) := RK(B) ^ RK(C) */ +OP_UNM,/* A B R(A) := -R(B) */ +OP_NOT,/* A B R(A) := not R(B) */ +OP_LEN,/* A B R(A) := length of R(B) */ + +OP_CONCAT,/* A B C R(A) := R(B).. ... ..R(C) */ + +OP_JMP,/* sBx pc+=sBx */ + +OP_EQ,/* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */ +OP_LT,/* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */ +OP_LE,/* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */ + +OP_TEST,/* A C if not (R(A) <=> C) then pc++ */ +OP_TESTSET,/* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */ + +OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */ +OP_TAILCALL,/* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */ +OP_RETURN,/* A B return R(A), ... ,R(A+B-2) (see note) */ + +OP_FORLOOP,/* A sBx R(A)+=R(A+2); + if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }*/ +OP_FORPREP,/* A sBx R(A)-=R(A+2); pc+=sBx */ + +OP_TFORLOOP,/* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); + if R(A+3) ~= nil then R(A+2)=R(A+3) else pc++ */ +OP_SETLIST,/* A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B */ + +OP_CLOSE,/* A close all variables in the stack up to (>=) R(A)*/ +OP_CLOSURE,/* A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) */ + +OP_VARARG/* A B R(A), R(A+1), ..., R(A+B-1) = vararg */ +} OpCode; + + +#define NUM_OPCODES (cast(int, OP_VARARG) + 1) + + + +/*=========================================================================== + Notes: + (*) In OP_CALL, if (B == 0) then B = top. C is the number of returns - 1, + and can be 0: OP_CALL then sets `top' to last_result+1, so + next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use `top'. + + (*) In OP_VARARG, if (B == 0) then use actual number of varargs and + set top (like in OP_CALL with C == 0). + + (*) In OP_RETURN, if (B == 0) then return up to `top' + + (*) In OP_SETLIST, if (B == 0) then B = `top'; + if (C == 0) then next `instruction' is real C + + (*) For comparisons, A specifies what condition the test should accept + (true or false). + + (*) All `skips' (pc++) assume that next instruction is a jump +===========================================================================*/ + + +/* +** masks for instruction properties. The format is: +** bits 0-1: op mode +** bits 2-3: C arg mode +** bits 4-5: B arg mode +** bit 6: instruction set register A +** bit 7: operator is a test +*/ + +enum OpArgMask { + OpArgN, /* argument is not used */ + OpArgU, /* argument is used */ + OpArgR, /* argument is a register or a jump offset */ + OpArgK /* argument is a constant or register/constant */ +}; + +LUAI_DATA const lu_byte luaP_opmodes[NUM_OPCODES]; + +#define getOpMode(m) (cast(enum OpMode, luaP_opmodes[m] & 3)) +#define getBMode(m) (cast(enum OpArgMask, (luaP_opmodes[m] >> 4) & 3)) +#define getCMode(m) (cast(enum OpArgMask, (luaP_opmodes[m] >> 2) & 3)) +#define testAMode(m) (luaP_opmodes[m] & (1 << 6)) +#define testTMode(m) (luaP_opmodes[m] & (1 << 7)) + + +LUAI_DATA const char *const luaP_opnames[NUM_OPCODES+1]; /* opcode names */ + + +/* number of list items to accumulate before a SETLIST instruction */ +#define LFIELDS_PER_FLUSH 50 + + +#endif diff --git a/engines/sword25/util/pluto/pdep/lstate.h b/engines/sword25/util/pluto/pdep/lstate.h new file mode 100644 index 0000000000..3bc575b6bc --- /dev/null +++ b/engines/sword25/util/pluto/pdep/lstate.h @@ -0,0 +1,169 @@ +/* +** $Id: lstate.h,v 2.24.1.2 2008/01/03 15:20:39 roberto Exp $ +** Global State +** See Copyright Notice in lua.h +*/ + +#ifndef lstate_h +#define lstate_h + +#include "lua.h" + +#include "lobject.h" +#include "ltm.h" +#include "lzio.h" + + + +struct lua_longjmp; /* defined in ldo.c */ + + +/* table of globals */ +#define gt(L) (&L->l_gt) + +/* registry */ +#define registry(L) (&G(L)->l_registry) + + +/* extra stack space to handle TM calls and some other extras */ +#define EXTRA_STACK 5 + + +#define BASIC_CI_SIZE 8 + +#define BASIC_STACK_SIZE (2*LUA_MINSTACK) + + + +typedef struct stringtable { + GCObject **hash; + lu_int32 nuse; /* number of elements */ + int size; +} stringtable; + + +/* +** informations about a call +*/ +typedef struct CallInfo { + StkId base; /* base for this function */ + StkId func; /* function index in the stack */ + StkId top; /* top for this function */ + const Instruction *savedpc; + int nresults; /* expected number of results from this function */ + int tailcalls; /* number of tail calls lost under this entry */ +} CallInfo; + + + +#define curr_func(L) (clvalue(L->ci->func)) +#define ci_func(ci) (clvalue((ci)->func)) +#define f_isLua(ci) (!ci_func(ci)->c.isC) +#define isLua(ci) (ttisfunction((ci)->func) && f_isLua(ci)) + + +/* +** `global state', shared by all threads of this state +*/ +typedef struct global_State { + stringtable strt; /* hash table for strings */ + lua_Alloc frealloc; /* function to reallocate memory */ + void *ud; /* auxiliary data to `frealloc' */ + lu_byte currentwhite; + lu_byte gcstate; /* state of garbage collector */ + int sweepstrgc; /* position of sweep in `strt' */ + GCObject *rootgc; /* list of all collectable objects */ + GCObject **sweepgc; /* position of sweep in `rootgc' */ + GCObject *gray; /* list of gray objects */ + GCObject *grayagain; /* list of objects to be traversed atomically */ + GCObject *weak; /* list of weak tables (to be cleared) */ + GCObject *tmudata; /* last element of list of userdata to be GC */ + Mbuffer buff; /* temporary buffer for string concatentation */ + lu_mem GCthreshold; + lu_mem totalbytes; /* number of bytes currently allocated */ + lu_mem estimate; /* an estimate of number of bytes actually in use */ + lu_mem gcdept; /* how much GC is `behind schedule' */ + int gcpause; /* size of pause between successive GCs */ + int gcstepmul; /* GC `granularity' */ + lua_CFunction panic; /* to be called in unprotected errors */ + TValue l_registry; + struct lua_State *mainthread; + UpVal uvhead; /* head of double-linked list of all open upvalues */ + struct Table *mt[NUM_TAGS]; /* metatables for basic types */ + TString *tmname[TM_N]; /* array with tag-method names */ +} global_State; + + +/* +** `per thread' state +*/ +struct lua_State { + CommonHeader; + lu_byte status; + StkId top; /* first free slot in the stack */ + StkId base; /* base of current function */ + global_State *l_G; + CallInfo *ci; /* call info for current function */ + const Instruction *savedpc; /* `savedpc' of current function */ + StkId stack_last; /* last free slot in the stack */ + StkId stack; /* stack base */ + CallInfo *end_ci; /* points after end of ci array*/ + CallInfo *base_ci; /* array of CallInfo's */ + int stacksize; + int size_ci; /* size of array `base_ci' */ + unsigned short nCcalls; /* number of nested C calls */ + unsigned short baseCcalls; /* nested C calls when resuming coroutine */ + lu_byte hookmask; + lu_byte allowhook; + int basehookcount; + int hookcount; + lua_Hook hook; + TValue l_gt; /* table of globals */ + TValue env; /* temporary place for environments */ + GCObject *openupval; /* list of open upvalues in this stack */ + GCObject *gclist; + struct lua_longjmp *errorJmp; /* current error recover point */ + ptrdiff_t errfunc; /* current error handling function (stack index) */ +}; + + +#define G(L) (L->l_G) + + +/* +** Union of all collectable objects +*/ +union GCObject { + GCheader gch; + union TString ts; + union Udata u; + union Closure cl; + struct Table h; + struct Proto p; + struct UpVal uv; + struct lua_State th; /* thread */ +}; + + +/* macros to convert a GCObject into a specific value */ +#define rawgco2ts(o) check_exp((o)->gch.tt == LUA_TSTRING, &((o)->ts)) +#define gco2ts(o) (&rawgco2ts(o)->tsv) +#define rawgco2u(o) check_exp((o)->gch.tt == LUA_TUSERDATA, &((o)->u)) +#define gco2u(o) (&rawgco2u(o)->uv) +#define gco2cl(o) check_exp((o)->gch.tt == LUA_TFUNCTION, &((o)->cl)) +#define gco2h(o) check_exp((o)->gch.tt == LUA_TTABLE, &((o)->h)) +#define gco2p(o) check_exp((o)->gch.tt == LUA_TPROTO, &((o)->p)) +#define gco2uv(o) check_exp((o)->gch.tt == LUA_TUPVAL, &((o)->uv)) +#define ngcotouv(o) \ + check_exp((o) == NULL || (o)->gch.tt == LUA_TUPVAL, &((o)->uv)) +#define gco2th(o) check_exp((o)->gch.tt == LUA_TTHREAD, &((o)->th)) + +/* macro to convert any Lua object into a GCObject */ +#define obj2gco(v) (cast(GCObject *, (v))) + + +LUAI_FUNC lua_State *luaE_newthread (lua_State *L); +LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1); + +#endif + diff --git a/engines/sword25/util/pluto/pdep/lstring.h b/engines/sword25/util/pluto/pdep/lstring.h new file mode 100644 index 0000000000..73a2ff8b38 --- /dev/null +++ b/engines/sword25/util/pluto/pdep/lstring.h @@ -0,0 +1,31 @@ +/* +** $Id: lstring.h,v 1.43.1.1 2007/12/27 13:02:25 roberto Exp $ +** String table (keep all strings handled by Lua) +** See Copyright Notice in lua.h +*/ + +#ifndef lstring_h +#define lstring_h + + +#include "lgc.h" +#include "lobject.h" +#include "lstate.h" + + +#define sizestring(s) (sizeof(union TString)+((s)->len+1)*sizeof(char)) + +#define sizeudata(u) (sizeof(union Udata)+(u)->len) + +#define luaS_new(L, s) (luaS_newlstr(L, s, strlen(s))) +#define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \ + (sizeof(s)/sizeof(char))-1)) + +#define luaS_fix(s) l_setbit((s)->tsv.marked, FIXEDBIT) + +LUAI_FUNC void luaS_resize (lua_State *L, int newsize); +LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s, Table *e); +LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l); + + +#endif diff --git a/engines/sword25/util/pluto/pdep/ltm.h b/engines/sword25/util/pluto/pdep/ltm.h new file mode 100644 index 0000000000..64343b781b --- /dev/null +++ b/engines/sword25/util/pluto/pdep/ltm.h @@ -0,0 +1,54 @@ +/* +** $Id: ltm.h,v 2.6.1.1 2007/12/27 13:02:25 roberto Exp $ +** Tag methods +** See Copyright Notice in lua.h +*/ + +#ifndef ltm_h +#define ltm_h + + +#include "lobject.h" + + +/* +* WARNING: if you change the order of this enumeration, +* grep "ORDER TM" +*/ +typedef enum { + TM_INDEX, + TM_NEWINDEX, + TM_GC, + TM_MODE, + TM_EQ, /* last tag method with `fast' access */ + TM_ADD, + TM_SUB, + TM_MUL, + TM_DIV, + TM_MOD, + TM_POW, + TM_UNM, + TM_LEN, + TM_LT, + TM_LE, + TM_CONCAT, + TM_CALL, + TM_N /* number of elements in the enum */ +} TMS; + + + +#define gfasttm(g,et,e) ((et) == NULL ? NULL : \ + ((et)->flags & (1u<<(e))) ? NULL : luaT_gettm(et, e, (g)->tmname[e])) + +#define fasttm(l,et,e) gfasttm(G(l), et, e) + +LUAI_DATA const char *const luaT_typenames[]; + + +LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename); +LUAI_FUNC const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, + TMS event); +LUAI_FUNC void luaT_init (lua_State *L); + +#endif diff --git a/engines/sword25/util/pluto/pdep/lua.h b/engines/sword25/util/pluto/pdep/lua.h new file mode 100644 index 0000000000..0f3f28fce5 --- /dev/null +++ b/engines/sword25/util/pluto/pdep/lua.h @@ -0,0 +1,388 @@ +/* +** $Id: lua.h,v 1.218.1.4 2008/01/03 15:41:15 roberto Exp $ +** Lua - An Extensible Extension Language +** Lua.org, PUC-Rio, Brazil (http://www.lua.org) +** See Copyright Notice at the end of this file +*/ + + +#ifndef lua_h +#define lua_h + +#include <stdarg.h> +#include <stddef.h> + + +#include "sword25/util/lua/luaconf.h" + + +#define LUA_VERSION "Lua 5.1" +#define LUA_RELEASE "Lua 5.1.3" +#define LUA_VERSION_NUM 501 +#define LUA_COPYRIGHT "Copyright (C) 1994-2008 Lua.org, PUC-Rio" +#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes" + + +/* mark for precompiled code (`<esc>Lua') */ +#define LUA_SIGNATURE "\033Lua" + +/* option for multiple returns in `lua_pcall' and `lua_call' */ +#define LUA_MULTRET (-1) + + +/* +** pseudo-indices +*/ +#define LUA_REGISTRYINDEX (-10000) +#define LUA_ENVIRONINDEX (-10001) +#define LUA_GLOBALSINDEX (-10002) +#define lua_upvalueindex(i) (LUA_GLOBALSINDEX-(i)) + + +/* thread status; 0 is OK */ +#define LUA_YIELD 1 +#define LUA_ERRRUN 2 +#define LUA_ERRSYNTAX 3 +#define LUA_ERRMEM 4 +#define LUA_ERRERR 5 + + +typedef struct lua_State lua_State; + +typedef int (*lua_CFunction) (lua_State *L); + + +/* +** functions that read/write blocks when loading/dumping Lua chunks +*/ +typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz); + +typedef int (*lua_Writer) (lua_State *L, const void* p, size_t sz, void* ud); + + +/* +** prototype for memory-allocation functions +*/ +typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize); + + +/* +** basic types +*/ +#define LUA_TNONE (-1) + +#define LUA_TNIL 0 +#define LUA_TBOOLEAN 1 +#define LUA_TLIGHTUSERDATA 2 +#define LUA_TNUMBER 3 +#define LUA_TSTRING 4 +#define LUA_TTABLE 5 +#define LUA_TFUNCTION 6 +#define LUA_TUSERDATA 7 +#define LUA_TTHREAD 8 + + + +/* minimum Lua stack available to a C function */ +#define LUA_MINSTACK 20 + + +/* +** generic extra include file +*/ +#if defined(LUA_USER_H) +#include LUA_USER_H +#endif + + +/* type of numbers in Lua */ +typedef LUA_NUMBER lua_Number; + + +/* type for integer functions */ +typedef LUA_INTEGER lua_Integer; + + + +/* +** state manipulation +*/ +LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud); +LUA_API void (lua_close) (lua_State *L); +LUA_API lua_State *(lua_newthread) (lua_State *L); + +LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf); + + +/* +** basic stack manipulation +*/ +LUA_API int (lua_gettop) (lua_State *L); +LUA_API void (lua_settop) (lua_State *L, int idx); +LUA_API void (lua_pushvalue) (lua_State *L, int idx); +LUA_API void (lua_remove) (lua_State *L, int idx); +LUA_API void (lua_insert) (lua_State *L, int idx); +LUA_API void (lua_replace) (lua_State *L, int idx); +LUA_API int (lua_checkstack) (lua_State *L, int sz); + +LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n); + + +/* +** access functions (stack -> C) +*/ + +LUA_API int (lua_isnumber) (lua_State *L, int idx); +LUA_API int (lua_isstring) (lua_State *L, int idx); +LUA_API int (lua_iscfunction) (lua_State *L, int idx); +LUA_API int (lua_isuserdata) (lua_State *L, int idx); +LUA_API int (lua_type) (lua_State *L, int idx); +LUA_API const char *(lua_typename) (lua_State *L, int tp); + +LUA_API int (lua_equal) (lua_State *L, int idx1, int idx2); +LUA_API int (lua_rawequal) (lua_State *L, int idx1, int idx2); +LUA_API int (lua_lessthan) (lua_State *L, int idx1, int idx2); + +LUA_API lua_Number (lua_tonumber) (lua_State *L, int idx); +LUA_API lua_Integer (lua_tointeger) (lua_State *L, int idx); +LUA_API int (lua_toboolean) (lua_State *L, int idx); +LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len); +LUA_API size_t (lua_objlen) (lua_State *L, int idx); +LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx); +LUA_API void *(lua_touserdata) (lua_State *L, int idx); +LUA_API lua_State *(lua_tothread) (lua_State *L, int idx); +LUA_API const void *(lua_topointer) (lua_State *L, int idx); + + +/* +** push functions (C -> stack) +*/ +LUA_API void (lua_pushnil) (lua_State *L); +LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n); +LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n); +LUA_API void (lua_pushlstring) (lua_State *L, const char *s, size_t l); +LUA_API void (lua_pushstring) (lua_State *L, const char *s); +LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt, + va_list argp); +LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...); +LUA_API void (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n); +LUA_API void (lua_pushboolean) (lua_State *L, int b); +LUA_API void (lua_pushlightuserdata) (lua_State *L, void *p); +LUA_API int (lua_pushthread) (lua_State *L); + + +/* +** get functions (Lua -> stack) +*/ +LUA_API void (lua_gettable) (lua_State *L, int idx); +LUA_API void (lua_getfield) (lua_State *L, int idx, const char *k); +LUA_API void (lua_rawget) (lua_State *L, int idx); +LUA_API void (lua_rawgeti) (lua_State *L, int idx, int n); +LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec); +LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz); +LUA_API int (lua_getmetatable) (lua_State *L, int objindex); +LUA_API void (lua_getfenv) (lua_State *L, int idx); + + +/* +** set functions (stack -> Lua) +*/ +LUA_API void (lua_settable) (lua_State *L, int idx); +LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k); +LUA_API void (lua_rawset) (lua_State *L, int idx); +LUA_API void (lua_rawseti) (lua_State *L, int idx, int n); +LUA_API int (lua_setmetatable) (lua_State *L, int objindex); +LUA_API int (lua_setfenv) (lua_State *L, int idx); + + +/* +** `load' and `call' functions (load and run Lua code) +*/ +LUA_API void (lua_call) (lua_State *L, int nargs, int nresults); +LUA_API int (lua_pcall) (lua_State *L, int nargs, int nresults, int errfunc); +LUA_API int (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud); +LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt, + const char *chunkname); + +LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data); + + +/* +** coroutine functions +*/ +LUA_API int (lua_yield) (lua_State *L, int nresults); +LUA_API int (lua_resume) (lua_State *L, int narg); +LUA_API int (lua_status) (lua_State *L); + +/* +** garbage-collection function and options +*/ + +#define LUA_GCSTOP 0 +#define LUA_GCRESTART 1 +#define LUA_GCCOLLECT 2 +#define LUA_GCCOUNT 3 +#define LUA_GCCOUNTB 4 +#define LUA_GCSTEP 5 +#define LUA_GCSETPAUSE 6 +#define LUA_GCSETSTEPMUL 7 + +LUA_API int (lua_gc) (lua_State *L, int what, int data); + + +/* +** miscellaneous functions +*/ + +LUA_API int (lua_error) (lua_State *L); + +LUA_API int (lua_next) (lua_State *L, int idx); + +LUA_API void (lua_concat) (lua_State *L, int n); + +LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud); +LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud); + + + +/* +** =============================================================== +** some useful macros +** =============================================================== +*/ + +#define lua_pop(L,n) lua_settop(L, -(n)-1) + +#define lua_newtable(L) lua_createtable(L, 0, 0) + +#define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n))) + +#define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0) + +#define lua_strlen(L,i) lua_objlen(L, (i)) + +#define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION) +#define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE) +#define lua_islightuserdata(L,n) (lua_type(L, (n)) == LUA_TLIGHTUSERDATA) +#define lua_isnil(L,n) (lua_type(L, (n)) == LUA_TNIL) +#define lua_isboolean(L,n) (lua_type(L, (n)) == LUA_TBOOLEAN) +#define lua_isthread(L,n) (lua_type(L, (n)) == LUA_TTHREAD) +#define lua_isnone(L,n) (lua_type(L, (n)) == LUA_TNONE) +#define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0) + +#define lua_pushliteral(L, s) \ + lua_pushlstring(L, "" s, (sizeof(s)/sizeof(char))-1) + +#define lua_setglobal(L,s) lua_setfield(L, LUA_GLOBALSINDEX, (s)) +#define lua_getglobal(L,s) lua_getfield(L, LUA_GLOBALSINDEX, (s)) + +#define lua_tostring(L,i) lua_tolstring(L, (i), NULL) + + + +/* +** compatibility macros and functions +*/ + +#define lua_open() luaL_newstate() + +#define lua_getregistry(L) lua_pushvalue(L, LUA_REGISTRYINDEX) + +#define lua_getgccount(L) lua_gc(L, LUA_GCCOUNT, 0) + +#define lua_Chunkreader lua_Reader +#define lua_Chunkwriter lua_Writer + + +/* hack */ +LUA_API void lua_setlevel (lua_State *from, lua_State *to); + + +/* +** {====================================================================== +** Debug API +** ======================================================================= +*/ + + +/* +** Event codes +*/ +#define LUA_HOOKCALL 0 +#define LUA_HOOKRET 1 +#define LUA_HOOKLINE 2 +#define LUA_HOOKCOUNT 3 +#define LUA_HOOKTAILRET 4 + + +/* +** Event masks +*/ +#define LUA_MASKCALL (1 << LUA_HOOKCALL) +#define LUA_MASKRET (1 << LUA_HOOKRET) +#define LUA_MASKLINE (1 << LUA_HOOKLINE) +#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT) + +typedef struct lua_Debug lua_Debug; /* activation record */ + + +/* Functions to be called by the debuger in specific events */ +typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar); + + +LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar); +LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar); +LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n); +LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n); +LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n); +LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n); + +LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count); +LUA_API lua_Hook lua_gethook (lua_State *L); +LUA_API int lua_gethookmask (lua_State *L); +LUA_API int lua_gethookcount (lua_State *L); + + +struct lua_Debug { + int event; + const char *name; /* (n) */ + const char *namewhat; /* (n) `global', `local', `field', `method' */ + const char *what; /* (S) `Lua', `C', `main', `tail' */ + const char *source; /* (S) */ + int currentline; /* (l) */ + int nups; /* (u) number of upvalues */ + int linedefined; /* (S) */ + int lastlinedefined; /* (S) */ + char short_src[LUA_IDSIZE]; /* (S) */ + /* private part */ + int i_ci; /* active function */ +}; + +/* }====================================================================== */ + + +/****************************************************************************** +* Copyright (C) 1994-2008 Lua.org, PUC-Rio. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +******************************************************************************/ + + +#endif diff --git a/engines/sword25/util/pluto/pdep/lzio.h b/engines/sword25/util/pluto/pdep/lzio.h new file mode 100644 index 0000000000..4e654a52c9 --- /dev/null +++ b/engines/sword25/util/pluto/pdep/lzio.h @@ -0,0 +1,65 @@ +/* +** $Id: lzio.h,v 1.21.1.1 2007/12/27 13:02:25 roberto Exp $ +** Buffered streams +** See Copyright Notice in lua.h +*/ + + +#ifndef lzio_h +#define lzio_h + +#include "lua.h" + + +#define EOZ (-1) /* end of stream */ + +typedef struct Zio ZIO; + +#define char2int(c) cast(int, cast(unsigned char, (c))) + +#define zgetc(z) (((z)->n--)>0 ? char2int(*(z)->p++) : pdep_fill(z)) + +typedef struct Mbuffer { + char *buffer; + size_t n; + size_t buffsize; +} Mbuffer; + +#define pdep_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->buffsize = 0) + +#define pdep_buffer(buff) ((buff)->buffer) +#define pdep_sizebuffer(buff) ((buff)->buffsize) +#define pdep_bufflen(buff) ((buff)->n) + +#define pdep_resetbuffer(buff) ((buff)->n = 0) + + +#define pdep_resizebuffer(L, buff, size) \ + (pdep_reallocvector(L, (buff)->buffer, (buff)->buffsize, size, char), \ + (buff)->buffsize = size) + +#define pdep_freebuffer(L, buff) pdep_resizebuffer(L, buff, 0) + + +LUAI_FUNC char *pdep_openspace (lua_State *L, Mbuffer *buff, size_t n); +LUAI_FUNC void pdep_init (lua_State *L, ZIO *z, lua_Reader reader, + void *data); +LUAI_FUNC size_t pdep_read (ZIO* z, void* b, size_t n); /* read next n bytes */ +LUAI_FUNC int pdep_lookahead (ZIO *z); + + + +/* --------- Private Part ------------------ */ + +struct Zio { + size_t n; /* bytes still unread */ + const char *p; /* current position in buffer */ + lua_Reader reader; + void* data; /* additional data */ + lua_State *L; /* Lua state (for reader) */ +}; + + +LUAI_FUNC int pdep_fill (ZIO *z); + +#endif diff --git a/engines/sword25/util/pluto/pdep/pdep.h b/engines/sword25/util/pluto/pdep/pdep.h new file mode 100644 index 0000000000..c26f4566c5 --- /dev/null +++ b/engines/sword25/util/pluto/pdep/pdep.h @@ -0,0 +1,41 @@ +#ifndef PDEP_H +#define PDEP_H + +#include "lua.h" +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "llimits.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lstate.h" +#include "lstring.h" +#include "lauxlib.h" + + +#define pdep_reallocv(L,b,on,n,e) \ + pdep_realloc_(L, (b), (on)*(e), (n)*(e)) +#define pdep_reallocvector(L, v,oldn,n,t) \ + ((v)=cast(t *, pdep_reallocv(L, v, oldn, n, sizeof(t)))) +#define pdep_freearray(L, b, n, t) pdep_reallocv(L, (b), n, 0, sizeof(t)) +#define pdep_newvector(L,n,t) \ + cast(t *, pdep_reallocv(L, NULL, 0, n, sizeof(t))) +#define pdep_new(L,t) cast(t *, pdep_malloc(L, sizeof(t))) +#define pdep_malloc(L,t) pdep_realloc_(L, NULL, 0, (t)) +#define pdep_checkstack(L,n) \ + if ((char *)L->stack_last - (char *)L->top <= (n)*(int)sizeof(TValue)) \ + pdep_growstack(L, n); \ + else pdep_reallocstack(L, L->stacksize - EXTRA_STACK - 1); + + +void pdep_pushobject (lua_State *L, const TValue *o); +void *pdep_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize); +void pdep_link (lua_State *L, GCObject *o, lu_byte tt); +Proto *pdep_newproto (lua_State *L); +Closure *pdep_newLclosure (lua_State *L, int nelems, Table *e); +void pdep_reallocstack (lua_State *L, int newsize); +void pdep_growstack (lua_State *L, int n); +void pdep_reallocCI (lua_State *L, int newsize); +TString *pdep_newlstr (lua_State *L, const char *str, size_t l); + +#endif diff --git a/engines/sword25/util/pluto/pluto.c b/engines/sword25/util/pluto/pluto.c new file mode 100644 index 0000000000..61eb40e984 --- /dev/null +++ b/engines/sword25/util/pluto/pluto.c @@ -0,0 +1,1658 @@ +/* $Id$ */ + +/* Pluto - Heavy-duty persistence for Lua + * Copyright (C) 2004 by Ben Sunshine-Hill, and released into the public + * domain. People making use of this software as part of an application + * are politely requested to email the author at sneftel@gmail.com + * with a brief description of the application, primarily to satisfy his + * curiosity. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "sword25/util/lua/lua.h" +#include "pluto.h" + +#define USE_PDEP + +#ifdef USE_PDEP +#include "pdep/pdep.h" +#define LIF(prefix, name) pdep ## _ ## name +#else +#include "lapi.h" +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "llimits.h" +#include "lmem.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lstate.h" +#include "lstring.h" +#include "lauxlib.h" +#define LIF(prefix, name) lua ## prefix ## _ ## name +#endif + +#include <string.h> + + + +/* #define PLUTO_DEBUG */ + + + + +#ifdef PLUTO_DEBUG +#include <stdio.h> +#endif + +#define PLUTO_TPERMANENT 101 + +#define verify(x) { int v = (int)((x)); v=v; lua_assert(v); } + +typedef struct PersistInfo_t { + lua_State *L; + int counter; + lua_Chunkwriter writer; + void *ud; +#ifdef PLUTO_DEBUG + int level; +#endif +} PersistInfo; + +#ifdef PLUTO_DEBUG +void printindent(int indent) +{ + int il; + for(il=0; il<indent; il++) { + printf(" "); + } +} +#endif + +/* Mutual recursion requires prototype */ +static void persist(PersistInfo *pi); + +/* A simple reimplementation of the unfortunately static function luaA_index. + * Does not support the global table, registry, or upvalues. */ +static StkId getobject(lua_State *L, int stackpos) +{ + if(stackpos > 0) { + lua_assert(L->base+stackpos-1 < L->top); + return L->base+stackpos-1; + } else { + lua_assert(L->top-stackpos >= L->base); + return L->top+stackpos; + } +} + +/* Choose whether to do a regular or special persistence based on an object's + * metatable. "default" is whether the object, if it doesn't have a __persist + * entry, is literally persistable or not. + * Pushes the unpersist closure and returns true if special persistence is + * used. */ +static int persistspecialobject(PersistInfo *pi, int defaction) +{ + /* perms reftbl ... obj */ + lua_checkstack(pi->L, 4); + /* Check whether we should persist literally, or via the __persist + * metafunction */ + if(!lua_getmetatable(pi->L, -1)) { + if(defaction) { + { + int zero = 0; + pi->writer(pi->L, &zero, sizeof(int), pi->ud); + } + return 0; + } else { + lua_pushstring(pi->L, "Type not literally persistable by default"); + lua_error(pi->L); + } + } + /* perms reftbl sptbl ... obj mt */ + lua_pushstring(pi->L, "__persist"); + /* perms reftbl sptbl ... obj mt "__persist" */ + lua_rawget(pi->L, -2); + /* perms reftbl sptbl ... obj mt __persist? */ + if(lua_isnil(pi->L, -1)) { + /* perms reftbl sptbl ... obj mt nil */ + lua_pop(pi->L, 2); + /* perms reftbl sptbl ... obj */ + if(defaction) { + { + int zero = 0; + pi->writer(pi->L, &zero, sizeof(int), pi->ud); + } + return 0; + } else { + lua_pushstring(pi->L, "Type not literally persistable by default"); + lua_error(pi->L); + return 0; /* not reached */ + } + } else if(lua_isboolean(pi->L, -1)) { + /* perms reftbl sptbl ... obj mt bool */ + if(lua_toboolean(pi->L, -1)) { + /* perms reftbl sptbl ... obj mt true */ + lua_pop(pi->L, 2); + /* perms reftbl sptbl ... obj */ + { + int zero = 0; + pi->writer(pi->L, &zero, sizeof(int), pi->ud); + } + return 0; + } else { + lua_pushstring(pi->L, "Metatable forbade persistence"); + lua_error(pi->L); + return 0; /* not reached */ + } + } else if(!lua_isfunction(pi->L, -1)) { + lua_pushstring(pi->L, "__persist not nil, boolean, or function"); + lua_error(pi->L); + } + /* perms reftbl ... obj mt __persist */ + lua_pushvalue(pi->L, -3); + /* perms reftbl ... obj mt __persist obj */ +#ifdef PLUTO_PASS_USERDATA_TO_PERSIST + lua_pushlightuserdata(pi->L, (void*)pi->writer); + lua_pushlightuserdata(pi->L, pi->ud); + /* perms reftbl ... obj mt __persist obj ud */ + lua_call(pi->L, 3, 1); + /* perms reftbl ... obj mt func? */ +#else + lua_call(pi->L, 1, 1); + /* perms reftbl ... obj mt func? */ +#endif + /* perms reftbl ... obj mt func? */ + if(!lua_isfunction(pi->L, -1)) { + lua_pushstring(pi->L, "__persist function did not return a function"); + lua_error(pi->L); + } + /* perms reftbl ... obj mt func */ + { + int one = 1; + pi->writer(pi->L, &one, sizeof(int), pi->ud); + } + persist(pi); + /* perms reftbl ... obj mt func */ + lua_pop(pi->L, 2); + /* perms reftbl ... obj */ + return 1; +} + +static void persisttable(PersistInfo *pi) +{ + /* perms reftbl ... tbl */ + lua_checkstack(pi->L, 3); + if(persistspecialobject(pi, 1)) { + /* perms reftbl ... tbl */ + return; + } + /* perms reftbl ... tbl */ + /* First, persist the metatable (if any) */ + if(!lua_getmetatable(pi->L, -1)) { + lua_pushnil(pi->L); + } + /* perms reftbl ... tbl mt/nil */ + persist(pi); + lua_pop(pi->L, 1); + /* perms reftbl ... tbl */ + + /* Now, persist all k/v pairs */ + lua_pushnil(pi->L); + /* perms reftbl ... tbl nil */ + while(lua_next(pi->L, -2)) { + /* perms reftbl ... tbl k v */ + lua_pushvalue(pi->L, -2); + /* perms reftbl ... tbl k v k */ + persist(pi); + lua_pop(pi->L, 1); + /* perms reftbl ... tbl k v */ + persist(pi); + lua_pop(pi->L, 1); + /* perms reftbl ... tbl k */ + } + /* perms reftbl ... tbl */ + /* Terminate list */ + lua_pushnil(pi->L); + /* perms reftbl ... tbl nil */ + persist(pi); + lua_pop(pi->L, 1); + /* perms reftbl ... tbl */ +} + +static void persistuserdata(PersistInfo *pi) { + /* perms reftbl ... udata */ + lua_checkstack(pi->L, 2); + if(persistspecialobject(pi, 0)) { + /* perms reftbl ... udata */ + return; + } else { + /* Use literal persistence */ + size_t length = uvalue(getobject(pi->L, -1))->len; + pi->writer(pi->L, &length, sizeof(size_t), pi->ud); + pi->writer(pi->L, lua_touserdata(pi->L, -1), length, pi->ud); + if(!lua_getmetatable(pi->L, -1)) { + /* perms reftbl ... udata */ + lua_pushnil(pi->L); + /* perms reftbl ... udata mt/nil */ + } + persist(pi); + lua_pop(pi->L, 1); + /* perms reftbl ... udata */ + } +} + + +static Proto *toproto(lua_State *L, int stackpos) +{ + return gco2p(getobject(L, stackpos)->value.gc); +} + +static UpVal *toupval(lua_State *L, int stackpos) +{ + lua_assert(ttype(getobject(L, stackpos)) == LUA_TUPVAL); + return gco2uv(getobject(L, stackpos)->value.gc); +} + +static void pushproto(lua_State *L, Proto *proto) +{ + TValue o; + setptvalue(L, &o, proto); + LIF(A,pushobject)(L, &o); +} + +#define setuvvalue(L,obj,x) \ + { TValue *i_o=(obj); \ + i_o->value.gc=cast(GCObject *, (x)); i_o->tt=LUA_TUPVAL; \ + checkliveness(G(L),i_o); } + +static void pushupval(lua_State *L, UpVal *upval) +{ + TValue o; + setuvvalue(L, &o, upval); + LIF(A,pushobject)(L, &o); +} + +static void pushclosure(lua_State *L, Closure *closure) +{ + TValue o; + setclvalue(L, &o, closure); + LIF(A,pushobject)(L, &o); +} + +static void pushstring(lua_State *L, TString *s) +{ + TValue o; + setsvalue(L, &o, s); + LIF(A,pushobject)(L, &o); +} + +static void persistfunction(PersistInfo *pi) +{ + /* perms reftbl ... func */ + Closure *cl = clvalue(getobject(pi->L, -1)); + lua_checkstack(pi->L, 2); + if(cl->c.isC) { + /* It's a C function. For now, we aren't going to allow + * persistence of C closures, even if the "C proto" is + * already in the permanents table. */ + lua_pushstring(pi->L, "Attempt to persist a C function"); + lua_error(pi->L); + } else { + /* It's a Lua closure. */ + { + /* We don't really _NEED_ the number of upvals, + * but it'll simplify things a bit */ + pi->writer(pi->L, &cl->l.p->nups, sizeof(lu_byte), pi->ud); + } + /* Persist prototype */ + { + pushproto(pi->L, cl->l.p); + /* perms reftbl ... func proto */ + persist(pi); + lua_pop(pi->L, 1); + /* perms reftbl ... func */ + } + /* Persist upvalue values (not the upvalue objects + * themselves) */ + { + int i; + for(i=0; i<cl->l.p->nups; i++) { + /* perms reftbl ... func */ + pushupval(pi->L, cl->l.upvals[i]); + /* perms reftbl ... func upval */ + persist(pi); + lua_pop(pi->L, 1); + /* perms reftbl ... func */ + } + /* perms reftbl ... func */ + } + /* Persist function environment */ + { + lua_getfenv(pi->L, -1); + /* perms reftbl ... func fenv */ + if(lua_equal(pi->L, -1, LUA_GLOBALSINDEX)) { + /* Function has the default fenv */ + /* perms reftbl ... func _G */ + lua_pop(pi->L, 1); + /* perms reftbl ... func */ + lua_pushnil(pi->L); + /* perms reftbl ... func nil */ + } + /* perms reftbl ... func fenv/nil */ + persist(pi); + lua_pop(pi->L, 1); + /* perms reftbl ... func */ + } + } +} + + +/* Upvalues are tricky. Here's why. + * + * A particular upvalue may be either "open", in which case its member v + * points into a thread's stack, or "closed" in which case it points to the + * upvalue itself. An upvalue is closed under any of the following conditions: + * -- The function that initially declared the variable "local" returns + * -- The thread in which the closure was created is garbage collected + * + * To make things wackier, just because a thread is reachable by Lua doesn't + * mean it's in our root set. We need to be able to treat an open upvalue + * from an unreachable thread as a closed upvalue. + * + * The solution: + * (a) For the purposes of persisting, don't indicate whether an upvalue is + * closed or not. + * (b) When unpersisting, pretend that all upvalues are closed. + * (c) When persisting, persist all open upvalues referenced by a thread + * that is persisted, and tag each one with the corresponding stack position + * (d) When unpersisting, "reopen" each of these upvalues as the thread is + * unpersisted + */ +static void persistupval(PersistInfo *pi) +{ + /* perms reftbl ... upval */ + UpVal *uv = toupval(pi->L, -1); + lua_checkstack(pi->L, 1); + + /* We can't permit the upval to linger around on the stack, as Lua + * will bail if its GC finds it. */ + + lua_pop(pi->L, 1); + /* perms reftbl ... */ + LIF(A,pushobject)(pi->L, uv->v); + /* perms reftbl ... obj */ + persist(pi); + /* perms reftbl ... obj */ +} + +static void persistproto(PersistInfo *pi) +{ + /* perms reftbl ... proto */ + Proto *p = toproto(pi->L, -1); + lua_checkstack(pi->L, 2); + + /* Persist constant refs */ + { + int i; + pi->writer(pi->L, &p->sizek, sizeof(int), pi->ud); + for(i=0; i<p->sizek; i++) { + LIF(A,pushobject)(pi->L, &p->k[i]); + /* perms reftbl ... proto const */ + persist(pi); + lua_pop(pi->L, 1); + /* perms reftbl ... proto */ + } + } + /* perms reftbl ... proto */ + + /* serialize inner Proto refs */ + { + int i; + pi->writer(pi->L, &p->sizep, sizeof(int), pi->ud); + for(i=0; i<p->sizep; i++) + { + pushproto(pi->L, p->p[i]); + /* perms reftbl ... proto subproto */ + persist(pi); + lua_pop(pi->L, 1); + /* perms reftbl ... proto */ + } + } + /* perms reftbl ... proto */ + + /* Serialize code */ + { + pi->writer(pi->L, &p->sizecode, sizeof(int), pi->ud); + pi->writer(pi->L, p->code, sizeof(Instruction) * p->sizecode, pi->ud); + } + + /* Serialize upvalue names */ + { + int i; + pi->writer(pi->L, &p->sizeupvalues, sizeof(int), pi->ud); + for(i=0; i<p->sizeupvalues; i++) + { + pushstring(pi->L, p->upvalues[i]); + persist(pi); + lua_pop(pi->L, 1); + } + } + /* Serialize local variable infos */ + { + int i; + pi->writer(pi->L, &p->sizelocvars, sizeof(int), pi->ud); + for(i=0; i<p->sizelocvars; i++) + { + pushstring(pi->L, p->locvars[i].varname); + persist(pi); + lua_pop(pi->L, 1); + + pi->writer(pi->L, &p->locvars[i].startpc, sizeof(int), pi->ud); + pi->writer(pi->L, &p->locvars[i].endpc, sizeof(int), pi->ud); + } + } + + /* Serialize source string */ + pushstring(pi->L, p->source); + persist(pi); + lua_pop(pi->L, 1); + + /* Serialize line numbers */ + { + pi->writer(pi->L, &p->sizelineinfo, sizeof(int), pi->ud); + if (p->sizelineinfo) + { + pi->writer(pi->L, p->lineinfo, sizeof(int) * p->sizelineinfo, pi->ud); + } + } + + /* Serialize linedefined and lastlinedefined */ + pi->writer(pi->L, &p->linedefined, sizeof(int), pi->ud); + pi->writer(pi->L, &p->lastlinedefined, sizeof(int), pi->ud); + + /* Serialize misc values */ + { + pi->writer(pi->L, &p->nups, sizeof(lu_byte), pi->ud); + pi->writer(pi->L, &p->numparams, sizeof(lu_byte), pi->ud); + pi->writer(pi->L, &p->is_vararg, sizeof(lu_byte), pi->ud); + pi->writer(pi->L, &p->maxstacksize, sizeof(lu_byte), pi->ud); + } + /* We do not currently persist upvalue names, local variable names, + * variable lifetimes, line info, or source code. */ +} + +/* Copies a stack, but the stack is reversed in the process + */ +static size_t revappendstack(lua_State *from, lua_State *to) +{ + StkId o; + for(o=from->top-1; o>=from->stack; o--) { + setobj2s(to, to->top, o); + to->top++; + } + return from->top - from->stack; +} + +/* Persist all stack members + */ +static void persistthread(PersistInfo *pi) +{ + size_t posremaining; + lua_State *L2; + /* perms reftbl ... thr */ + L2 = lua_tothread(pi->L, -1); + lua_checkstack(pi->L, L2->top - L2->stack + 1); + if(pi->L == L2) { + lua_pushstring(pi->L, "Can't persist currently running thread"); + lua_error(pi->L); + return; /* not reached */ + } + + /* Persist the stack */ + posremaining = revappendstack(L2, pi->L); + /* perms reftbl ... thr (rev'ed contents of L2) */ + pi->writer(pi->L, &posremaining, sizeof(size_t), pi->ud); + for(; posremaining > 0; posremaining--) { + persist(pi); + lua_pop(pi->L, 1); + } + /* perms reftbl ... thr */ + /* Now, persist the CallInfo stack. */ + { + size_t i, numframes = (L2->ci - L2->base_ci) + 1; + pi->writer(pi->L, &numframes, sizeof(size_t), pi->ud); + for(i=0; i<numframes; i++) { + CallInfo *ci = L2->base_ci + i; + size_t stackbase = ci->base - L2->stack; + size_t stackfunc = ci->func - L2->stack; + size_t stacktop = ci->top - L2->stack; + size_t savedpc = (ci != L2->base_ci) ? + ci->savedpc - ci_func(ci)->l.p->code : + 0; + pi->writer(pi->L, &stackbase, sizeof(size_t), pi->ud); + pi->writer(pi->L, &stackfunc, sizeof(size_t), pi->ud); + pi->writer(pi->L, &stacktop, sizeof(size_t), pi->ud); + pi->writer(pi->L, &ci->nresults, sizeof(int), pi->ud); + pi->writer(pi->L, &savedpc, sizeof(size_t), pi->ud); + } + } + + /* Serialize the state's other parameters, with the exception of upval stuff */ + { + size_t stackbase = L2->base - L2->stack; + size_t stacktop = L2->top - L2->stack; + lua_assert(L2->nCcalls <= 1); + pi->writer(pi->L, &L2->status, sizeof(lu_byte), pi->ud); + pi->writer(pi->L, &stackbase, sizeof(size_t), pi->ud); + pi->writer(pi->L, &stacktop, sizeof(size_t), pi->ud); + pi->writer(pi->L, &L2->errfunc, sizeof(ptrdiff_t), pi->ud); + } + + /* Finally, record upvalues which need to be reopened */ + /* See the comment above persistupval() for why we do this */ + { + GCObject *gco; + UpVal *uv; + /* perms reftbl ... thr */ + for(gco = L2->openupval; gco != NULL; gco = uv->next) { + size_t stackpos; + uv = gco2uv(gco); + + /* Make sure upvalue is really open */ + lua_assert(uv->v != &uv->u.value); + pushupval(pi->L, uv); + /* perms reftbl ... thr uv */ + persist(pi); + lua_pop(pi->L, 1); + /* perms reftbl ... thr */ + stackpos = uv->v - L2->stack; + pi->writer(pi->L, &stackpos, sizeof(size_t), pi->ud); + } + /* perms reftbl ... thr */ + lua_pushnil(pi->L); + /* perms reftbl ... thr nil */ + persist(pi); + lua_pop(pi->L, 1); + /* perms reftbl ... thr */ + } + /* perms reftbl ... thr */ +} + +static void persistboolean(PersistInfo *pi) +{ + int b = lua_toboolean(pi->L, -1); + pi->writer(pi->L, &b, sizeof(int), pi->ud); +} + +static void persistlightuserdata(PersistInfo *pi) +{ + void *p = lua_touserdata(pi->L, -1); + pi->writer(pi->L, &p, sizeof(void *), pi->ud); +} + +static void persistnumber(PersistInfo *pi) +{ + lua_Number n = lua_tonumber(pi->L, -1); + pi->writer(pi->L, &n, sizeof(lua_Number), pi->ud); +} + +static void persiststring(PersistInfo *pi) +{ + size_t length = lua_strlen(pi->L, -1); + pi->writer(pi->L, &length, sizeof(size_t), pi->ud); + pi->writer(pi->L, lua_tostring(pi->L, -1), length, pi->ud); +} + +/* Top-level delegating persist function + */ +static void persist(PersistInfo *pi) +{ + /* perms reftbl ... obj */ + lua_checkstack(pi->L, 2); + /* If the object has already been written, write a reference to it */ + lua_pushvalue(pi->L, -1); + /* perms reftbl ... obj obj */ + lua_rawget(pi->L, 2); + /* perms reftbl ... obj ref? */ + if(!lua_isnil(pi->L, -1)) { + /* perms reftbl ... obj ref */ + int zero = 0; + int ref = (int)lua_touserdata(pi->L, -1); + pi->writer(pi->L, &zero, sizeof(int), pi->ud); + pi->writer(pi->L, &ref, sizeof(int), pi->ud); + lua_pop(pi->L, 1); + /* perms reftbl ... obj ref */ +#ifdef PLUTO_DEBUG + printindent(pi->level); + printf("0 %d\n", ref); +#endif + return; + } + /* perms reftbl ... obj nil */ + lua_pop(pi->L, 1); + /* perms reftbl ... obj */ + /* If the object is nil, write the pseudoreference 0 */ + if(lua_isnil(pi->L, -1)) { + int zero = 0; + /* firsttime */ + pi->writer(pi->L, &zero, sizeof(int), pi->ud); + /* ref */ + pi->writer(pi->L, &zero, sizeof(int), pi->ud); +#ifdef PLUTO_DEBUG + printindent(pi->level); + printf("0 0\n"); +#endif + return; + } + { + /* indicate that it's the first time */ + int one = 1; + pi->writer(pi->L, &one, sizeof(int), pi->ud); + } + lua_pushvalue(pi->L, -1); + /* perms reftbl ... obj obj */ + lua_pushlightuserdata(pi->L, (void*)(++(pi->counter))); + /* perms reftbl ... obj obj ref */ + lua_rawset(pi->L, 2); + /* perms reftbl ... obj */ + + pi->writer(pi->L, &pi->counter, sizeof(int), pi->ud); + + + /* At this point, we'll give the permanents table a chance to play. */ + { + lua_pushvalue(pi->L, -1); + /* perms reftbl ... obj obj */ + lua_gettable(pi->L, 1); + /* perms reftbl ... obj permkey? */ + if(!lua_isnil(pi->L, -1)) { + /* perms reftbl ... obj permkey */ + int type = PLUTO_TPERMANENT; +#ifdef PLUTO_DEBUG + printindent(pi->level); + printf("1 %d PERM\n", pi->counter); + pi->level++; +#endif + pi->writer(pi->L, &type, sizeof(int), pi->ud); + persist(pi); + lua_pop(pi->L, 1); + /* perms reftbl ... obj */ +#ifdef PLUTO_DEBUG + pi->level--; +#endif + return; + } else { + /* perms reftbl ... obj nil */ + lua_pop(pi->L, 1); + /* perms reftbl ... obj */ + } + /* perms reftbl ... obj */ + } + { + int type = lua_type(pi->L, -1); + pi->writer(pi->L, &type, sizeof(int), pi->ud); + +#ifdef PLUTO_DEBUG + printindent(pi->level); + printf("1 %d %d\n", pi->counter, type); + pi->level++; +#endif + } + + switch(lua_type(pi->L, -1)) { + case LUA_TBOOLEAN: + persistboolean(pi); + break; + case LUA_TLIGHTUSERDATA: + persistlightuserdata(pi); + break; + case LUA_TNUMBER: + persistnumber(pi); + break; + case LUA_TSTRING: + persiststring(pi); + break; + case LUA_TTABLE: + persisttable(pi); + break; + case LUA_TFUNCTION: + persistfunction(pi); + break; + case LUA_TTHREAD: + persistthread(pi); + break; + case LUA_TPROTO: + persistproto(pi); + break; + case LUA_TUPVAL: + persistupval(pi); + break; + case LUA_TUSERDATA: + persistuserdata(pi); + break; + default: + lua_assert(0); + } +#ifdef PLUTO_DEBUG + pi->level--; +#endif +} + +void pluto_persist(lua_State *L, lua_Chunkwriter writer, void *ud) +{ + PersistInfo pi; + + pi.counter = 0; + pi.L = L; + pi.writer = writer; + pi.ud = ud; +#ifdef PLUTO_DEBUG + pi.level = 0; +#endif + + lua_checkstack(L, 4); + /* perms? rootobj? ...? */ + lua_assert(lua_gettop(L) == 2); + /* perms rootobj */ + lua_assert(!lua_isnil(L, 2)); + /* perms rootobj */ + lua_newtable(L); + /* perms rootobj reftbl */ + + /* Now we're going to make the table weakly keyed. This prevents the + * GC from visiting it and trying to mark things it doesn't want to + * mark in tables, e.g. upvalues. All objects in the table are + * a priori reachable, so it doesn't matter that we do this. */ + lua_newtable(L); + /* perms rootobj reftbl mt */ + lua_pushstring(L, "__mode"); + /* perms rootobj reftbl mt "__mode" */ + lua_pushstring(L, "k"); + /* perms rootobj reftbl mt "__mode" "k" */ + lua_settable(L, 4); + /* perms rootobj reftbl mt */ + lua_setmetatable(L, 3); + /* perms rootobj reftbl */ + lua_insert(L, 2); + /* perms reftbl rootobj */ + persist(&pi); + /* perms reftbl rootobj */ + lua_remove(L, 2); + /* perms rootobj */ +} + +typedef struct WriterInfo_t { + char* buf; + size_t buflen; +} WriterInfo; + +static int bufwriter (lua_State *L, const void* p, size_t sz, void* ud) { + const char* cp = (const char*)p; + WriterInfo *wi = (WriterInfo *)ud; + + LIF(M,reallocvector)(L, wi->buf, wi->buflen, wi->buflen+sz, char); + while(sz) + { + /* how dearly I love ugly C pointer twiddling */ + wi->buf[wi->buflen++] = *cp++; + sz--; + } + return 0; +} + +int persist_l(lua_State *L) +{ + /* perms? rootobj? ...? */ + WriterInfo wi; + + wi.buf = NULL; + wi.buflen = 0; + + lua_settop(L, 2); + /* perms? rootobj? */ + luaL_checktype(L, 1, LUA_TTABLE); + /* perms rootobj? */ + luaL_checktype(L, 1, LUA_TTABLE); + /* perms rootobj */ + + pluto_persist(L, bufwriter, &wi); + + lua_settop(L, 0); + /* (empty) */ + lua_pushlstring(L, wi.buf, wi.buflen); + /* str */ + pdep_freearray(L, wi.buf, wi.buflen, char); + return 1; +} + +typedef struct UnpersistInfo_t { + lua_State *L; + ZIO zio; +#ifdef PLUTO_DEBUG + int level; +#endif +} UnpersistInfo; + +static void unpersist(UnpersistInfo *upi); + +/* The object is left on the stack. This is primarily used by unpersist, but + * may be used by GCed objects that may incur cycles in order to preregister + * the object. */ +static void registerobject(int ref, UnpersistInfo *upi) +{ + /* perms reftbl ... obj */ + lua_checkstack(upi->L, 2); + lua_pushlightuserdata(upi->L, (void*)ref); + /* perms reftbl ... obj ref */ + lua_pushvalue(upi->L, -2); + /* perms reftbl ... obj ref obj */ + lua_settable(upi->L, 2); + /* perms reftbl ... obj */ +} + +static void unpersistboolean(UnpersistInfo *upi) +{ + /* perms reftbl ... */ + int b; + lua_checkstack(upi->L, 1); + verify(LIF(Z,read)(&upi->zio, &b, sizeof(int)) == 0); + lua_pushboolean(upi->L, b); + /* perms reftbl ... bool */ +} + +static void unpersistlightuserdata(UnpersistInfo *upi) +{ + /* perms reftbl ... */ + void *p; + lua_checkstack(upi->L, 1); + verify(LIF(Z,read)(&upi->zio, &p, sizeof(void *)) == 0); + lua_pushlightuserdata(upi->L, p); + /* perms reftbl ... ludata */ +} + +static void unpersistnumber(UnpersistInfo *upi) +{ + /* perms reftbl ... */ + lua_Number n; + lua_checkstack(upi->L, 1); + verify(LIF(Z,read)(&upi->zio, &n, sizeof(lua_Number)) == 0); + lua_pushnumber(upi->L, n); + /* perms reftbl ... num */ +} + +static void unpersiststring(UnpersistInfo *upi) +{ + /* perms reftbl sptbl ref */ + int length; + char* string; + lua_checkstack(upi->L, 1); + verify(LIF(Z,read)(&upi->zio, &length, sizeof(int)) == 0); + string = pdep_newvector(upi->L, length, char); + verify(LIF(Z,read)(&upi->zio, string, length) == 0); + lua_pushlstring(upi->L, string, length); + /* perms reftbl sptbl ref str */ + pdep_freearray(upi->L, string, length, char); +} + +static void unpersistspecialtable(int ref, UnpersistInfo *upi) +{ + /* perms reftbl ... */ + lua_checkstack(upi->L, 1); + unpersist(upi); + /* perms reftbl ... spfunc? */ + lua_assert(lua_isfunction(upi->L, -1)); + /* perms reftbl ... spfunc */ + lua_call(upi->L, 0, 1); + /* perms reftbl ... tbl? */ + lua_assert(lua_istable(upi->L, -1)); + /* perms reftbl ... tbl */ +} + +static void unpersistliteraltable(int ref, UnpersistInfo *upi) +{ + /* perms reftbl ... */ + lua_checkstack(upi->L, 3); + /* Preregister table for handling of cycles */ + lua_newtable(upi->L); + /* perms reftbl ... tbl */ + registerobject(ref, upi); + /* perms reftbl ... tbl */ + /* Unpersist metatable */ + { + unpersist(upi); + /* perms reftbl ... tbl mt/nil? */ + if(lua_istable(upi->L, -1)) { + /* perms reftbl ... tbl mt */ + lua_setmetatable(upi->L, -2); + /* perms reftbl ... tbl */ + } else { + /* perms reftbl ... tbl nil? */ + lua_assert(lua_isnil(upi->L, -1)); + /* perms reftbl ... tbl nil */ + lua_pop(upi->L, 1); + /* perms reftbl ... tbl */ + } + /* perms reftbl ... tbl */ + } + + while(1) + { + /* perms reftbl ... tbl */ + unpersist(upi); + /* perms reftbl ... tbl key/nil */ + if(lua_isnil(upi->L, -1)) { + /* perms reftbl ... tbl nil */ + lua_pop(upi->L, 1); + /* perms reftbl ... tbl */ + break; + } + /* perms reftbl ... tbl key */ + unpersist(upi); + /* perms reftbl ... tbl key value? */ + lua_assert(!lua_isnil(upi->L, -1)); + /* perms reftbl ... tbl key value */ + lua_rawset(upi->L, -3); + /* perms reftbl ... tbl */ + } +} + +static void unpersisttable(int ref, UnpersistInfo *upi) +{ + /* perms reftbl ... */ + lua_checkstack(upi->L, 1); + { + int isspecial; + verify(LIF(Z,read)(&upi->zio, &isspecial, sizeof(int)) == 0); + if(isspecial) { + unpersistspecialtable(ref, upi); + /* perms reftbl ... tbl */ + } else { + unpersistliteraltable(ref, upi); + /* perms reftbl ... tbl */ + } + /* perms reftbl ... tbl */ + } +} + +static UpVal *makeupval(lua_State *L, int stackpos) +{ + UpVal *uv = pdep_new(L, UpVal); + pdep_link(L, (GCObject*)uv, LUA_TUPVAL); + uv->tt = LUA_TUPVAL; + uv->v = &uv->u.value; + uv->u.l.prev = NULL; + uv->u.l.next = NULL; + setobj(L, uv->v, getobject(L, stackpos)); + return uv; +} + +static Proto *makefakeproto(lua_State *L, lu_byte nups) +{ + Proto *p = pdep_newproto(L); + p->sizelineinfo = 1; + p->lineinfo = pdep_newvector(L, 1, int); + p->lineinfo[0] = 1; + p->sizecode = 1; + p->code = pdep_newvector(L, 1, Instruction); + p->code[0] = CREATE_ABC(OP_RETURN, 0, 1, 0); + p->source = pdep_newlstr(L, "", 0); + p->maxstacksize = 2; + p->nups = nups; + p->sizek = 0; + p->sizep = 0; + + return p; +} + +/* The GC is not fond of finding upvalues in tables. We get around this + * during persistence using a weakly keyed table, so that the GC doesn't + * bother to mark them. This won't work in unpersisting, however, since + * if we make the values weak they'll be collected (since nothing else + * references them). Our solution, during unpersisting, is to represent + * upvalues as dummy functions, each with one upvalue. */ +static void boxupval_start(lua_State *L) +{ + LClosure *lcl; + lcl = (LClosure*)pdep_newLclosure(L, 1, hvalue(&L->l_gt)); + pushclosure(L, (Closure*)lcl); + /* ... func */ + lcl->p = makefakeproto(L, 1); + + /* Temporarily initialize the upvalue to nil */ + + lua_pushnil(L); + lcl->upvals[0] = makeupval(L, -1); + lua_pop(L, 1); +} + +static void boxupval_finish(lua_State *L) +{ + /* ... func obj */ + LClosure *lcl = (LClosure *) clvalue(getobject(L, -2)); + + lcl->upvals[0]->u.value = *getobject(L, -1); + lua_pop(L, 1); +} + + +static void unboxupval(lua_State *L) +{ + /* ... func */ + LClosure *lcl; + UpVal *uv; + + lcl = (LClosure*)clvalue(getobject(L, -1)); + uv = lcl->upvals[0]; + lua_pop(L, 1); + /* ... */ + pushupval(L, uv); + /* ... upval */ +} + +static void unpersistfunction(int ref, UnpersistInfo *upi) +{ + /* perms reftbl ... */ + LClosure *lcl; + int i; + lu_byte nupvalues; + lua_checkstack(upi->L, 2); + + verify(LIF(Z,read)(&upi->zio, &nupvalues, sizeof(lu_byte)) == 0); + + lcl = (LClosure*)pdep_newLclosure(upi->L, nupvalues, hvalue(&upi->L->l_gt)); + pushclosure(upi->L, (Closure*)lcl); + + /* perms reftbl ... func */ + /* Put *some* proto in the closure, before the GC can find it */ + lcl->p = makefakeproto(upi->L, nupvalues); + + /* Also, we need to temporarily fill the upvalues */ + lua_pushnil(upi->L); + /* perms reftbl ... func nil */ + for(i=0; i<nupvalues; i++) { + lcl->upvals[i] = makeupval(upi->L, -1); + } + lua_pop(upi->L, 1); + /* perms reftbl ... func */ + + /* I can't see offhand how a function would ever get to be self- + * referential, but just in case let's register it early */ + registerobject(ref, upi); + + /* Now that it's safe, we can get the real proto */ + unpersist(upi); + /* perms reftbl ... func proto? */ + lua_assert(lua_type(upi->L, -1) == LUA_TPROTO); + /* perms reftbl ... func proto */ + lcl->p = toproto(upi->L, -1); + lua_pop(upi->L, 1); + /* perms reftbl ... func */ + + for(i=0; i<nupvalues; i++) { + /* perms reftbl ... func */ + unpersist(upi); + /* perms reftbl ... func func2 */ + unboxupval(upi->L); + /* perms reftbl ... func upval */ + lcl->upvals[i] = toupval(upi->L, -1); + lua_pop(upi->L, 1); + /* perms reftbl ... func */ + } + /* perms reftbl ... func */ + + /* Finally, the fenv */ + unpersist(upi); + /* perms reftbl ... func fenv/nil? */ + lua_assert(lua_type(upi->L, -1) == LUA_TNIL || + lua_type(upi->L, -1) == LUA_TTABLE); + /* perms reftbl ... func fenv/nil */ + if(!lua_isnil(upi->L, -1)) { + /* perms reftbl ... func fenv */ + lua_setfenv(upi->L, -2); + /* perms reftbl ... func */ + } else { + /* perms reftbl ... func nil */ + lua_pop(upi->L, 1); + /* perms reftbl ... func */ + } + /* perms reftbl ... func */ +} + +static void unpersistupval(int ref, UnpersistInfo *upi) +{ + /* perms reftbl ... */ + lua_checkstack(upi->L, 2); + + boxupval_start(upi->L); + /* perms reftbl ... func */ + registerobject(ref, upi); + + unpersist(upi); + /* perms reftbl ... func obj */ + boxupval_finish(upi->L); + /* perms reftbl ... func */ +} + +static void unpersistproto(int ref, UnpersistInfo *upi) +{ + /* perms reftbl ... */ + Proto *p; + int i; + int sizep, sizek; + + /* We have to be careful. The GC expects a lot out of protos. In + * particular, we need to give the function a valid string for its + * source, and valid code, even before we actually read in the real + * code. */ + TString *source = pdep_newlstr(upi->L, "", 0); + p = pdep_newproto(upi->L); + p->source = source; + p->sizecode=1; + p->code = pdep_newvector(upi->L, 1, Instruction); + p->code[0] = CREATE_ABC(OP_RETURN, 0, 1, 0); + p->maxstacksize = 2; + p->sizek = 0; + p->sizep = 0; + + lua_checkstack(upi->L, 2); + + pushproto(upi->L, p); + /* perms reftbl ... proto */ + /* We don't need to register early, since protos can never ever be + * involved in cyclic references */ + + /* Read in constant references */ + { + verify(LIF(Z,read)(&upi->zio, &sizek, sizeof(int)) == 0); + LIF(M,reallocvector)(upi->L, p->k, 0, sizek, TValue); + for(i=0; i<sizek; i++) { + /* perms reftbl ... proto */ + unpersist(upi); + /* perms reftbl ... proto k */ + setobj2s(upi->L, &p->k[i], getobject(upi->L, -1)); + p->sizek++; + lua_pop(upi->L, 1); + /* perms reftbl ... proto */ + } + /* perms reftbl ... proto */ + } + /* Read in sub-proto references */ + { + verify(LIF(Z,read)(&upi->zio, &sizep, sizeof(int)) == 0); + LIF(M,reallocvector)(upi->L, p->p, 0, sizep, Proto*); + for(i=0; i<sizep; i++) { + /* perms reftbl ... proto */ + unpersist(upi); + /* perms reftbl ... proto subproto */ + p->p[i] = toproto(upi->L, -1); + p->sizep++; + lua_pop(upi->L, 1); + /* perms reftbl ... proto */ + } + /* perms reftbl ... proto */ + } + + /* Read in code */ + { + verify(LIF(Z,read)(&upi->zio, &p->sizecode, sizeof(int)) == 0); + LIF(M,reallocvector)(upi->L, p->code, 1, p->sizecode, Instruction); + verify(LIF(Z,read)(&upi->zio, p->code, + sizeof(Instruction) * p->sizecode) == 0); + } + + /* Read in upvalue names */ + { + verify(LIF(Z,read)(&upi->zio, &p->sizeupvalues, sizeof(int)) == 0); + if (p->sizeupvalues) + { + LIF(M,reallocvector)(upi->L, p->upvalues, 0, p->sizeupvalues, TString *); + for(i=0; i<p->sizeupvalues; i++) + { + unpersist(upi); + p->upvalues[i] = pdep_newlstr(upi->L, lua_tostring(upi->L, -1), strlen(lua_tostring(upi->L, -1))); + lua_pop(upi->L, 1); + } + } + } + + /* Read in local variable infos */ + { + verify(LIF(Z,read)(&upi->zio, &p->sizelocvars, sizeof(int)) == 0); + if (p->sizelocvars) + { + LIF(M,reallocvector)(upi->L, p->locvars, 0, p->sizelocvars, LocVar); + for(i=0; i<p->sizelocvars; i++) + { + unpersist(upi); + p->locvars[i].varname = pdep_newlstr(upi->L, lua_tostring(upi->L, -1), strlen(lua_tostring(upi->L, -1))); + lua_pop(upi->L, 1); + + verify(LIF(Z,read)(&upi->zio, &p->locvars[i].startpc, sizeof(int)) == 0); + verify(LIF(Z,read)(&upi->zio, &p->locvars[i].endpc, sizeof(int)) == 0); + } + } + } + + /* Read in source string*/ + unpersist(upi); + p->source = pdep_newlstr(upi->L, lua_tostring(upi->L, -1), strlen(lua_tostring(upi->L, -1))); + lua_pop(upi->L, 1); + + /* Read in line numbers */ + { + verify(LIF(Z,read)(&upi->zio, &p->sizelineinfo, sizeof(int)) == 0); + if (p->sizelineinfo) + { + LIF(M,reallocvector)(upi->L, p->lineinfo, 0, p->sizelineinfo, int); + verify(LIF(Z,read)(&upi->zio, p->lineinfo, + sizeof(int) * p->sizelineinfo) == 0); + } + } + + /* Read in linedefined and lastlinedefined */ + verify(LIF(Z,read)(&upi->zio, &p->linedefined, sizeof(int)) == 0); + verify(LIF(Z,read)(&upi->zio, &p->lastlinedefined, sizeof(int)) == 0); + + /* Read in misc values */ + { + verify(LIF(Z,read)(&upi->zio, &p->nups, sizeof(lu_byte)) == 0); + verify(LIF(Z,read)(&upi->zio, &p->numparams, sizeof(lu_byte)) == 0); + verify(LIF(Z,read)(&upi->zio, &p->is_vararg, sizeof(lu_byte)) == 0); + verify(LIF(Z,read)(&upi->zio, &p->maxstacksize, sizeof(lu_byte)) == 0); + } +} + + +/* Does basically the opposite of luaC_link(). + * Right now this function is rather inefficient; it requires traversing the + * entire root GC set in order to find one object. If the GC list were doubly + * linked this would be much easier, but there's no reason for Lua to have + * that. */ +static void gcunlink(lua_State *L, GCObject *gco) +{ + GCObject *prevslot; + if(G(L)->rootgc == gco) { + G(L)->rootgc = G(L)->rootgc->gch.next; + return; + } + + prevslot = G(L)->rootgc; + while(prevslot->gch.next != gco) { + lua_assert(prevslot->gch.next != NULL); + prevslot = prevslot->gch.next; + } + + prevslot->gch.next = prevslot->gch.next->gch.next; +} + +/* FIXME __ALL__ field ordering */ +static void unpersistthread(int ref, UnpersistInfo *upi) +{ + /* perms reftbl ... */ + lua_State *L2; + size_t stacklimit = 0; + L2 = lua_newthread(upi->L); + lua_checkstack(upi->L, 3); + /* L1: perms reftbl ... thr */ + /* L2: (empty) */ + registerobject(ref, upi); + + /* First, deserialize the object stack. */ + { + size_t i, stacksize; + verify(LIF(Z,read)(&upi->zio, &stacksize, sizeof(size_t)) == 0); + LIF(D,growstack)(L2, (int)stacksize); + /* Make sure that the first stack element (a nil, representing + * the imaginary top-level C function) is written to the very, + * very bottom of the stack */ + L2->top--; + for(i=0; i<stacksize; i++) { + unpersist(upi); + /* L1: perms reftbl ... thr obj* */ + } + lua_xmove(upi->L, L2, stacksize); + /* L1: perms reftbl ... thr */ + /* L2: obj* */ + } + /* (hereafter, stacks refer to L1) */ + + /* Now, deserialize the CallInfo stack. */ + { + size_t i, numframes; + verify(LIF(Z,read)(&upi->zio, &numframes, sizeof(size_t)) == 0); + LIF(D,reallocCI)(L2,numframes*2); + for(i=0; i<numframes; i++) { + CallInfo *ci = L2->base_ci + i; + size_t stackbase, stackfunc, stacktop, savedpc; + verify(LIF(Z,read)(&upi->zio, &stackbase, sizeof(size_t)) == 0); + verify(LIF(Z,read)(&upi->zio, &stackfunc, sizeof(size_t)) == 0); + verify(LIF(Z,read)(&upi->zio, &stacktop, sizeof(size_t)) == 0); + verify(LIF(Z,read)(&upi->zio, &ci->nresults, sizeof(int)) == 0); + verify(LIF(Z,read)(&upi->zio, &savedpc, sizeof(size_t)) == 0); + + if(stacklimit < stacktop) + stacklimit = stacktop; + + ci->base = L2->stack+stackbase; + ci->func = L2->stack+stackfunc; + ci->top = L2->stack+stacktop; + ci->savedpc = (ci != L2->base_ci) ? + ci_func(ci)->l.p->code+savedpc : + 0; + ci->tailcalls = 0; + /* Update the pointer each time, to keep the GC + * happy*/ + L2->ci = ci; + } + } + /* perms reftbl ... thr */ + /* Deserialize the state's other parameters, with the exception of upval stuff */ + { + size_t stackbase, stacktop; + L2->savedpc = L2->ci->savedpc; + verify(LIF(Z,read)(&upi->zio, &L2->status, sizeof(lu_byte)) == 0); + verify(LIF(Z,read)(&upi->zio, &stackbase, sizeof(size_t)) == 0); + verify(LIF(Z,read)(&upi->zio, &stacktop, sizeof(size_t)) == 0); + verify(LIF(Z,read)(&upi->zio, &L2->errfunc, sizeof(ptrdiff_t)) == 0); + L2->base = L2->stack + stackbase; + L2->top = L2->stack + stacktop; + } + /* Finally, "reopen" upvalues (see persistupval() for why) */ + { + UpVal* uv; + GCObject **nextslot = &L2->openupval; + global_State *g = G(L2); + while(1) { + size_t stackpos; + unpersist(upi); + /* perms reftbl ... thr uv/nil */ + if(lua_isnil(upi->L, -1)) { + /* perms reftbl ... thr nil */ + lua_pop(upi->L, 1); + /* perms reftbl ... thr */ + break; + } + /* perms reftbl ... thr boxeduv */ + unboxupval(upi->L); + /* perms reftbl ... thr uv */ + uv = toupval(upi->L, -1); + lua_pop(upi->L, 1); + /* perms reftbl ... thr */ + + verify(LIF(Z,read)(&upi->zio, &stackpos, sizeof(size_t)) == 0); + uv->v = L2->stack + stackpos; + gcunlink(upi->L, (GCObject*)uv); + uv->marked = luaC_white(g); + *nextslot = (GCObject*)uv; + nextslot = &uv->next; + uv->u.l.prev = &G(L2)->uvhead; + uv->u.l.next = G(L2)->uvhead.u.l.next; + uv->u.l.next->u.l.prev = uv; + G(L2)->uvhead.u.l.next = uv; + lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); + } + *nextslot = NULL; + } + + /* The stack must be valid at least to the highest value among the CallInfos */ + /* 'top' and the values up to there must be filled with 'nil' */ + { + StkId o; + LIF(D,checkstack)(L2, (int)stacklimit); + for (o = L2->top; o <= L2->top + stacklimit; o++) + setnilvalue(o); + } +} + +static void unpersistuserdata(int ref, UnpersistInfo *upi) +{ + /* perms reftbl ... */ + int isspecial; + lua_checkstack(upi->L, 2); + verify(LIF(Z,read)(&upi->zio, &isspecial, sizeof(int)) == 0); + if(isspecial) { + unpersist(upi); + /* perms reftbl ... spfunc? */ + lua_assert(lua_isfunction(upi->L, -1)); + /* perms reftbl ... spfunc */ +#ifdef PLUTO_PASS_USERDATA_TO_PERSIST + lua_pushlightuserdata(upi->L, &upi->zio); + lua_call(upi->L, 1, 1); +#else + lua_call(upi->L, 0, 1); +#endif + /* perms reftbl ... udata? */ +/* This assertion might not be necessary; it's conceivable, for + * example, that the SP function might decide to return a table + * with equivalent functionality. For the time being, we'll + * ignore this possibility in favor of stricter and more testable + * requirements. */ + lua_assert(lua_isuserdata(upi->L, -1)); + /* perms reftbl ... udata */ + } else { + size_t length; + verify(LIF(Z,read)(&upi->zio, &length, sizeof(size_t)) == 0); + + lua_newuserdata(upi->L, length); + /* perms reftbl ... udata */ + registerobject(ref, upi); + verify(LIF(Z,read)(&upi->zio, lua_touserdata(upi->L, -1), length) == 0); + + unpersist(upi); + /* perms reftbl ... udata mt/nil? */ + lua_assert(lua_istable(upi->L, -1) || lua_isnil(upi->L, -1)); + /* perms reftbl ... udata mt/nil */ + lua_setmetatable(upi->L, -2); + /* perms reftbl ... udata */ + } + /* perms reftbl ... udata */ +} + +static void unpersistpermanent(int ref, UnpersistInfo *upi) +{ + /* perms reftbl ... */ + lua_checkstack(upi->L, 2); + unpersist(upi); + /* perms reftbl permkey */ + lua_gettable(upi->L, 1); + /* perms reftbl perm? */ + /* We assume currently that the substituted permanent value + * shouldn't be nil. This may be a bad assumption. Real-life + * experience is needed to evaluate this. */ + lua_assert(!lua_isnil(upi->L, -1)); + /* perms reftbl perm */ +} + +/* For debugging only; not called when lua_assert is empty */ +static int inreftable(lua_State *L, int ref) +{ + int res; + lua_checkstack(L, 1); + /* perms reftbl ... */ + lua_pushlightuserdata(L, (void*)ref); + /* perms reftbl ... ref */ + lua_gettable(L, 2); + /* perms reftbl ... obj? */ + res = !lua_isnil(L, -1); + lua_pop(L, 1); + /* perms reftbl ... */ + return res; +} + +static void unpersist(UnpersistInfo *upi) +{ + /* perms reftbl ... */ + int firstTime; + int stacksize = lua_gettop(upi->L); stacksize = stacksize; /* DEBUG */ + lua_checkstack(upi->L, 2); + LIF(Z,read)(&upi->zio, &firstTime, sizeof(int)); + if(firstTime) { + int ref; + int type; + LIF(Z,read)(&upi->zio, &ref, sizeof(int)); + lua_assert(!inreftable(upi->L, ref)); + LIF(Z,read)(&upi->zio, &type, sizeof(int)); +#ifdef PLUTO_DEBUG + printindent(upi->level); + printf("1 %d %d\n", ref, type); + upi->level++; +#endif + switch(type) { + case LUA_TBOOLEAN: + unpersistboolean(upi); + break; + case LUA_TLIGHTUSERDATA: + unpersistlightuserdata(upi); + break; + case LUA_TNUMBER: + unpersistnumber(upi); + break; + case LUA_TSTRING: + unpersiststring(upi); + break; + case LUA_TTABLE: + unpersisttable(ref, upi); + break; + case LUA_TFUNCTION: + unpersistfunction(ref, upi); + break; + case LUA_TTHREAD: + unpersistthread(ref, upi); + break; + case LUA_TPROTO: + unpersistproto(ref, upi); + break; + case LUA_TUPVAL: + unpersistupval(ref, upi); + break; + case LUA_TUSERDATA: + unpersistuserdata(ref, upi); + break; + case PLUTO_TPERMANENT: + unpersistpermanent(ref, upi); + break; + default: + lua_assert(0); + } + /* perms reftbl ... obj */ + lua_assert(lua_type(upi->L, -1) == type || + type == PLUTO_TPERMANENT || + /* Remember, upvalues get a special dispensation, as + * described in boxupval */ + (lua_type(upi->L, -1) == LUA_TFUNCTION && + type == LUA_TUPVAL)); + registerobject(ref, upi); + /* perms reftbl ... obj */ +#ifdef PLUTO_DEBUG + upi->level--; +#endif + } else { + int ref; + LIF(Z,read)(&upi->zio, &ref, sizeof(int)); +#ifdef PLUTO_DEBUG + printindent(upi->level); + printf("0 %d\n", ref); +#endif + if(ref == 0) { + lua_pushnil(upi->L); + /* perms reftbl ... nil */ + } else { + lua_pushlightuserdata(upi->L, (void*)ref); + /* perms reftbl ... ref */ + lua_gettable(upi->L, 2); + /* perms reftbl ... obj? */ + lua_assert(!lua_isnil(upi->L, -1)); + } + /* perms reftbl ... obj/nil */ + } + /* perms reftbl ... obj/nil */ + lua_assert(lua_gettop(upi->L) == stacksize + 1); +} + +void pluto_unpersist(lua_State *L, lua_Chunkreader reader, void *ud) +{ + /* We use the graciously provided ZIO (what the heck does the Z stand + * for?) library so that we don't have to deal with the reader directly. + * Letting the reader function decide how much data to return can be + * very unpleasant. + */ + UnpersistInfo upi; + upi.L = L; +#ifdef PLUTO_DEBUG + upi.level = 0; +#endif + + lua_checkstack(L, 3); + LIF(Z,init)(L, &upi.zio, reader, ud); + + /* perms */ + lua_newtable(L); + /* perms reftbl */ + lua_gc(L, LUA_GCSTOP, 0); + unpersist(&upi); + lua_gc(L, LUA_GCRESTART, 0); + /* perms reftbl rootobj */ + lua_replace(L, 2); + /* perms rootobj */ +} + +typedef struct LoadInfo_t { + char *buf; + size_t size; +} LoadInfo; + + +static const char *bufreader(lua_State *L, void *ud, size_t *sz) { + LoadInfo *li = (LoadInfo *)ud; + if(li->size == 0) { + return NULL; + } + *sz = li->size; + li->size = 0; + return li->buf; +} + +int unpersist_l(lua_State *L) +{ + LoadInfo li; + char const *origbuf; + char *tempbuf; + size_t bufsize; + /* perms? str? ...? */ + lua_settop(L, 2); + /* perms? str? */ + origbuf = luaL_checklstring(L, 2, &bufsize); + tempbuf = LIF(M,newvector)(L, bufsize, char); + memcpy(tempbuf, origbuf, bufsize); + + li.buf = tempbuf; + li.size = bufsize; + + /* perms? str */ + lua_pop(L, 1); + /* perms? */ + luaL_checktype(L, 1, LUA_TTABLE); + /* perms */ + pluto_unpersist(L, bufreader, &li); + /* perms rootobj */ + LIF(M,freearray)(L, tempbuf, bufsize, char); + return 1; +} + +static luaL_reg pluto_reg[] = { + { "persist", persist_l }, + { "unpersist", unpersist_l }, + { NULL, NULL } +}; + +LUALIB_API int luaopen_pluto(lua_State *L) { + luaL_openlib(L, "pluto", pluto_reg, 0); + return 1; +} diff --git a/engines/sword25/util/pluto/pluto.h b/engines/sword25/util/pluto/pluto.h new file mode 100644 index 0000000000..3674842d44 --- /dev/null +++ b/engines/sword25/util/pluto/pluto.h @@ -0,0 +1,25 @@ +/* $Id$ */ + +/* Pluto - Heavy-duty persistence for Lua + * Copyright (C) 2004 by Ben Sunshine-Hill, and released into the public + * domain. People making use of this software as part of an application + * are politely requested to email the author at sneftel@gmail.com + * with a brief description of the application, primarily to satisfy his + * curiosity. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* lua.h must be included before this file */ + +void pluto_persist(lua_State *L, lua_Chunkwriter writer, void *ud); + +void pluto_unpersist(lua_State *L, lua_Chunkreader reader, void *ud); + +LUALIB_API int luaopen_pluto(lua_State *L); diff --git a/engines/sword25/util/pluto/plzio.c b/engines/sword25/util/pluto/plzio.c new file mode 100644 index 0000000000..7c5ab3b773 --- /dev/null +++ b/engines/sword25/util/pluto/plzio.c @@ -0,0 +1,76 @@ +/* +** $Id: lzio.c,v 1.31.1.1 2007/12/27 13:02:25 roberto Exp $ +** a generic input stream interface +** See Copyright Notice in lua.h +*/ + + +#include <string.h> + +#define lzio_c +#define LUA_CORE + +#include "pdep/pdep.h" + +int pdep_fill (ZIO *z) { + size_t size; + lua_State *L = z->L; + const char *buff; + lua_unlock(L); + buff = z->reader(L, z->data, &size); + lua_lock(L); + if (buff == NULL || size == 0) return EOZ; + z->n = size - 1; + z->p = buff; + return char2int(*(z->p++)); +} + + +int pdep_lookahead (ZIO *z) { + if (z->n == 0) { + if (pdep_fill(z) == EOZ) + return EOZ; + else { + z->n++; /* pdep_fill removed first byte; put back it */ + z->p--; + } + } + return char2int(*z->p); +} + + +void pdep_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) { + z->L = L; + z->reader = reader; + z->data = data; + z->n = 0; + z->p = NULL; +} + + +/* --------------------------------------------------------------- read --- */ +size_t pdep_read (ZIO *z, void *b, size_t n) { + while (n) { + size_t m; + if (pdep_lookahead(z) == EOZ) + return n; /* return number of missing bytes */ + m = (n <= z->n) ? n : z->n; /* min. between n and z->n */ + memcpy(b, z->p, m); + z->n -= m; + z->p += m; + b = (char *)b + m; + n -= m; + } + return 0; +} + +/* ------------------------------------------------------------------------ */ +char *pdep_openspace (lua_State *L, Mbuffer *buff, size_t n) { + if (n > buff->buffsize) { + if (n < LUA_MINBUFFER) n = LUA_MINBUFFER; + pdep_resizebuffer(L, buff, n); + } + return buff->buffer; +} + + diff --git a/engines/sword25/util/pluto/pptest.c b/engines/sword25/util/pluto/pptest.c new file mode 100644 index 0000000000..1bfecf2b75 --- /dev/null +++ b/engines/sword25/util/pluto/pptest.c @@ -0,0 +1,95 @@ +/* $Id$ */ + +#include <stdio.h> +#include <stdlib.h> + +#include "lua.h" +#include "lualib.h" +#include "lauxlib.h" + +static int LUAF_createludata(lua_State *L) +{ + lua_pushlightuserdata(L, (void*)321); + return 1; +} + +/* A userdata that may be literally persisted */ +static int LUAF_boxinteger(lua_State *L) +{ + /* num */ + int* ptr = lua_newuserdata(L, sizeof(int)); + /* num udata */ + *ptr = luaL_checkint(L, 1); + lua_newtable(L); + /* num udata mt */ + lua_pushstring(L, "__persist"); + /* num udata mt "__persist" */ + lua_pushboolean(L, 1); + /* num udata mt "__persist" true */ + lua_rawset(L, 3); + /* num udata mt */ + lua_setmetatable(L, 2); + /* num udata */ + return 1; +} + +static int LUAF_boxboolean(lua_State *L) +{ + /* bool */ + char* ptr = lua_newuserdata(L, sizeof(char)); + /* bool udata */ + *ptr = lua_toboolean(L, 1); + lua_newtable(L); + /* num udata mt */ + lua_pushstring(L, "__persist"); + /* num udata mt "__persist" */ + lua_getglobal(L, "booleanpersist"); + /* num udata mt "__persist" booleanpersist */ + lua_rawset(L, 3); + /* num udata mt */ + lua_setmetatable(L, 2); + /* num udata */ + return 1; +} + +static int LUAF_unboxboolean(lua_State *L) +{ + /* udata */ + lua_pushboolean(L, *(char*)lua_touserdata(L, 1)); + /* udata bool */ + return 1; +} + +static int LUAF_onerror(lua_State *L) +{ + + const char* str = 0; + if(lua_gettop(L) != 0) + { + str = lua_tostring(L, -1); + printf("%s\n",str); + } + return 0; +} + +int main() +{ + lua_State* L = lua_open(); + + luaL_openlibs(L); + lua_settop(L, 0); + + lua_register(L, "createludata", LUAF_createludata); + lua_register(L, "boxinteger", LUAF_boxinteger); + lua_register(L, "boxboolean", LUAF_boxboolean); + lua_register(L, "unboxboolean", LUAF_unboxboolean); + lua_register(L, "onerror", LUAF_onerror); + + lua_pushcfunction(L, LUAF_onerror); + luaL_loadfile(L, "pptest.lua"); + lua_pcall(L,0,0,1); + + lua_close(L); + + return 0; +} diff --git a/engines/sword25/util/pluto/pptest.lua b/engines/sword25/util/pluto/pptest.lua new file mode 100644 index 0000000000..144da3ee80 --- /dev/null +++ b/engines/sword25/util/pluto/pptest.lua @@ -0,0 +1,168 @@ +-- $Id$ + +require "pluto" + +permtable = { 1234 } + +perms = { [coroutine.yield] = 1, [permtable] = 2 } + +twithmt = {} +setmetatable( twithmt, { __call = function() return 21 end } ) + +function testfenv() + return abc +end + +setfenv(testfenv, { abc = 456 }) + +function fa(i) + local ia = i + 1 + return fb(ia) +end + +function fb(i) + local ib = i + 1 + ib = ib + fc(ib) + return ib +end + +function fc(i) + local ic = i + 1 + coroutine.yield() + return ic*2 +end + +function func() + return 4 +end + +thr = coroutine.create(fa) +coroutine.resume(thr, 2) + +testtbl = { a = 2, [2] = 4 } + +function funcreturningclosure(n) + return function() + return n + end +end + +function nestedfunc(n) + return (function(m) return m+2 end)(n+3) +end + +testloopa = {} +testloopb = { testloopa = testloopa } +testloopa.testloopb = testloopb + +sharedref = {} +refa = {sharedref = sharedref} +refb = {sharedref = sharedref} + +sptable = { a = 3 } + +setmetatable(sptable, { + __persist = function(tbl) + local a = tbl.a + return function() + return { a = a+3 } + end + end +}) + +literaludata = boxinteger(71) + +function booleanpersist(udata) + local b = unboxboolean(udata) + return function() + return boxboolean(b) + end +end + +function makecounter() + local a = 0 + return { + inc = function() a = a + 1 end, + cur = function() return a end + } +end + +function uvinthreadfunc() + local a = 1 + local b = function() + a = a+1 + coroutine.yield() + a = a+1 + end + a = a+1 + b() + a = a+1 + return a +end + +uvinthread = coroutine.create(uvinthreadfunc) +coroutine.resume(uvinthread) + +niinmt = { a = 3 } +setmetatable(niinmt, {__newindex = function(key, val) end }) + + + + +local function GenerateObjects() + local Table = {} + + function Table:Func() + return { Table, self } + end + + function uvcycle() + return Table:Func() + end +end + +GenerateObjects() + + + +function debuginfo(foo) + foo = foo + foo + return debug.getlocal(1,1) +end + +rootobj = { + testfalse = false, + testtrue = true, + testseven = 7, + testfoobar = "foobar", + testfuncreturnsfour = func, + testnil = nil, + testthread = thr, + testperm = permtable, + testmt = twithmt, + testtbl = testtbl, + testfenv = testfenv, + testclosure = funcreturningclosure(11), + testnilclosure = funcreturningclosure(nil), + testnest = nestedfunc, + testludata = createludata(), + testlooptable = testloopa, + testsharedrefa = refa, + testsharedrefb = refb, + testsptable = sptable, + testliteraludata = literaludata, + testspudata1 = boxboolean(true), + testspudata2 = boxboolean(false), + testsharedupval = makecounter(), + testuvinthread = uvinthread, + testniinmt = niinmt, + testuvcycle = uvcycle, + testdebuginfo = debuginfo +} + +buf = pluto.persist(perms, rootobj) + +onerror() +outfile = io.open("test.plh", "wb") +outfile:write(buf) +outfile:close() diff --git a/engines/sword25/util/pluto/puptest.c b/engines/sword25/util/pluto/puptest.c new file mode 100644 index 0000000000..e9aa7ea305 --- /dev/null +++ b/engines/sword25/util/pluto/puptest.c @@ -0,0 +1,81 @@ +/* $Id$ */ + +#include <stdio.h> +#include <stdlib.h> + +#include "lua.h" +#include "lualib.h" +#include "lauxlib.h" + +static int LUAF_checkludata(lua_State *L) +{ + lua_pushboolean(L, lua_touserdata(L, -1) == (void*)321); + return 1; +} + +static int LUAF_unboxinteger(lua_State *L) +{ + lua_pushnumber(L, *((int*)lua_touserdata(L, -1))); + return 1; +} + +static int LUAF_unboxboolean(lua_State *L) +{ + /* udata */ + lua_pushboolean(L, *(char*)lua_touserdata(L, 1)); + /* udata bool */ + return 1; +} + +static int LUAF_boxboolean(lua_State *L) +{ + /* bool */ + char* ptr = lua_newuserdata(L, sizeof(char)); + /* bool udata */ + *ptr = lua_toboolean(L, 1); + lua_newtable(L); + /* num udata mt */ + lua_pushstring(L, "__persist"); + /* num udata mt "__persist" */ + lua_getglobal(L, "booleanpersist"); + /* num udata mt "__persist" booleanpersist */ + lua_rawset(L, 3); + /* num udata mt */ + lua_setmetatable(L, 2); + /* num udata */ + return 1; +} + +static int LUAF_onerror(lua_State *L) +{ + + const char* str = 0; + if(lua_gettop(L) != 0) + { + str = lua_tostring(L, -1); + printf("%s\n",str); + } + return 0; +} + +int main() +{ + lua_State* L = lua_open(); + + luaL_openlibs(L); + lua_settop(L, 0); + + lua_register(L, "checkludata", LUAF_checkludata); + lua_register(L, "unboxinteger", LUAF_unboxinteger); + lua_register(L, "boxboolean", LUAF_boxboolean); + lua_register(L, "unboxboolean", LUAF_unboxboolean); + lua_register(L, "onerror", LUAF_onerror); + + lua_pushcfunction(L, LUAF_onerror); + luaL_loadfile(L, "puptest.lua"); + lua_pcall(L,0,0,1); + + lua_close(L); + + return 0; +} diff --git a/engines/sword25/util/pluto/puptest.lua b/engines/sword25/util/pluto/puptest.lua new file mode 100644 index 0000000000..e5ccdd64bd --- /dev/null +++ b/engines/sword25/util/pluto/puptest.lua @@ -0,0 +1,93 @@ +-- $Id$ + +require "pluto" + +permtable = { 1234 } + +perms = { [1] = coroutine.yield, [2] = permtable } + +function testcounter(counter) + local a = counter.cur() + counter.inc() + return counter.cur() == a+1 +end + +function testuvinthread(func) + local success, result = coroutine.resume(func) + return success and result == 5 +end + + +function test(rootobj) + local passed = 0 + local total = 0 + local dotest = function(name,cond) + total = total+1 + if cond then + print(name, " PASSED") + passed = passed + 1 + else + print(name, "* FAILED") + end + end + + + dotest("Boolean FALSE ", rootobj.testfalse == false) + dotest("Boolean TRUE ", rootobj.testtrue == true) + dotest("Number 7 ", rootobj.testseven == 7) + dotest("String 'foobar' ", rootobj.testfoobar == "foobar") + dotest("Func returning 4 ", rootobj.testfuncreturnsfour() == 4) + dotest("Nil value ", rootobj.testnil == nil) + dotest("Thread resume ", coroutine.resume(rootobj.testthread) == true,14) + dotest("Table ", rootobj.testtbl.a == 2 and rootobj.testtbl[2] == 4); + dotest("Permanent table ", rootobj.testperm == permtable) + dotest("Table metatable ", rootobj.testmt() == 21) + dotest("Function env ", rootobj.testfenv() == 456) + dotest("Lua closure ", rootobj.testclosure() == 11) + dotest("Nil in closure ", rootobj.testnilclosure() == nil) + dotest("Nested func ", rootobj.testnest(1) == 6) + dotest("Light userdata ", checkludata(rootobj.testludata)) + dotest("Looped tables ", + rootobj.testlooptable.testloopb.testloopa == + rootobj.testlooptable) + dotest("Shared reference ", rootobj.testsharedrefa.sharedref == + rootobj.testsharedrefb.sharedref) + dotest("Identical tables ", rootobj.testsharedrefa ~= + rootobj.testsharedrefb) + dotest("Table special persist", rootobj.testsptable.a == 6) + dotest("Udata literal persist", + unboxinteger(rootobj.testliteraludata) == 71) + dotest("Udata special persist", + unboxboolean(rootobj.testspudata1) == true and + unboxboolean(rootobj.testspudata2) == false) + dotest("Shared upvalues ", + testcounter(rootobj.testsharedupval)) + dotest("Open upvalues ", + testuvinthread(rootobj.testuvinthread)) + dotest("Upvalue cycles ", + rootobj.testuvcycle()[1] == rootobj.testuvcycle()[2]) + dotest("__newindex metamethod", rootobj.testniinmt.a == 3) + dotest("Debug info ", (rootobj.testdebuginfo(2)) == "foo") + print() + if passed == total then + print("All tests passed.") + else + print(passed .. "/" .. total .. " tests passed.") + end +end + +infile, err = io.open("test.plh", "rb") +if infile == nil then + error("While opening: " .. (err or "no error")) +end + +buf, err = infile:read("*a") +if buf == nil then + error("While reading: " .. (err or "no error")) +end + +infile:close() + +rootobj = pluto.unpersist(perms, buf) + +test(rootobj) |