summaryrefslogtreecommitdiff
path: root/library/LuaWrapper.cpp
diff options
context:
space:
mode:
authorAlexander Gavrilov2012-03-23 11:54:59 +0400
committerAlexander Gavrilov2012-03-23 11:54:59 +0400
commit6b2006361dfc2e976c70f8b5507acb9f8a7224db (patch)
tree0ef3535e232042a4a0bfaa1a1ee7303230a49e20 /library/LuaWrapper.cpp
parent78437310d0e032880d19ee97eac67af60b369258 (diff)
downloaddfhack-6b2006361dfc2e976c70f8b5507acb9f8a7224db.tar.gz
dfhack-6b2006361dfc2e976c70f8b5507acb9f8a7224db.tar.bz2
dfhack-6b2006361dfc2e976c70f8b5507acb9f8a7224db.tar.xz
Add a _displace method that implements offsetting a pointer by an int.
Diffstat (limited to 'library/LuaWrapper.cpp')
-rw-r--r--library/LuaWrapper.cpp75
1 files changed, 73 insertions, 2 deletions
diff --git a/library/LuaWrapper.cpp b/library/LuaWrapper.cpp
index a394b4cf..9214a4c5 100644
--- a/library/LuaWrapper.cpp
+++ b/library/LuaWrapper.cpp
@@ -68,6 +68,7 @@ inline void lua_swap(lua_State *state) { lua_insert(state, -2); }
#define DFHACK_COMPARE_NAME "DFHack::ComparePtrs"
#define DFHACK_TYPE_TOSTRING_NAME "DFHack::TypeToString"
#define DFHACK_SIZEOF_NAME "DFHack::Sizeof"
+#define DFHACK_DISPLACE_NAME "DFHack::Displace"
/*
* Upvalue: contents of DFHACK_TYPETABLE_NAME
@@ -514,7 +515,8 @@ static void *get_object_internal(lua_State *state, type_identity *type, int val_
/**
* 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)
+static type_identity *get_object_identity(lua_State *state, int objidx,
+ const char *ctx, bool allow_type = false)
{
if (!lua_getmetatable(state, objidx))
luaL_error(state, "Invalid object in %s", ctx);
@@ -527,6 +529,9 @@ static type_identity *get_object_identity(lua_State *state, int objidx, const ch
}
else
{
+ if (!allow_type)
+ luaL_error(state, "Object expected in %s", ctx);
+
lua_pushvalue(state, objidx);
LookupInTable(state, DFHACK_TYPEID_TABLE_NAME);
}
@@ -604,7 +609,7 @@ static int meta_sizeof(lua_State *state)
return 2;
}
- type_identity *id = get_object_identity(state, 1, "df.sizeof()");
+ type_identity *id = get_object_identity(state, 1, "df.sizeof()", true);
lua_pushinteger(state, id->byte_size());
@@ -618,6 +623,62 @@ static int meta_sizeof(lua_State *state)
}
/**
+ * Method: displace for DF object references.
+ *
+ * Returns: a reference with the same type, but modified address
+ */
+static int meta_displace(lua_State *state)
+{
+ int argc = lua_gettop(state);
+
+ bool has_step = (argc >= 3);
+ if ((argc < 2 || argc > 3) ||
+ !lua_isnumber(state, 2) ||
+ (has_step && !lua_isnumber(state, 3)))
+ {
+ luaL_error(state, "Usage: object:_displace(index[,step]) or df._displace(object,...)");
+ }
+
+ int index = lua_tointeger(state, 2);
+ int step = has_step ? lua_tointeger(state, 3) : 1;
+
+ // Two special cases: nil and lightuserdata for NULL and void*
+ if (lua_isnil(state, 1))
+ {
+ lua_pushnil(state);
+ return 1;
+ }
+
+ if (lua_islightuserdata(state, 1))
+ {
+ if (!has_step)
+ luaL_error(state, "Step is mandatory in _displace of void*");
+
+ auto ptr = (uint8_t*)lua_touserdata(state, 1);
+ lua_pushlightuserdata(state, ptr + index*step);
+ return 1;
+ }
+
+ type_identity *id = get_object_identity(state, 1, "df._displace()");
+
+ if (!has_step)
+ step = id->byte_size();
+
+ if (index == 0 || step == 0)
+ {
+ lua_pushvalue(state, 1);
+ }
+ else
+ {
+ auto ptr = (uint8_t*)get_object_ref(state, 1);
+ lua_getmetatable(state, 1);
+ push_object_ref(state, ptr + index*step);
+ }
+
+ 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)
@@ -1063,9 +1124,14 @@ static void SetPtrMethods(lua_State *state, int meta_idx, int read_idx)
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_SIZEOF_NAME);
lua_setfield(state, meta_idx, "sizeof");
+ lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_DISPLACE_NAME);
+ lua_setfield(state, meta_idx, "_displace");
+
EnableMetaField(state, read_idx, "_type");
EnableMetaField(state, read_idx, "_kind");
+
EnableMetaField(state, read_idx, "sizeof");
+ EnableMetaField(state, read_idx, "_displace");
}
/**
@@ -1485,6 +1551,9 @@ static void DoAttach(lua_State *state)
lua_pushcfunction(state, meta_sizeof);
lua_setfield(state, LUA_REGISTRYINDEX, DFHACK_SIZEOF_NAME);
+ lua_pushcfunction(state, meta_displace);
+ lua_setfield(state, LUA_REGISTRYINDEX, DFHACK_DISPLACE_NAME);
+
luaL_register(state, "df", no_functions);
{
@@ -1496,6 +1565,8 @@ static void DoAttach(lua_State *state)
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_SIZEOF_NAME);
lua_setfield(state, -2, "sizeof");
+ lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_DISPLACE_NAME);
+ lua_setfield(state, -2, "_displace");
freeze_table(state, true, "df");
lua_remove(state, -2);