aboutsummaryrefslogtreecommitdiff
path: root/engines/sword25/util/pluto
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sword25/util/pluto')
-rwxr-xr-xengines/sword25/util/pluto/CHANGELOG38
-rwxr-xr-xengines/sword25/util/pluto/FILEFORMAT168
-rwxr-xr-xengines/sword25/util/pluto/Makefile29
-rwxr-xr-xengines/sword25/util/pluto/README133
-rwxr-xr-xengines/sword25/util/pluto/THANKS10
-rwxr-xr-xengines/sword25/util/pluto/pdep.c112
-rwxr-xr-xengines/sword25/util/pluto/pdep/README5
-rwxr-xr-xengines/sword25/util/pluto/pdep/lauxlib.h174
-rwxr-xr-xengines/sword25/util/pluto/pdep/ldo.h57
-rwxr-xr-xengines/sword25/util/pluto/pdep/lfunc.h34
-rwxr-xr-xengines/sword25/util/pluto/pdep/lgc.h110
-rwxr-xr-xengines/sword25/util/pluto/pdep/llimits.h128
-rwxr-xr-xengines/sword25/util/pluto/pdep/lobject.h381
-rwxr-xr-xengines/sword25/util/pluto/pdep/lopcodes.h268
-rwxr-xr-xengines/sword25/util/pluto/pdep/lstate.h169
-rwxr-xr-xengines/sword25/util/pluto/pdep/lstring.h31
-rwxr-xr-xengines/sword25/util/pluto/pdep/ltm.h54
-rwxr-xr-xengines/sword25/util/pluto/pdep/lua.h388
-rwxr-xr-xengines/sword25/util/pluto/pdep/lzio.h65
-rwxr-xr-xengines/sword25/util/pluto/pdep/pdep.h41
-rwxr-xr-xengines/sword25/util/pluto/pluto.c1658
-rwxr-xr-xengines/sword25/util/pluto/pluto.h25
-rwxr-xr-xengines/sword25/util/pluto/plzio.c76
-rwxr-xr-xengines/sword25/util/pluto/pptest.c95
-rwxr-xr-xengines/sword25/util/pluto/pptest.lua168
-rwxr-xr-xengines/sword25/util/pluto/puptest.c81
-rwxr-xr-xengines/sword25/util/pluto/puptest.lua93
27 files changed, 4591 insertions, 0 deletions
diff --git a/engines/sword25/util/pluto/CHANGELOG b/engines/sword25/util/pluto/CHANGELOG
new file mode 100755
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 100755
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 100755
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 100755
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 100755
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 100755
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 100755
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 100755
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 100755
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 100755
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 100755
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 100755
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 100755
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 100755
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 100755
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 100755
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 100755
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 100755
index 0000000000..5bc97b746f
--- /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 "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 100755
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 100755
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 100755
index 0000000000..8abf3293b2
--- /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 "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 100755
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 100755
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 100755
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 100755
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 100755
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 100755
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)