summaryrefslogtreecommitdiff
path: root/library/LuaWrapper.cpp
diff options
context:
space:
mode:
authorAlexander Gavrilov2012-03-23 11:30:54 +0400
committerAlexander Gavrilov2012-03-23 11:30:54 +0400
commit78437310d0e032880d19ee97eac67af60b369258 (patch)
tree300cd9d03f0c71593def75c94e1611b701587283 /library/LuaWrapper.cpp
parentccc8fac166ad04e67b581da44918a504865811a7 (diff)
downloaddfhack-78437310d0e032880d19ee97eac67af60b369258.tar.gz
dfhack-78437310d0e032880d19ee97eac67af60b369258.tar.bz2
dfhack-78437310d0e032880d19ee97eac67af60b369258.tar.xz
Add a sizeof method/function to retrieve object/type size and address.
Diffstat (limited to 'library/LuaWrapper.cpp')
-rw-r--r--library/LuaWrapper.cpp121
1 files changed, 110 insertions, 11 deletions
diff --git a/library/LuaWrapper.cpp b/library/LuaWrapper.cpp
index 21938627..a394b4cf 100644
--- a/library/LuaWrapper.cpp
+++ b/library/LuaWrapper.cpp
@@ -67,6 +67,7 @@ inline void lua_swap(lua_State *state) { lua_insert(state, -2); }
#define DFHACK_CHANGEERROR_NAME "DFHack::ChangeError"
#define DFHACK_COMPARE_NAME "DFHack::ComparePtrs"
#define DFHACK_TYPE_TOSTRING_NAME "DFHack::TypeToString"
+#define DFHACK_SIZEOF_NAME "DFHack::Sizeof"
/*
* Upvalue: contents of DFHACK_TYPETABLE_NAME
@@ -417,6 +418,14 @@ static void push_object_ref(lua_State *state, void *ptr)
// stack: [userdata]
}
+static void *get_object_ref(lua_State *state, int val_index)
+{
+ assert(!lua_islightuserdata(state, val_index));
+
+ auto ref = (DFRefHeader*)lua_touserdata(state, val_index);
+ return ref->ptr;
+}
+
/**
* Push the pointer using given identity.
*/
@@ -499,8 +508,42 @@ static void *get_object_internal(lua_State *state, type_identity *type, int val_
/*
* Finally decode the reference.
*/
- auto ref = (DFRefHeader*)lua_touserdata(state, val_index);
- return ref->ptr;
+ return get_object_ref(state, val_index);
+}
+
+/**
+ * Given a DF object reference or type, safely retrieve its identity pointer.
+ */
+static type_identity *get_object_identity(lua_State *state, int objidx, const char *ctx)
+{
+ if (!lua_getmetatable(state, objidx))
+ luaL_error(state, "Invalid object in %s", ctx);
+
+ // Verify object type validity
+ if (lua_isuserdata(state, objidx))
+ {
+ lua_dup(state);
+ LookupInTable(state, DFHACK_TYPETABLE_NAME);
+ }
+ else
+ {
+ lua_pushvalue(state, objidx);
+ LookupInTable(state, DFHACK_TYPEID_TABLE_NAME);
+ }
+
+ if (lua_isnil(state, -1))
+ luaL_error(state, "Invalid object metatable in %s", ctx);
+ lua_pop(state, 1);
+
+ // Extract identity from metatable
+ lua_getfield(state, -1, "_identity");
+
+ type_identity *id = (type_identity*)lua_touserdata(state, -1);
+ if (!id)
+ luaL_error(state, "Invalid object identity in %s", ctx);
+
+ lua_pop(state, 2);
+ return id;
}
/**
@@ -517,20 +560,64 @@ static int meta_ptr_compare(lua_State *state)
return 1;
}
- if (!lua_equal(state, -1, -2))
+ if (get_object_ref(state, 1) != get_object_ref(state, 2))
+ {
+ lua_pushboolean(state, false);
+ return 1;
+ }
+
+ if (!lua_rawequal(state, -1, -2))
{
// todo: nonidentical type comparison
lua_pushboolean(state, false);
return 1;
}
- auto ref1 = (DFRefHeader*)lua_touserdata(state, 1);
- auto ref2 = (DFRefHeader*)lua_touserdata(state, 2);
- lua_pushboolean(state, ref1->ptr == ref2->ptr);
+ lua_pushboolean(state, true);
return 1;
}
/**
+ * Method: sizeof for DF object references.
+ *
+ * Returns: size[, address]
+ */
+static int meta_sizeof(lua_State *state)
+{
+ int argc = lua_gettop(state);
+
+ if (argc != 1)
+ luaL_error(state, "Usage: object:sizeof() or df.sizeof(object)");
+
+ // Two special cases: nil and lightuserdata for NULL and void*
+ if (lua_isnil(state, 1))
+ {
+ lua_pushnil(state);
+ lua_pushinteger(state, 0);
+ return 2;
+ }
+
+ if (lua_islightuserdata(state, 1))
+ {
+ lua_pushnil(state);
+ lua_pushnumber(state, (size_t)lua_touserdata(state, 1));
+ return 2;
+ }
+
+ type_identity *id = get_object_identity(state, 1, "df.sizeof()");
+
+ lua_pushinteger(state, id->byte_size());
+
+ if (lua_isuserdata(state, 1))
+ {
+ lua_pushnumber(state, (size_t)get_object_ref(state, 1));
+ return 2;
+ }
+ else
+ return 1;
+}
+
+/**
* Resolve the field name in UPVAL_FIELDTABLE, die if not found.
*/
static void lookup_field(lua_State *state, int index, const char *mode)
@@ -566,8 +653,7 @@ static uint8_t *get_object_addr(lua_State *state, int obj, int field, const char
lua_pop(state, 1);
- auto ref = (DFRefHeader*)lua_touserdata(state, obj);
- return (uint8_t*)ref->ptr;
+ return (uint8_t*)get_object_ref(state, obj);
}
static void GetAdHocMetatable(lua_State *state, const struct_field_info *field);
@@ -847,9 +933,9 @@ static int meta_bitfield_index(lua_State *state)
// whole
if (lua_isuserdata(state, iidx) && lua_touserdata(state, iidx) == id)
{
- lua_Integer intv = 0;
+ size_t intv = 0;
memcpy(&intv, ptr, std::min(sizeof(intv), size_t(id->byte_size())));
- lua_pushinteger(state, intv);
+ lua_pushnumber(state, intv);
return 1;
}
@@ -880,7 +966,7 @@ static int meta_bitfield_newindex(lua_State *state)
if (!lua_isnumber(state, 3))
field_error(state, 2, "number expected", "write");
- lua_Integer intv = lua_tointeger(state, 3);
+ size_t intv = (size_t)lua_tonumber(state, 3);
memcpy(ptr, &intv, std::min(sizeof(intv), size_t(id->byte_size())));
return 0;
}
@@ -974,8 +1060,12 @@ static void SetPtrMethods(lua_State *state, int meta_idx, int read_idx)
lua_pushcclosure(state, meta_ptr_tostring, 2);
lua_setfield(state, meta_idx, "__tostring");
+ lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_SIZEOF_NAME);
+ lua_setfield(state, meta_idx, "sizeof");
+
EnableMetaField(state, read_idx, "_type");
EnableMetaField(state, read_idx, "_kind");
+ EnableMetaField(state, read_idx, "sizeof");
}
/**
@@ -1326,6 +1416,9 @@ static void RenderType(lua_State *state, compound_identity *node)
assert(base == lua_gettop(state));
+ lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_SIZEOF_NAME);
+ lua_setfield(state, base, "sizeof");
+
if (node->type() == IDTYPE_GLOBAL)
{
BuildTypeMetatable(state, node);
@@ -1389,6 +1482,9 @@ static void DoAttach(lua_State *state)
lua_pushcfunction(state, meta_type_tostring);
lua_setfield(state, LUA_REGISTRYINDEX, DFHACK_TYPE_TOSTRING_NAME);
+ lua_pushcfunction(state, meta_sizeof);
+ lua_setfield(state, LUA_REGISTRYINDEX, DFHACK_SIZEOF_NAME);
+
luaL_register(state, "df", no_functions);
{
@@ -1398,6 +1494,9 @@ static void DoAttach(lua_State *state)
// Render the type structure
RenderTypeChildren(state, compound_identity::getTopScope());
+ lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_SIZEOF_NAME);
+ lua_setfield(state, -2, "sizeof");
+
freeze_table(state, true, "df");
lua_remove(state, -2);
lua_setmetatable(state, -2);