From 8d7cf092fd6f3f1cf68e6b48b8f3dc42ef40dcfa Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Wed, 13 Jun 2012 21:12:36 +0400 Subject: [PATCH] Add Lua API for access to some contextual and low-level info. --- LUA_API.rst | 39 +++++++++++++++ Lua API.html | 52 +++++++++++++++---- library/LuaApi.cpp | 115 +++++++++++++++++++++++++++++++++++++++++++ library/LuaTools.cpp | 6 +-- 4 files changed, 199 insertions(+), 13 deletions(-) diff --git a/LUA_API.rst b/LUA_API.rst index 0736b02b7..54105d045 100644 --- a/LUA_API.rst +++ b/LUA_API.rst @@ -607,6 +607,22 @@ One notable difference is that these explicit wrappers allow argument count adjustment according to the usual lua rules, so trailing false/nil arguments can be omitted. +* ``dfhack.getOSType()`` + + Returns the OS type string from ``symbols.xml``. + +* ``dfhack.getDFVersion()`` + + Returns the DF version string from ``symbols.xml``. + +* ``dfhack.getDFPath()`` + + Returns the DF directory path. + +* ``dfhack.getHackPath()`` + + Returns the dfhack directory path, i.e. ``".../df/hack/"``. + * ``dfhack.isWorldLoaded()`` Checks if the world is loaded. @@ -1102,6 +1118,29 @@ Constructions module Returns *true, was_only_planned* if removed; or *false* if none found. +Internal API +------------ + +These functions are intended for the use by dfhack developers, +and are only documented here for completeness: + +* ``dfhack.internal.getAddress(name)`` + + Returns the global address ``name``, or *nil*. + +* ``dfhack.internal.setAddress(name, value)`` + + Sets the global address ``name``. Returns the value of ``getAddress`` before the change. + +* ``dfhack.internal.getBase()`` + + Returns the base address of the process. + +* ``dfhack.internal.getMemRanges()`` + + Returns a sequence of tables describing virtual memory ranges of the process. + + Core interpreter context ======================== diff --git a/Lua API.html b/Lua API.html index 568090a76..02e7abf3c 100644 --- a/Lua API.html +++ b/Lua API.html @@ -345,17 +345,18 @@ ul.auto-toc {
  • Burrows module
  • Buildings module
  • Constructions module
  • +
  • Internal API
  • -
  • Core interpreter context
  • -
  • Plugins @@ -862,6 +863,18 @@ One notable difference is that these explicit wrappers allow argument count adjustment according to the usual lua rules, so trailing false/nil arguments can be omitted.

    +
    +

    Internal API

    +

    These functions are intended for the use by dfhack developers, +and are only documented here for completeness:

    +
      +
    • dfhack.internal.getAddress(name)

      +

      Returns the global address name, or nil.

      +
    • +
    • dfhack.internal.setAddress(name, value)

      +

      Sets the global address name. Returns the value of getAddress before the change.

      +
    • +
    • dfhack.internal.getBase()

      +

      Returns the base address of the process.

      +
    • +
    • dfhack.internal.getMemRanges()

      +

      Returns a sequence of tables describing virtual memory ranges of the process.

      +
    • +
    +
    -

    Core interpreter context

    +

    Core interpreter context

    While plugins can create any number of interpreter instances, there is one special context managed by dfhack core. It is the only context that can receive events from DF and plugins.

    @@ -1307,7 +1339,7 @@ Using timeout_active(id,nil) cancels the timer
  • -

    Event type

    +

    Event type

    An event is just a lua table with a predefined metatable that contains a __call metamethod. When it is invoked, it loops through the table with next and calls all contained values. @@ -1333,14 +1365,14 @@ order using dfhack.safecall.

    -

    Plugins

    +

    Plugins

    DFHack plugins may export native functions and events to lua contexts. They are automatically imported by mkmodule('plugins.<name>'); this means that a lua module file is still necessary for require to read.

    The following plugins have lua support.

    -

    burrows

    +

    burrows

    Implements extended burrow manipulations.

    Events:

      @@ -1378,7 +1410,7 @@ set is the same as used by the command line.

      The lua module file also re-exports functions from dfhack.burrows.

    -

    sort

    +

    sort

    Does not export any native functions as of now. Instead, it calls lua code to perform the actual ordering of list items.

    diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 8e8a3c4e3..aa168db3a 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -84,6 +84,8 @@ distribution. using namespace DFHack; using namespace DFHack::LuaWrapper; +void dfhack_printerr(lua_State *S, const std::string &str); + void Lua::Push(lua_State *state, const Units::NoblePosition &pos) { lua_createtable(state, 0, 3); @@ -640,10 +642,37 @@ static void OpenModule(lua_State *state, const char *mname, /***** DFHack module *****/ +static std::string getOSType() +{ + switch (Core::getInstance().vinfo->getOS()) + { + case OS_WINDOWS: + return "windows"; + + case OS_LINUX: + return "linux"; + + case OS_APPLE: + return "darwin"; + + default: + return "unknown"; + } +} + +static std::string getDFVersion() { return Core::getInstance().vinfo->getVersion(); } + +static std::string getDFPath() { return Core::getInstance().p->getPath(); } +static std::string getHackPath() { return Core::getInstance().getHackPath(); } + static bool isWorldLoaded() { return Core::getInstance().isWorldLoaded(); } static bool isMapLoaded() { return Core::getInstance().isMapLoaded(); } static const LuaWrapper::FunctionReg dfhack_module[] = { + WRAP(getOSType), + WRAP(getDFVersion), + WRAP(getDFPath), + WRAP(getHackPath), WRAP(isWorldLoaded), WRAP(isMapLoaded), WRAPM(Translation, TranslateName), @@ -990,6 +1019,91 @@ static const luaL_Reg dfhack_constructions_funcs[] = { { NULL, NULL } }; +/***** Internal module *****/ + +static uint32_t getBase() { return Core::getInstance().p->getBase(); } + +static const LuaWrapper::FunctionReg dfhack_internal_module[] = { + WRAP(getBase), + { NULL, NULL } +}; + +static int internal_getAddress(lua_State *L) +{ + const char *name = luaL_checkstring(L, 1); + uint32_t addr = Core::getInstance().vinfo->getAddress(name); + if (addr) + lua_pushnumber(L, addr); + else + lua_pushnil(L); + return 1; +} + +static int internal_setAddress(lua_State *L) +{ + std::string name = luaL_checkstring(L, 1); + uint32_t addr = luaL_checkint(L, 2); + internal_getAddress(L); + + // Set the address + Core::getInstance().vinfo->setAddress(name, addr); + + auto fields = df::global::_identity.getFields(); + + for (int i = 0; fields && fields[i].mode != struct_field_info::END; ++i) + { + if (fields[i].name != name) + continue; + + *(void**)fields[i].offset = (void*)addr; + } + + // Print via printerr, so that it is definitely logged to stderr.log. + std::string msg = stl_sprintf("", name.c_str(), addr); + dfhack_printerr(L, msg); + + return 1; +} + +static int internal_getMemRanges(lua_State *L) +{ + std::vector ranges; + Core::getInstance().p->getMemRanges(ranges); + + lua_newtable(L); + + for(size_t i = 0; i < ranges.size(); i++) + { + lua_newtable(L); + lua_pushnumber(L, (uint32_t)ranges[i].start); + lua_setfield(L, -2, "start"); + lua_pushnumber(L, (uint32_t)ranges[i].end); + lua_setfield(L, -2, "end"); + lua_pushstring(L, ranges[i].name); + lua_setfield(L, -2, "name"); + lua_pushboolean(L, ranges[i].read); + lua_setfield(L, -2, "read"); + lua_pushboolean(L, ranges[i].write); + lua_setfield(L, -2, "write"); + lua_pushboolean(L, ranges[i].execute); + lua_setfield(L, -2, "execute"); + lua_pushboolean(L, ranges[i].shared); + lua_setfield(L, -2, "shared"); + lua_pushboolean(L, ranges[i].valid); + lua_setfield(L, -2, "valid"); + lua_rawseti(L, -2, i+1); + } + + return 1; +} + +static const luaL_Reg dfhack_internal_funcs[] = { + { "getAddress", internal_getAddress }, + { "setAddress", internal_setAddress }, + { "getMemRanges", internal_getMemRanges }, + { NULL, NULL } +}; + /************************ * Main Open function * @@ -1009,4 +1123,5 @@ void OpenDFHackApi(lua_State *state) OpenModule(state, "burrows", dfhack_burrows_module, dfhack_burrows_funcs); OpenModule(state, "buildings", dfhack_buildings_module, dfhack_buildings_funcs); OpenModule(state, "constructions", dfhack_constructions_module); + OpenModule(state, "internal", dfhack_internal_module, dfhack_internal_funcs); } diff --git a/library/LuaTools.cpp b/library/LuaTools.cpp index f794f6b41..752c341b2 100644 --- a/library/LuaTools.cpp +++ b/library/LuaTools.cpp @@ -66,6 +66,8 @@ using namespace DFHack::LuaWrapper; lua_State *DFHack::Lua::Core::State = NULL; +void dfhack_printerr(lua_State *S, const std::string &str); + inline void AssertCoreSuspend(lua_State *state) { assert(!Lua::IsCoreContext(state) || DFHack::Core::getInstance().isSuspended()); @@ -96,8 +98,6 @@ static void check_valid_ptr_index(lua_State *state, int val_index) } } -static void dfhack_printerr(lua_State *S, const std::string &str); - static void signal_typeid_error(color_ostream *out, lua_State *state, type_identity *type, const char *msg, int val_index, bool perr, bool signal) @@ -233,7 +233,7 @@ static int lua_dfhack_println(lua_State *S) return 0; } -static void dfhack_printerr(lua_State *S, const std::string &str) +void dfhack_printerr(lua_State *S, const std::string &str) { if (color_ostream *out = Lua::GetOutput(S)) out->printerr("%s\n", str.c_str());