Split LuaWrapper.cpp into two files.
							parent
							
								
									053bfe345c
								
							
						
					
					
						commit
						d865d54a90
					
				| @ -0,0 +1,872 @@ | |||||||
|  | /*
 | ||||||
|  | https://github.com/peterix/dfhack
 | ||||||
|  | Copyright (c) 2009-2011 Petr Mrázek (peterix@gmail.com) | ||||||
|  | 
 | ||||||
|  | This software is provided 'as-is', without any express or implied | ||||||
|  | warranty. In no event will the authors be held liable for any | ||||||
|  | damages arising from the use of this software. | ||||||
|  | 
 | ||||||
|  | Permission is granted to anyone to use this software for any | ||||||
|  | purpose, including commercial applications, and to alter it and | ||||||
|  | redistribute it freely, subject to the following restrictions: | ||||||
|  | 
 | ||||||
|  | 1. The origin of this software must not be misrepresented; you must | ||||||
|  | not claim that you wrote the original software. If you use this | ||||||
|  | software in a product, an acknowledgment in the product documentation | ||||||
|  | would be appreciated but is not required. | ||||||
|  | 
 | ||||||
|  | 2. Altered source versions must be plainly marked as such, and | ||||||
|  | must not be misrepresented as being the original software. | ||||||
|  | 
 | ||||||
|  | 3. This notice may not be removed or altered from any source | ||||||
|  | distribution. | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | #include "Internal.h" | ||||||
|  | 
 | ||||||
|  | #include <string> | ||||||
|  | #include <vector> | ||||||
|  | #include <map> | ||||||
|  | 
 | ||||||
|  | #include "MemAccess.h" | ||||||
|  | #include "Core.h" | ||||||
|  | #include "VersionInfo.h" | ||||||
|  | #include "tinythread.h" | ||||||
|  | // must be last due to MS stupidity
 | ||||||
|  | #include "DataDefs.h" | ||||||
|  | #include "DataIdentity.h" | ||||||
|  | #include "LuaWrapper.h" | ||||||
|  | 
 | ||||||
|  | #include "MiscUtils.h" | ||||||
|  | 
 | ||||||
|  | #include <lua.h> | ||||||
|  | #include <lauxlib.h> | ||||||
|  | 
 | ||||||
|  | using namespace DFHack; | ||||||
|  | using namespace DFHack::LuaWrapper; | ||||||
|  | 
 | ||||||
|  | /**************************************
 | ||||||
|  |  * Identity object read/write methods * | ||||||
|  |  **************************************/ | ||||||
|  | 
 | ||||||
|  | void constructed_identity::lua_read(lua_State *state, int fname_idx, void *ptr) | ||||||
|  | { | ||||||
|  |     push_object_internal(state, this, ptr); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void constructed_identity::lua_write(lua_State *state, int fname_idx, void *ptr, int val_index) | ||||||
|  | { | ||||||
|  |     field_error(state, fname_idx, "complex object", "write"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void enum_identity::lua_read(lua_State *state, int fname_idx, void *ptr) | ||||||
|  | { | ||||||
|  |     base_type->lua_read(state, fname_idx, ptr); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void enum_identity::lua_write(lua_State *state, int fname_idx, void *ptr, int val_index) | ||||||
|  | { | ||||||
|  |     base_type->lua_write(state, fname_idx, ptr, val_index); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void df::number_identity_base::lua_read(lua_State *state, int fname_idx, void *ptr) | ||||||
|  | { | ||||||
|  |     lua_pushnumber(state, read(ptr)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void df::number_identity_base::lua_write(lua_State *state, int fname_idx, void *ptr, int val_index) | ||||||
|  | { | ||||||
|  |     if (!lua_isnumber(state, val_index)) | ||||||
|  |         field_error(state, fname_idx, "number expected", "write"); | ||||||
|  | 
 | ||||||
|  |     write(ptr, lua_tonumber(state, val_index)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void df::bool_identity::lua_read(lua_State *state, int fname_idx, void *ptr) | ||||||
|  | { | ||||||
|  |     lua_pushboolean(state, *(bool*)ptr); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void df::bool_identity::lua_write(lua_State *state, int fname_idx, void *ptr, int val_index) | ||||||
|  | { | ||||||
|  |     char *pb = (char*)ptr; | ||||||
|  | 
 | ||||||
|  |     if (lua_isboolean(state, val_index) || lua_isnil(state, val_index)) | ||||||
|  |         *pb = lua_toboolean(state, val_index); | ||||||
|  |     else if (lua_isnumber(state, val_index)) | ||||||
|  |         *pb = lua_tointeger(state, val_index); | ||||||
|  |     else | ||||||
|  |         field_error(state, fname_idx, "boolean or number expected", "write"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void df::stl_string_identity::lua_read(lua_State *state, int fname_idx, void *ptr) | ||||||
|  | { | ||||||
|  |     auto pstr = (std::string*)ptr; | ||||||
|  |     lua_pushlstring(state, pstr->data(), pstr->size()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void df::stl_string_identity::lua_write(lua_State *state, int fname_idx, void *ptr, int val_index) | ||||||
|  | { | ||||||
|  |     size_t size; | ||||||
|  |     const char *bytes = lua_tolstring(state, val_index, &size); | ||||||
|  |     if (!bytes) | ||||||
|  |         field_error(state, fname_idx, "string expected", "write"); | ||||||
|  | 
 | ||||||
|  |     *(std::string*)ptr = std::string(bytes, size); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void df::pointer_identity::lua_read(lua_State *state, int fname_idx, void *ptr, type_identity *target) | ||||||
|  | { | ||||||
|  |     push_object_internal(state, target, *(void**)ptr); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void df::pointer_identity::lua_read(lua_State *state, int fname_idx, void *ptr) | ||||||
|  | { | ||||||
|  |     lua_read(state, fname_idx, ptr, target); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void df::pointer_identity::lua_write(lua_State *state, int fname_idx, void *ptr, | ||||||
|  |                                      type_identity *target, int val_index) | ||||||
|  | { | ||||||
|  |     auto pptr = (void**)ptr; | ||||||
|  | 
 | ||||||
|  |     if (lua_isnil(state, val_index)) | ||||||
|  |         *pptr = NULL; | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         void *nval = get_object_internal(state, target, val_index, false); | ||||||
|  |         if (nval) | ||||||
|  |             *pptr = nval; | ||||||
|  |         else | ||||||
|  |             field_error(state, fname_idx, "incompatible pointer type", "write"); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void df::pointer_identity::lua_write(lua_State *state, int fname_idx, void *ptr, int val_index) | ||||||
|  | { | ||||||
|  |     lua_write(state, fname_idx, ptr, target, val_index); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int container_identity::lua_item_count(lua_State *state, void *ptr) | ||||||
|  | { | ||||||
|  |     if (lua_isnumber(state, UPVAL_ITEM_COUNT)) | ||||||
|  |         return lua_tointeger(state, UPVAL_ITEM_COUNT); | ||||||
|  |     else | ||||||
|  |         return item_count(ptr); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void container_identity::lua_item_reference(lua_State *state, int fname_idx, void *ptr, int idx) | ||||||
|  | { | ||||||
|  |     auto id = (type_identity*)lua_touserdata(state, UPVAL_ITEM_ID); | ||||||
|  |     void *pitem = item_pointer(id, ptr, idx); | ||||||
|  |     push_object_internal(state, id, pitem); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void container_identity::lua_item_read(lua_State *state, int fname_idx, void *ptr, int idx) | ||||||
|  | { | ||||||
|  |     auto id = (type_identity*)lua_touserdata(state, UPVAL_ITEM_ID); | ||||||
|  |     void *pitem = item_pointer(id, ptr, idx); | ||||||
|  |     id->lua_read(state, fname_idx, pitem); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void container_identity::lua_item_write(lua_State *state, int fname_idx, void *ptr, int idx, int val_index) | ||||||
|  | { | ||||||
|  |     auto id = (type_identity*)lua_touserdata(state, UPVAL_ITEM_ID); | ||||||
|  |     void *pitem = item_pointer(id, ptr, idx); | ||||||
|  |     id->lua_write(state, fname_idx, pitem, val_index); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ptr_container_identity::lua_item_reference(lua_State *state, int fname_idx, void *ptr, int idx) | ||||||
|  | { | ||||||
|  |     auto id = (type_identity*)lua_touserdata(state, UPVAL_ITEM_ID); | ||||||
|  |     void *pitem = item_pointer(id, ptr, idx); | ||||||
|  |     push_adhoc_pointer(state, pitem, id); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ptr_container_identity::lua_item_read(lua_State *state, int fname_idx, void *ptr, int idx) | ||||||
|  | { | ||||||
|  |     auto id = (type_identity*)lua_touserdata(state, UPVAL_ITEM_ID); | ||||||
|  |     void *pitem = item_pointer(&df::identity_traits<void*>::identity, ptr, idx); | ||||||
|  |     df::pointer_identity::lua_read(state, fname_idx, pitem, id); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ptr_container_identity::lua_item_write(lua_State *state, int fname_idx, void *ptr, int idx, int val_index) | ||||||
|  | { | ||||||
|  |     auto id = (type_identity*)lua_touserdata(state, UPVAL_ITEM_ID); | ||||||
|  |     void *pitem = item_pointer(&df::identity_traits<void*>::identity, ptr, idx); | ||||||
|  |     df::pointer_identity::lua_write(state, fname_idx, pitem, id, val_index); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void bit_container_identity::lua_item_reference(lua_State *state, int, void *, int) | ||||||
|  | { | ||||||
|  |     lua_pushnil(state); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void bit_container_identity::lua_item_read(lua_State *state, int fname_idx, void *ptr, int idx) | ||||||
|  | { | ||||||
|  |     lua_pushboolean(state, get_item(ptr, idx)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void bit_container_identity::lua_item_write(lua_State *state, int fname_idx, void *ptr, int idx, int val_index) | ||||||
|  | { | ||||||
|  |     if (lua_isboolean(state, val_index) || lua_isnil(state, val_index)) | ||||||
|  |         set_item(ptr, idx, lua_toboolean(state, val_index)); | ||||||
|  |     else if (lua_isnumber(state, val_index)) | ||||||
|  |         set_item(ptr, idx, lua_tointeger(state, val_index) != 0); | ||||||
|  |     else | ||||||
|  |         field_error(state, fname_idx, "boolean or number expected", "write"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Resolve the field name in UPVAL_FIELDTABLE, die if not found. | ||||||
|  |  */ | ||||||
|  | static void lookup_field(lua_State *state, int index, const char *mode) | ||||||
|  | { | ||||||
|  |     lua_pushvalue(state, index); | ||||||
|  |     lua_gettable(state, UPVAL_FIELDTABLE); // uses metatable with enum keys
 | ||||||
|  | 
 | ||||||
|  |     if (lua_isnil(state, -1)) | ||||||
|  |         field_error(state, index, "not found", mode); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void *find_field(lua_State *state, int index, const char *mode) | ||||||
|  | { | ||||||
|  |     lookup_field(state, index, mode); | ||||||
|  | 
 | ||||||
|  |     void *p = lua_touserdata(state, -1); | ||||||
|  |     lua_pop(state, 1); | ||||||
|  |     return p; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void GetAdHocMetatable(lua_State *state, const struct_field_info *field); | ||||||
|  | 
 | ||||||
|  | static void read_field(lua_State *state, const struct_field_info *field, void *ptr) | ||||||
|  | { | ||||||
|  |     switch (field->mode) | ||||||
|  |     { | ||||||
|  |         case struct_field_info::STATIC_STRING: | ||||||
|  |         { | ||||||
|  |             int len = strnlen((char*)ptr, field->count); | ||||||
|  |             lua_pushlstring(state, (char*)ptr, len); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         case struct_field_info::PRIMITIVE: | ||||||
|  |         case struct_field_info::SUBSTRUCT: | ||||||
|  |             field->type->lua_read(state, 2, ptr); | ||||||
|  |             return; | ||||||
|  | 
 | ||||||
|  |         case struct_field_info::POINTER: | ||||||
|  |             df::pointer_identity::lua_read(state, 2, ptr, field->type); | ||||||
|  |             return; | ||||||
|  | 
 | ||||||
|  |         case struct_field_info::CONTAINER: | ||||||
|  |             if (!field->eid || !field->type->isContainer() || | ||||||
|  |                 field->eid == ((container_identity*)field->type)->getIndexEnumType()) | ||||||
|  |             { | ||||||
|  |                 field->type->lua_read(state, 2, ptr); | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |             // fallthrough
 | ||||||
|  | 
 | ||||||
|  |         case struct_field_info::STATIC_ARRAY: | ||||||
|  |         case struct_field_info::STL_VECTOR_PTR: | ||||||
|  |             GetAdHocMetatable(state, field); | ||||||
|  |             push_object_ref(state, ptr); | ||||||
|  |             return; | ||||||
|  | 
 | ||||||
|  |         case struct_field_info::END: | ||||||
|  |             break; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     lua_pushnil(state); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void field_reference(lua_State *state, const struct_field_info *field, void *ptr) | ||||||
|  | { | ||||||
|  |     switch (field->mode) | ||||||
|  |     { | ||||||
|  |         case struct_field_info::PRIMITIVE: | ||||||
|  |         case struct_field_info::SUBSTRUCT: | ||||||
|  |             push_object_internal(state, field->type, ptr); | ||||||
|  |             return; | ||||||
|  | 
 | ||||||
|  |         case struct_field_info::POINTER: | ||||||
|  |             push_adhoc_pointer(state, ptr, field->type); | ||||||
|  |             return; | ||||||
|  | 
 | ||||||
|  |         case struct_field_info::CONTAINER: | ||||||
|  |             read_field(state, field, ptr); | ||||||
|  |             return; | ||||||
|  | 
 | ||||||
|  |         case struct_field_info::STATIC_STRING: | ||||||
|  |         case struct_field_info::STATIC_ARRAY: | ||||||
|  |         case struct_field_info::STL_VECTOR_PTR: | ||||||
|  |             GetAdHocMetatable(state, field); | ||||||
|  |             push_object_ref(state, ptr); | ||||||
|  |             return; | ||||||
|  | 
 | ||||||
|  |         case struct_field_info::END: | ||||||
|  |             break; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     lua_pushnil(state); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void write_field(lua_State *state, const struct_field_info *field, void *ptr, int value_idx) | ||||||
|  | { | ||||||
|  |     switch (field->mode) | ||||||
|  |     { | ||||||
|  |         case struct_field_info::STATIC_STRING: | ||||||
|  |         { | ||||||
|  |             size_t size; | ||||||
|  |             const char *str = lua_tolstring(state, value_idx, &size); | ||||||
|  |             if (!str) | ||||||
|  |                 field_error(state, 2, "string expected", "write"); | ||||||
|  |             memcpy(ptr, str, std::min(size+1, size_t(field->count))); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         case struct_field_info::PRIMITIVE: | ||||||
|  |         case struct_field_info::SUBSTRUCT: | ||||||
|  |         case struct_field_info::CONTAINER: | ||||||
|  |             field->type->lua_write(state, 2, ptr, value_idx); | ||||||
|  |             return; | ||||||
|  | 
 | ||||||
|  |         case struct_field_info::POINTER: | ||||||
|  |             df::pointer_identity::lua_write(state, 2, ptr, field->type, value_idx); | ||||||
|  | 
 | ||||||
|  |         case struct_field_info::STATIC_ARRAY: | ||||||
|  |         case struct_field_info::STL_VECTOR_PTR: | ||||||
|  |             field_error(state, 2, "complex object", "write"); | ||||||
|  | 
 | ||||||
|  |         case struct_field_info::END: | ||||||
|  |             return; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Metamethod: represent a type node as string. | ||||||
|  |  */ | ||||||
|  | static int meta_type_tostring(lua_State *state) | ||||||
|  | { | ||||||
|  |     if (!lua_getmetatable(state, 1)) | ||||||
|  |         return 0; | ||||||
|  | 
 | ||||||
|  |     lua_getfield(state, -1, "__metatable"); | ||||||
|  |     const char *cname = lua_tostring(state, -1); | ||||||
|  | 
 | ||||||
|  |     lua_pushstring(state, stl_sprintf("<type: %s>", cname).c_str()); | ||||||
|  |     return 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Metamethod: represent a DF object reference as string. | ||||||
|  |  */ | ||||||
|  | static int meta_ptr_tostring(lua_State *state) | ||||||
|  | { | ||||||
|  |     uint8_t *ptr = get_object_addr(state, 1, 0, "access"); | ||||||
|  | 
 | ||||||
|  |     lua_getfield(state, UPVAL_METATABLE, "__metatable"); | ||||||
|  |     const char *cname = lua_tostring(state, -1); | ||||||
|  | 
 | ||||||
|  |     lua_pushstring(state, stl_sprintf("<%s: 0x%08x>", cname, (unsigned)ptr).c_str()); | ||||||
|  |     return 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Resolve the field in the metatable and return
 | ||||||
|  | static int get_metafield(lua_State *state) | ||||||
|  | { | ||||||
|  |     lua_rawget(state, UPVAL_METATABLE); | ||||||
|  |     return 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Metamethod: __index for structures. | ||||||
|  |  */ | ||||||
|  | static int meta_struct_index(lua_State *state) | ||||||
|  | { | ||||||
|  |     uint8_t *ptr = get_object_addr(state, 1, 2, "read"); | ||||||
|  |     auto field = (struct_field_info*)find_field(state, 2, "read"); | ||||||
|  |     if (!field) | ||||||
|  |         return get_metafield(state); | ||||||
|  |     read_field(state, field, ptr + field->offset); | ||||||
|  |     return 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Method: _field for structures. | ||||||
|  |  */ | ||||||
|  | static int meta_struct_field_reference(lua_State *state) | ||||||
|  | { | ||||||
|  |     if (lua_gettop(state) != 2) | ||||||
|  |         luaL_error(state, "Usage: object._field(name)"); | ||||||
|  |     uint8_t *ptr = get_object_addr(state, 1, 2, "reference"); | ||||||
|  |     auto field = (struct_field_info*)find_field(state, 2, "reference"); | ||||||
|  |     if (!field) | ||||||
|  |         field_error(state, 2, "builtin property", "reference"); | ||||||
|  |     field_reference(state, field, ptr + field->offset); | ||||||
|  |     return 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Metamethod: __newindex for structures. | ||||||
|  |  */ | ||||||
|  | static int meta_struct_newindex(lua_State *state) | ||||||
|  | { | ||||||
|  |     uint8_t *ptr = get_object_addr(state, 1, 2, "write"); | ||||||
|  |     auto field = (struct_field_info*)find_field(state, 2, "write"); | ||||||
|  |     if (!field) | ||||||
|  |         field_error(state, 2, "builtin property", "write"); | ||||||
|  |     write_field(state, field, ptr + field->offset, 3); | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Metamethod: __index for primitives, i.e. simple object references. | ||||||
|  |  *   Fields point to identity, or NULL for metafields. | ||||||
|  |  */ | ||||||
|  | static int meta_primitive_index(lua_State *state) | ||||||
|  | { | ||||||
|  |     uint8_t *ptr = get_object_addr(state, 1, 2, "read"); | ||||||
|  |     auto type = (type_identity*)find_field(state, 2, "read"); | ||||||
|  |     if (!type) | ||||||
|  |         return get_metafield(state); | ||||||
|  |     type->lua_read(state, 2, ptr); | ||||||
|  |     return 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Metamethod: __newindex for primitives. | ||||||
|  |  */ | ||||||
|  | static int meta_primitive_newindex(lua_State *state) | ||||||
|  | { | ||||||
|  |     uint8_t *ptr = get_object_addr(state, 1, 2, "write"); | ||||||
|  |     auto type = (type_identity*)find_field(state, 2, "write"); | ||||||
|  |     if (!type) | ||||||
|  |         field_error(state, 2, "builtin property", "write"); | ||||||
|  |     type->lua_write(state, 2, ptr, 3); | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Metamethod: __len for containers. | ||||||
|  |  */ | ||||||
|  | static int meta_container_len(lua_State *state) | ||||||
|  | { | ||||||
|  |     uint8_t *ptr = get_object_addr(state, 1, 0, "get length"); | ||||||
|  |     auto id = (container_identity*)lua_touserdata(state, UPVAL_CONTAINER_ID); | ||||||
|  |     int len = id->lua_item_count(state, ptr); | ||||||
|  |     lua_pushinteger(state, len); | ||||||
|  |     return 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Field lookup for containers: | ||||||
|  |  * | ||||||
|  |  *   - Numbers are indices and handled directly. | ||||||
|  |  *   - NULL userdata are metafields; push and exit; | ||||||
|  |  */ | ||||||
|  | static int lookup_container_field(lua_State *state, int field, const char *mode = NULL) | ||||||
|  | { | ||||||
|  |     if (lua_type(state, field) == LUA_TNUMBER) | ||||||
|  |         return field; | ||||||
|  | 
 | ||||||
|  |     lookup_field(state, field, mode ? mode : "read"); | ||||||
|  | 
 | ||||||
|  |     if (lua_isuserdata(state, -1) && !lua_touserdata(state, -1)) | ||||||
|  |     { | ||||||
|  |         if (mode) | ||||||
|  |             field_error(state, field, "builtin property", mode); | ||||||
|  | 
 | ||||||
|  |         lua_pop(state, 1); | ||||||
|  |         get_metafield(state); | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return -1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Index verification: number and in range. | ||||||
|  |  */ | ||||||
|  | static int check_container_index(lua_State *state, int len, | ||||||
|  |                                  int fidx, int iidx, const char *mode) | ||||||
|  | { | ||||||
|  |     if (!lua_isnumber(state, iidx)) | ||||||
|  |         field_error(state, fidx, "invalid index", mode); | ||||||
|  | 
 | ||||||
|  |     int idx = lua_tointeger(state, iidx); | ||||||
|  |     if (idx < 0 || idx >= len) | ||||||
|  |         field_error(state, fidx, "index out of bounds", mode); | ||||||
|  | 
 | ||||||
|  |     return idx; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Metamethod: __index for containers. | ||||||
|  |  */ | ||||||
|  | static int meta_container_index(lua_State *state) | ||||||
|  | { | ||||||
|  |     uint8_t *ptr = get_object_addr(state, 1, 2, "read"); | ||||||
|  |     int iidx = lookup_container_field(state, 2); | ||||||
|  |     if (!iidx) | ||||||
|  |         return 1; | ||||||
|  | 
 | ||||||
|  |     auto id = (container_identity*)lua_touserdata(state, UPVAL_CONTAINER_ID); | ||||||
|  |     int len = id->lua_item_count(state, ptr); | ||||||
|  |     int idx = check_container_index(state, len, 2, iidx, "read"); | ||||||
|  |     id->lua_item_read(state, 2, ptr, idx); | ||||||
|  |     return 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Method: _field for containers. | ||||||
|  |  */ | ||||||
|  | static int meta_container_field_reference(lua_State *state) | ||||||
|  | { | ||||||
|  |     if (lua_gettop(state) != 2) | ||||||
|  |         luaL_error(state, "Usage: object._field(index)"); | ||||||
|  |     uint8_t *ptr = get_object_addr(state, 1, 2, "reference"); | ||||||
|  |     int iidx = lookup_container_field(state, 2, "reference"); | ||||||
|  | 
 | ||||||
|  |     auto id = (container_identity*)lua_touserdata(state, UPVAL_CONTAINER_ID); | ||||||
|  |     int len = id->lua_item_count(state, ptr); | ||||||
|  |     int idx = check_container_index(state, len, 2, iidx, "reference"); | ||||||
|  |     id->lua_item_reference(state, 2, ptr, idx); | ||||||
|  |     return 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Metamethod: __index for containers. | ||||||
|  |  */ | ||||||
|  | static int meta_container_newindex(lua_State *state) | ||||||
|  | { | ||||||
|  |     uint8_t *ptr = get_object_addr(state, 1, 2, "write"); | ||||||
|  |     int iidx = lookup_container_field(state, 2, "write"); | ||||||
|  | 
 | ||||||
|  |     auto id = (container_identity*)lua_touserdata(state, UPVAL_CONTAINER_ID); | ||||||
|  |     int len = id->lua_item_count(state, ptr); | ||||||
|  |     int idx = check_container_index(state, len, 2, iidx, "write"); | ||||||
|  |     id->lua_item_write(state, 2, ptr, idx, 3); | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Metamethod: __len for bitfields. | ||||||
|  |  */ | ||||||
|  | static int meta_bitfield_len(lua_State *state) | ||||||
|  | { | ||||||
|  |     uint8_t *ptr = get_object_addr(state, 1, 0, "get size"); | ||||||
|  |     auto id = (bitfield_identity*)lua_touserdata(state, UPVAL_CONTAINER_ID); | ||||||
|  |     lua_pushinteger(state, id->getNumBits()); | ||||||
|  |     return 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Metamethod: __index for bitfields. | ||||||
|  |  */ | ||||||
|  | static int meta_bitfield_index(lua_State *state) | ||||||
|  | { | ||||||
|  |     uint8_t *ptr = get_object_addr(state, 1, 2, "read"); | ||||||
|  |     int iidx = lookup_container_field(state, 2); | ||||||
|  |     if (!iidx) | ||||||
|  |         return 1; | ||||||
|  | 
 | ||||||
|  |     auto id = (bitfield_identity*)lua_touserdata(state, UPVAL_CONTAINER_ID); | ||||||
|  | 
 | ||||||
|  |     // whole
 | ||||||
|  |     if (lua_isuserdata(state, iidx) && lua_touserdata(state, iidx) == id) | ||||||
|  |     { | ||||||
|  |         size_t intv = 0; | ||||||
|  |         memcpy(&intv, ptr, std::min(sizeof(intv), size_t(id->byte_size()))); | ||||||
|  |         lua_pushnumber(state, intv); | ||||||
|  |         return 1; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     int idx = check_container_index(state, id->getNumBits(), 2, iidx, "read"); | ||||||
|  |     int size = id->getBits()[idx].size; | ||||||
|  | 
 | ||||||
|  |     int value = getBitfieldField(ptr, idx, size); | ||||||
|  |     if (size <= 1) | ||||||
|  |         lua_pushboolean(state, value != 0); | ||||||
|  |     else | ||||||
|  |         lua_pushinteger(state, value); | ||||||
|  |     return 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Metamethod: __newindex for bitfields. | ||||||
|  |  */ | ||||||
|  | static int meta_bitfield_newindex(lua_State *state) | ||||||
|  | { | ||||||
|  |     uint8_t *ptr = get_object_addr(state, 1, 2, "write"); | ||||||
|  |     int iidx = lookup_container_field(state, 2, "write"); | ||||||
|  | 
 | ||||||
|  |     auto id = (bitfield_identity*)lua_touserdata(state, UPVAL_CONTAINER_ID); | ||||||
|  | 
 | ||||||
|  |     // whole
 | ||||||
|  |     if (lua_isuserdata(state, iidx) && lua_touserdata(state, iidx) == id) | ||||||
|  |     { | ||||||
|  |         if (!lua_isnumber(state, 3)) | ||||||
|  |             field_error(state, 2, "number expected", "write"); | ||||||
|  | 
 | ||||||
|  |         size_t intv = (size_t)lua_tonumber(state, 3); | ||||||
|  |         memcpy(ptr, &intv, std::min(sizeof(intv), size_t(id->byte_size()))); | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     int idx = check_container_index(state, id->getNumBits(), 2, iidx, "write"); | ||||||
|  |     int size = id->getBits()[idx].size; | ||||||
|  | 
 | ||||||
|  |     if (lua_isboolean(state, 3) || lua_isnil(state, 3)) | ||||||
|  |         setBitfieldField(ptr, idx, size, lua_toboolean(state, 3)); | ||||||
|  |     else if (lua_isnumber(state, 3)) | ||||||
|  |         setBitfieldField(ptr, idx, size, lua_tointeger(state, 3)); | ||||||
|  |     else | ||||||
|  |         field_error(state, 2, "number or boolean expected", "write"); | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Metamethod: __index for df.global | ||||||
|  |  */ | ||||||
|  | static int meta_global_index(lua_State *state) | ||||||
|  | { | ||||||
|  |     auto field = (struct_field_info*)find_field(state, 2, "read"); | ||||||
|  |     if (!field) | ||||||
|  |         return get_metafield(state); | ||||||
|  |     void *ptr = *(void**)field->offset; | ||||||
|  |     if (!ptr) | ||||||
|  |         field_error(state, 2, "global address not known", "read"); | ||||||
|  |     read_field(state, field, ptr); | ||||||
|  |     return 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Metamethod: __newindex for df.global | ||||||
|  |  */ | ||||||
|  | static int meta_global_newindex(lua_State *state) | ||||||
|  | { | ||||||
|  |     auto field = (struct_field_info*)find_field(state, 2, "write"); | ||||||
|  |     if (!field) | ||||||
|  |         field_error(state, 2, "builtin property", "write"); | ||||||
|  |     void *ptr = *(void**)field->offset; | ||||||
|  |     if (!ptr) | ||||||
|  |         field_error(state, 2, "global address not known", "write"); | ||||||
|  |     write_field(state, field, ptr, 3); | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Add fields in the array to the UPVAL_FIELDTABLE candidates on the stack. | ||||||
|  |  */ | ||||||
|  | static void IndexFields(lua_State *state, struct_identity *pstruct) | ||||||
|  | { | ||||||
|  |     // stack: fieldtable
 | ||||||
|  | 
 | ||||||
|  |     int base = lua_gettop(state); | ||||||
|  | 
 | ||||||
|  |     for (struct_identity *p = pstruct; p; p = p->getParent()) | ||||||
|  |     { | ||||||
|  |         auto fields = p->getFields(); | ||||||
|  | 
 | ||||||
|  |         for (; fields; ++fields) | ||||||
|  |         { | ||||||
|  |             if (fields->mode == struct_field_info::END) | ||||||
|  |                 break; | ||||||
|  | 
 | ||||||
|  |             lua_pushstring(state,fields->name); | ||||||
|  |             lua_pushlightuserdata(state,(void*)fields); | ||||||
|  |             lua_rawset(state,base); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Make a struct-style object metatable. | ||||||
|  |  */ | ||||||
|  | static void MakeFieldMetatable(lua_State *state, struct_identity *pstruct, | ||||||
|  |                                lua_CFunction reader, lua_CFunction writer) | ||||||
|  | { | ||||||
|  |     int base = lua_gettop(state); | ||||||
|  | 
 | ||||||
|  |     MakeMetatable(state, pstruct, "struct"); // meta, fields
 | ||||||
|  | 
 | ||||||
|  |     IndexFields(state, pstruct); | ||||||
|  | 
 | ||||||
|  |     SetStructMethod(state, base+1, base+2, reader, "__index"); | ||||||
|  |     SetStructMethod(state, base+1, base+2, writer, "__newindex"); | ||||||
|  | 
 | ||||||
|  |     // returns: [metatable readfields writefields];
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Make a primitive-style metatable | ||||||
|  |  */ | ||||||
|  | static void MakePrimitiveMetatable(lua_State *state, type_identity *type) | ||||||
|  | { | ||||||
|  |     int base = lua_gettop(state); | ||||||
|  | 
 | ||||||
|  |     MakeMetatable(state, type, "primitive"); | ||||||
|  | 
 | ||||||
|  |     SetPtrMethods(state, base+1, base+2); | ||||||
|  | 
 | ||||||
|  |     EnableMetaField(state, base+2, "value", type); | ||||||
|  | 
 | ||||||
|  |     SetStructMethod(state, base+1, base+2, meta_primitive_index, "__index"); | ||||||
|  |     SetStructMethod(state, base+1, base+2, meta_primitive_newindex, "__newindex"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Make a container-style object metatable. | ||||||
|  |  */ | ||||||
|  | static void MakeContainerMetatable(lua_State *state, container_identity *type, | ||||||
|  |                                    type_identity *item, int count, type_identity *ienum) | ||||||
|  | { | ||||||
|  |     int base = lua_gettop(state); | ||||||
|  | 
 | ||||||
|  |     MakeMetatable(state, type, "container"); | ||||||
|  |     SetPtrMethods(state, base+1, base+2); | ||||||
|  | 
 | ||||||
|  |     // Update the type name using full info
 | ||||||
|  |     lua_pushstring(state, type->getFullName(item).c_str()); | ||||||
|  |     lua_dup(state); | ||||||
|  |     lua_setfield(state, base+1, "__metatable"); | ||||||
|  |     lua_setfield(state, base+1, "_type"); | ||||||
|  | 
 | ||||||
|  |     lua_pushlightuserdata(state, item); | ||||||
|  |     lua_setfield(state, base+1, "_field_identity"); | ||||||
|  | 
 | ||||||
|  |     if (count >= 0) | ||||||
|  |     { | ||||||
|  |         lua_pushinteger(state, count); | ||||||
|  |         lua_setfield(state, base+1, "_count"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     SetContainerMethod(state, base+1, base+2, meta_container_len, "__len", type, item, count); | ||||||
|  |     SetContainerMethod(state, base+1, base+2, meta_container_index, "__index", type, item, count); | ||||||
|  |     SetContainerMethod(state, base+1, base+2, meta_container_newindex, "__newindex", type, item, count); | ||||||
|  | 
 | ||||||
|  |     SetContainerMethod(state, base+1, base+2, meta_container_field_reference, "_field", type, item, count); | ||||||
|  | 
 | ||||||
|  |     AttachEnumKeys(state, base+1, base+2, ienum); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Metatable construction identity methods. | ||||||
|  |  */ | ||||||
|  | void type_identity::build_metatable(lua_State *state) | ||||||
|  | { | ||||||
|  |     MakePrimitiveMetatable(state, this); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void container_identity::build_metatable(lua_State *state) | ||||||
|  | { | ||||||
|  |     MakeContainerMetatable(state, this, getItemType(), -1, getIndexEnumType()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void bitfield_identity::build_metatable(lua_State *state) | ||||||
|  | { | ||||||
|  |     int base = lua_gettop(state); | ||||||
|  | 
 | ||||||
|  |     MakeMetatable(state, this, "bitfield"); | ||||||
|  | 
 | ||||||
|  |     SetPtrMethods(state, base+1, base+2); | ||||||
|  | 
 | ||||||
|  |     SetContainerMethod(state, base+1, base+2, meta_bitfield_len, "__len", this, NULL, -1); | ||||||
|  |     SetContainerMethod(state, base+1, base+2, meta_bitfield_index, "__index", this, NULL, -1); | ||||||
|  |     SetContainerMethod(state, base+1, base+2, meta_bitfield_newindex, "__newindex", this, NULL, -1); | ||||||
|  | 
 | ||||||
|  |     AttachEnumKeys(state, base+1, base+2, this); | ||||||
|  | 
 | ||||||
|  |     EnableMetaField(state, base+2, "whole", this); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void struct_identity::build_metatable(lua_State *state) | ||||||
|  | { | ||||||
|  |     int base = lua_gettop(state); | ||||||
|  |     MakeFieldMetatable(state, this, meta_struct_index, meta_struct_newindex); | ||||||
|  |     SetStructMethod(state, base+1, base+2, meta_struct_field_reference, "_field"); | ||||||
|  |     SetPtrMethods(state, base+1, base+2); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void global_identity::build_metatable(lua_State *state) | ||||||
|  | { | ||||||
|  |     MakeFieldMetatable(state, this, meta_global_index, meta_global_newindex); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Construct a metatable for an object type folded into the field descriptor. | ||||||
|  |  * This is done to reduce compile-time symbol table bloat due to templates. | ||||||
|  |  */ | ||||||
|  | static void GetAdHocMetatable(lua_State *state, const struct_field_info *field) | ||||||
|  | { | ||||||
|  |     lua_pushlightuserdata(state, (void*)field); | ||||||
|  | 
 | ||||||
|  |     if (!LookupTypeInfo(state, true)) | ||||||
|  |     { | ||||||
|  |         switch (field->mode) | ||||||
|  |         { | ||||||
|  |         case struct_field_info::CONTAINER: | ||||||
|  |         { | ||||||
|  |             auto ctype = (container_identity*)field->type; | ||||||
|  |             MakeContainerMetatable(state, ctype, ctype->getItemType(), -1, field->eid); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         case struct_field_info::STATIC_STRING: | ||||||
|  |             MakeContainerMetatable(state, &df::buffer_container_identity::base_instance, | ||||||
|  |                                    &df::identity_traits<char>::identity, field->count, NULL); | ||||||
|  |             break; | ||||||
|  | 
 | ||||||
|  |         case struct_field_info::STATIC_ARRAY: | ||||||
|  |             MakeContainerMetatable(state, &df::buffer_container_identity::base_instance, | ||||||
|  |                                    field->type, field->count, field->eid); | ||||||
|  |             break; | ||||||
|  | 
 | ||||||
|  |         case struct_field_info::STL_VECTOR_PTR: | ||||||
|  |             MakeContainerMetatable(state, &df::identity_traits<std::vector<void*> >::identity, | ||||||
|  |                                    field->type, -1, field->eid); | ||||||
|  |             break; | ||||||
|  | 
 | ||||||
|  |         default: | ||||||
|  |             luaL_error(state, "Invalid ad-hoc field: %d", field->mode); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         lua_pop(state, 1); | ||||||
|  | 
 | ||||||
|  |         SaveTypeInfo(state, (void*)field); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void LuaWrapper::push_adhoc_pointer(lua_State *state, void *ptr, type_identity *target) | ||||||
|  | { | ||||||
|  |     if (!target) | ||||||
|  |     { | ||||||
|  |         push_object_internal(state, &df::identity_traits<void*>::identity, ptr); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     LookupInTable(state, target, DFHACK_PTR_IDTABLE_NAME); | ||||||
|  | 
 | ||||||
|  |     type_identity *id = (type_identity*)lua_touserdata(state, -1); | ||||||
|  |     lua_pop(state, 1); | ||||||
|  | 
 | ||||||
|  |     if (!id) | ||||||
|  |     { | ||||||
|  |         /*
 | ||||||
|  |          * HACK: relies on | ||||||
|  |          *   1) pointer_identity destructor being no-op | ||||||
|  |          *   2) lua gc never moving objects in memory | ||||||
|  |          */ | ||||||
|  | 
 | ||||||
|  |         void *newobj = lua_newuserdata(state, sizeof(pointer_identity)); | ||||||
|  |         id = new (newobj) pointer_identity(target); | ||||||
|  | 
 | ||||||
|  |         SaveInTable(state, target, DFHACK_PTR_IDTABLE_NAME); | ||||||
|  |         lua_pop(state, 1); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     push_object_internal(state, id, ptr); | ||||||
|  | } | ||||||
											
												
													File diff suppressed because it is too large
													Load Diff
												
											
										
									
								| @ -0,0 +1,189 @@ | |||||||
|  | /*
 | ||||||
|  | https://github.com/peterix/dfhack
 | ||||||
|  | Copyright (c) 2009-2011 Petr Mrázek (peterix@gmail.com) | ||||||
|  | 
 | ||||||
|  | This software is provided 'as-is', without any express or implied | ||||||
|  | warranty. In no event will the authors be held liable for any | ||||||
|  | damages arising from the use of this software. | ||||||
|  | 
 | ||||||
|  | Permission is granted to anyone to use this software for any | ||||||
|  | purpose, including commercial applications, and to alter it and | ||||||
|  | redistribute it freely, subject to the following restrictions: | ||||||
|  | 
 | ||||||
|  | 1. The origin of this software must not be misrepresented; you must | ||||||
|  | not claim that you wrote the original software. If you use this | ||||||
|  | software in a product, an acknowledgment in the product documentation | ||||||
|  | would be appreciated but is not required. | ||||||
|  | 
 | ||||||
|  | 2. Altered source versions must be plainly marked as such, and | ||||||
|  | must not be misrepresented as being the original software. | ||||||
|  | 
 | ||||||
|  | 3. This notice may not be removed or altered from any source | ||||||
|  | distribution. | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <string> | ||||||
|  | #include <sstream> | ||||||
|  | #include <vector> | ||||||
|  | #include <map> | ||||||
|  | 
 | ||||||
|  | #include "DataDefs.h" | ||||||
|  | 
 | ||||||
|  | #include <lua.h> | ||||||
|  | #include <lauxlib.h> | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Internal header file of the lua wrapper. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | namespace DFHack { namespace LuaWrapper { | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Registry name: hash of type metatables <-> type identities. | ||||||
|  |  */ | ||||||
|  | #define DFHACK_TYPETABLE_NAME "DFHack::DFTypes" | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Registry name: hash of type identity -> node in df.etc... | ||||||
|  |  */ | ||||||
|  | #define DFHACK_TYPEID_TABLE_NAME "DFHack::DFTypeIds" | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Registry name: hash of enum/bitfield identity -> index lookup table | ||||||
|  |  */ | ||||||
|  | #define DFHACK_ENUM_TABLE_NAME "DFHack::DFEnums" | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Registry name: hash of pointer target identity <-> adhoc pointer identity userdata. | ||||||
|  |  */ | ||||||
|  | #define DFHACK_PTR_IDTABLE_NAME "DFHack::PtrDFTypes" | ||||||
|  | 
 | ||||||
|  | // Function registry names
 | ||||||
|  | #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" | ||||||
|  | #define DFHACK_DISPLACE_NAME "DFHack::Displace" | ||||||
|  | #define DFHACK_NEW_NAME "DFHack::New" | ||||||
|  | #define DFHACK_ASSIGN_NAME "DFHack::Assign" | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Upvalue: contents of DFHACK_TYPETABLE_NAME | ||||||
|  |  */ | ||||||
|  | #define UPVAL_TYPETABLE lua_upvalueindex(1) | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Expected metatable of the current object. | ||||||
|  |  */ | ||||||
|  | #define UPVAL_METATABLE lua_upvalueindex(2) | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Table mapping field names to indices or data structure pointers. | ||||||
|  |  * Enum index table is linked into here via getmetatable($).__index. | ||||||
|  |  * Fields that are actually in UPVAL_METATABLE are marked with NULL light udata. | ||||||
|  |  */ | ||||||
|  | #define UPVAL_FIELDTABLE lua_upvalueindex(3) | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Only for containers: light udata with container identity. | ||||||
|  |  */ | ||||||
|  | #define UPVAL_CONTAINER_ID lua_upvalueindex(4) | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Only for containers: light udata with item identity. | ||||||
|  |  */ | ||||||
|  | #define UPVAL_ITEM_ID lua_upvalueindex(5) | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Only for containers: if not nil, overrides the item count. | ||||||
|  |  */ | ||||||
|  | #define UPVAL_ITEM_COUNT lua_upvalueindex(6) | ||||||
|  | 
 | ||||||
|  |     inline void lua_dup(lua_State *state) { lua_pushvalue(state, -1); } | ||||||
|  |     inline void lua_swap(lua_State *state) { lua_insert(state, -2); } | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Object references are represented as userdata instances | ||||||
|  |      * with an appropriate metatable; the payload of userdata is | ||||||
|  |      * this structure: | ||||||
|  |      */ | ||||||
|  |     struct DFRefHeader { | ||||||
|  |         void *ptr; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Push the pointer as DF object ref using metatable on the stack. | ||||||
|  |      */ | ||||||
|  |     void push_object_ref(lua_State *state, void *ptr); | ||||||
|  |     void *get_object_ref(lua_State *state, int val_index); | ||||||
|  | 
 | ||||||
|  |     /*
 | ||||||
|  |      * The system might be extended to carry some simple | ||||||
|  |      * objects inline inside the reference buffer. | ||||||
|  |      */ | ||||||
|  |     inline bool is_self_contained(DFRefHeader *ptr) { | ||||||
|  |         void **pp = &ptr->ptr; | ||||||
|  |         return **(void****)pp == (pp + 1); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |     * Report an error while accessing a field (index = field name). | ||||||
|  |     */ | ||||||
|  |     void field_error(lua_State *state, int index, const char *err, const char *mode); | ||||||
|  | 
 | ||||||
|  |     /*
 | ||||||
|  |      * If is_method is true, these use UPVAL_TYPETABLE to save a hash lookup. | ||||||
|  |      */ | ||||||
|  |     void push_object_internal(lua_State *state, type_identity *type, void *ptr, bool in_method = true); | ||||||
|  |     void *get_object_internal(lua_State *state, type_identity *type, int val_index, bool exact_type, bool in_method = true); | ||||||
|  | 
 | ||||||
|  |     void push_adhoc_pointer(lua_State *state, void *ptr, type_identity *target); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Verify that the object is a DF ref with UPVAL_METATABLE. | ||||||
|  |      * If everything ok, extract the address. | ||||||
|  |      */ | ||||||
|  |     uint8_t *get_object_addr(lua_State *state, int obj, int field, const char *mode); | ||||||
|  | 
 | ||||||
|  |     void LookupInTable(lua_State *state, void *id, const char *tname); | ||||||
|  |     void SaveInTable(lua_State *state, void *node, const char *tname); | ||||||
|  |     void SaveTypeInfo(lua_State *state, void *node); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Look up the key on the stack in DFHACK_TYPETABLE; | ||||||
|  |      * if found, put result on the stack and return true. | ||||||
|  |      */ | ||||||
|  |     bool LookupTypeInfo(lua_State *state, bool in_method); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Make a metatable with most common fields, and an empty table for UPVAL_FIELDTABLE. | ||||||
|  |      */ | ||||||
|  |     void MakeMetatable(lua_State *state, type_identity *type, const char *kind); | ||||||
|  |     /**
 | ||||||
|  |      * Enable a metafield by injecting an entry into a UPVAL_FIELDTABLE. | ||||||
|  |      */ | ||||||
|  |     void EnableMetaField(lua_State *state, int ftable_idx, const char *name, void *id = NULL); | ||||||
|  |     /**
 | ||||||
|  |      * Set metatable properties common to all actual DF object references. | ||||||
|  |      */ | ||||||
|  |     void SetPtrMethods(lua_State *state, int meta_idx, int read_idx); | ||||||
|  |     /**
 | ||||||
|  |      * Add a struct-style (3 upvalues) metamethod to the metatable. | ||||||
|  |      */ | ||||||
|  |     void SetStructMethod(lua_State *state, int meta_idx, int ftable_idx, | ||||||
|  |                          lua_CFunction function, const char *name); | ||||||
|  |     /**
 | ||||||
|  |      * Add a 6 upvalue metamethod to the metatable. | ||||||
|  |      */ | ||||||
|  |     void SetContainerMethod(lua_State *state, int meta_idx, int ftable_idx, | ||||||
|  |                             lua_CFunction function, const char *name, | ||||||
|  |                             type_identity *container, type_identity *item, int count); | ||||||
|  |     /**
 | ||||||
|  |      * If ienum refers to a valid enum, attach its keys to UPVAL_FIELDTABLE, | ||||||
|  |      * and the enum itself to the _enum metafield. | ||||||
|  |      */ | ||||||
|  |     void AttachEnumKeys(lua_State *state, int meta_idx, int ftable_idx, type_identity *ienum); | ||||||
|  | }} | ||||||
|  | 
 | ||||||
		Loading…
	
		Reference in New Issue