From 9adf310d7f162ba58da764bed2c918487c692f6b Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Tue, 22 May 2012 12:31:37 +0400 Subject: Update Units::isCitizen after looking at game-over detection code. --- library/LuaApi.cpp | 2 ++ library/modules/Units.cpp | 71 +++++++++++++++++++++++++++++++++++++++++------ library/xml | 2 +- 3 files changed, 66 insertions(+), 9 deletions(-) (limited to 'library') diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 6a550db8..8e8a3c4e 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -715,6 +715,8 @@ static const LuaWrapper::FunctionReg dfhack_units_module[] = { WRAPM(Units, isDead), WRAPM(Units, isAlive), WRAPM(Units, isSane), + WRAPM(Units, isDwarf), + WRAPM(Units, isCitizen), WRAPM(Units, getAge), WRAPM(Units, getProfessionName), WRAPM(Units, getCasteProfessionName), diff --git a/library/modules/Units.cpp b/library/modules/Units.cpp index dd26109e..ee383cc0 100644 --- a/library/modules/Units.cpp +++ b/library/modules/Units.cpp @@ -613,12 +613,45 @@ df::nemesis_record *Units::getNemesis(df::unit *unit) return NULL; } +static bool casteFlagSet(int race, int caste, df::caste_raw_flags flag) +{ + auto creature = df::creature_raw::find(race); + if (!creature) + return false; + + auto craw = vector_get(creature->caste, caste); + if (!craw) + return false; + + return craw->flags.is_set(flag); +} + +static bool isCrazed(df::unit *unit) +{ + if (unit->flags3.bits.scuttle) + return false; + if (unit->curse.rem_tags1.bits.CRAZED) + return false; + if (unit->curse.add_tags1.bits.CRAZED) + return true; + return casteFlagSet(unit->race, unit->caste, caste_raw_flags::CRAZED); +} + +static bool isOpposedToLife(df::unit *unit) +{ + if (unit->curse.rem_tags1.bits.OPPOSED_TO_LIFE) + return false; + if (unit->curse.add_tags1.bits.OPPOSED_TO_LIFE) + return true; + return casteFlagSet(unit->race, unit->caste, caste_raw_flags::CANNOT_UNDEAD); +} bool DFHack::Units::isDead(df::unit *unit) { CHECK_NULL_POINTER(unit); - return unit->flags1.bits.dead; + return unit->flags1.bits.dead || + unit->flags3.bits.ghostly; } bool DFHack::Units::isAlive(df::unit *unit) @@ -636,8 +669,11 @@ bool DFHack::Units::isSane(df::unit *unit) if (unit->flags1.bits.dead || unit->flags3.bits.ghostly || - unit->curse.add_tags1.bits.OPPOSED_TO_LIFE || - unit->curse.add_tags1.bits.CRAZED) + isOpposedToLife(unit) || + unit->unknown8.unk2) + return false; + + if (unit->unknown8.normal_race == unit->unknown8.were_race && isCrazed(unit)) return false; switch (unit->mood) @@ -657,19 +693,38 @@ bool DFHack::Units::isCitizen(df::unit *unit) { CHECK_NULL_POINTER(unit); + // Copied from the conditions used to decide game over, + // except that the game appears to let melancholy/raving + // dwarves count as citizens. + + if (!isDwarf(unit) || !isSane(unit)) + return false; + + if (unit->flags1.bits.marauder || + unit->flags1.bits.invader_origin || + unit->flags1.bits.active_invader || + unit->flags1.bits.forest || + unit->flags1.bits.merchant || + unit->flags1.bits.diplomat) + return false; + + if (unit->flags1.bits.tame) + return true; + return unit->civ_id == ui->civ_id && - !unit->flags1.bits.merchant && - !unit->flags1.bits.diplomat && + unit->civ_id != -1 && + !unit->flags2.bits.underworld && !unit->flags2.bits.resident && - !unit->flags1.bits.dead && - !unit->flags3.bits.ghostly; + !unit->flags2.bits.visitor_uninvited && + !unit->flags2.bits.visitor; } bool DFHack::Units::isDwarf(df::unit *unit) { CHECK_NULL_POINTER(unit); - return unit->race == ui->race_id; + return unit->race == ui->race_id || + unit->unknown8.normal_race == ui->race_id; } double DFHack::Units::getAge(df::unit *unit, bool true_age) diff --git a/library/xml b/library/xml index 234d0f57..d991d47b 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 234d0f57a927f306f2052fc2f45d38b3201ddee6 +Subproject commit d991d47b0f6709205c4e333bb86edb3dcf656429 -- cgit v1.2.1 From e72bf1ac9aa4d9c56f8435c5b86f538c06d651b9 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Sat, 26 May 2012 14:49:27 +0400 Subject: Sync to changes in df-structures. --- library/modules/Materials.cpp | 4 ++-- library/xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'library') diff --git a/library/modules/Materials.cpp b/library/modules/Materials.cpp index f49dd82e..f8f99f81 100644 --- a/library/modules/Materials.cpp +++ b/library/modules/Materials.cpp @@ -761,8 +761,8 @@ bool Materials::ReadCreatureTypesEx (void) { df::body_part_raw *bp = ca->body_info.body_parts[k]; t_bodypart part; - part.id = bp->part_code; - part.category = bp->part_name; + part.id = bp->token; + part.category = bp->category; caste.bodypart.push_back(part); } using namespace df::enums::mental_attribute_type; diff --git a/library/xml b/library/xml index d991d47b..7d5c349a 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit d991d47b0f6709205c4e333bb86edb3dcf656429 +Subproject commit 7d5c349a40dc1f211de2d37aeece4a3d9d631ed2 -- cgit v1.2.1 From f71a843c6e00705bb2031643e1d93e6fd7442063 Mon Sep 17 00:00:00 2001 From: Quietust Date: Mon, 28 May 2012 11:06:23 -0500 Subject: Don't throw a fatal exception just because os-type isn't something we recognize - ignore it and move on --- library/VersionInfoFactory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'library') diff --git a/library/VersionInfoFactory.cpp b/library/VersionInfoFactory.cpp index 36dbd9aa..972ab31b 100644 --- a/library/VersionInfoFactory.cpp +++ b/library/VersionInfoFactory.cpp @@ -107,7 +107,7 @@ void VersionInfoFactory::ParseVersion (TiXmlElement* entry, VersionInfo* mem) } else { - throw Error::SymbolsXmlBadAttribute("os-type"); + return; // ignore it if it's invalid } // process additional entries -- cgit v1.2.1 From 470c9f60aa2303faea68c68e946cc02de1a20c04 Mon Sep 17 00:00:00 2001 From: jj Date: Thu, 31 May 2012 13:23:00 +0200 Subject: remoteclient: dont use gcc deprecated auto_ptr --- library/RemoteClient.cpp | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'library') diff --git a/library/RemoteClient.cpp b/library/RemoteClient.cpp index a1ac2ec9..4d30988c 100644 --- a/library/RemoteClient.cpp +++ b/library/RemoteClient.cpp @@ -329,17 +329,19 @@ bool sendRemoteMessage(CSimpleSocket *socket, int16_t id, const MessageLite *msg int size = size_ready ? msg->GetCachedSize() : msg->ByteSize(); int fullsz = size + sizeof(RPCMessageHeader); - std::auto_ptr data(new uint8_t[fullsz]); - RPCMessageHeader *hdr = (RPCMessageHeader*)data.get(); + uint8_t *data = new uint8_t[fullsz]; + RPCMessageHeader *hdr = (RPCMessageHeader*)data; hdr->id = id; hdr->size = size; - uint8_t *pstart = data.get() + sizeof(RPCMessageHeader); + uint8_t *pstart = data + sizeof(RPCMessageHeader); uint8_t *pend = msg->SerializeWithCachedSizesToArray(pstart); assert((pend - pstart) == size); - return (socket->Send(data.get(), fullsz) == fullsz); + int got = socket->Send(data, fullsz); + delete[] data; + return (got == fullsz); } command_result RemoteFunctionBase::execute(color_ostream &out, @@ -402,9 +404,9 @@ command_result RemoteFunctionBase::execute(color_ostream &out, return CR_LINK_FAILURE; } - std::auto_ptr buf(new uint8_t[header.size]); + uint8_t *buf = new uint8_t[header.size]; - if (!readFullBuffer(p_client->socket, buf.get(), header.size)) + if (!readFullBuffer(p_client->socket, buf, header.size)) { out.printerr("In call to %s::%s: I/O error in receive %d bytes of data.\n", this->proto.c_str(), this->name.c_str(), header.size); @@ -413,18 +415,20 @@ command_result RemoteFunctionBase::execute(color_ostream &out, switch (header.id) { case RPC_REPLY_RESULT: - if (!output->ParseFromArray(buf.get(), header.size)) + if (!output->ParseFromArray(buf, header.size)) { out.printerr("In call to %s::%s: error parsing received result.\n", this->proto.c_str(), this->name.c_str()); + delete[] buf; return CR_LINK_FAILURE; } + delete[] buf; return CR_OK; case RPC_REPLY_TEXT: text_data.Clear(); - if (text_data.ParseFromArray(buf.get(), header.size)) + if (text_data.ParseFromArray(buf, header.size)) text_decoder.decode(&text_data); else out.printerr("In call to %s::%s: received invalid text data.\n", @@ -434,5 +438,6 @@ command_result RemoteFunctionBase::execute(color_ostream &out, default: break; } + delete[] buf; } } -- cgit v1.2.1 From b612532348ab18992d99f6abd507940cab877727 Mon Sep 17 00:00:00 2001 From: jj Date: Sat, 2 Jun 2012 23:35:05 +0200 Subject: export openplugin/lookupplugin from plugin manager --- library/include/PluginManager.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'library') diff --git a/library/include/PluginManager.h b/library/include/PluginManager.h index 31633dfe..b76df437 100644 --- a/library/include/PluginManager.h +++ b/library/include/PluginManager.h @@ -61,11 +61,11 @@ namespace DFHack struct DFLibrary; // Open a plugin library - DFLibrary * OpenPlugin (const char * filename); + DFHACK_EXPORT DFLibrary * OpenPlugin (const char * filename); // find a symbol inside plugin - void * LookupPlugin (DFLibrary * plugin ,const char * function); + DFHACK_EXPORT void * LookupPlugin (DFLibrary * plugin ,const char * function); // Close a plugin library - void ClosePlugin (DFLibrary * plugin); + DFHACK_EXPORT void ClosePlugin (DFLibrary * plugin); struct DFHACK_EXPORT CommandReg { const char *name; -- cgit v1.2.1 From b7edbf2076e20ef5a05979e687a5cdf93ddf203e Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Tue, 5 Jun 2012 14:00:52 +0400 Subject: Support 7-argument vmethods. --- library/include/DataFuncs.h | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'library') diff --git a/library/include/DataFuncs.h b/library/include/DataFuncs.h index aff04128..637a532f 100644 --- a/library/include/DataFuncs.h +++ b/library/include/DataFuncs.h @@ -160,6 +160,17 @@ INSTANTIATE_WRAPPERS(6, (OSTREAM_ARG,A1,A2,A3,A4,A5,A6), (out,vA1,vA2,vA3,vA4,vA #define FW_TARGS class A1, class A2, class A3, class A4, class A5, class A6, class A7 INSTANTIATE_RETURN_TYPE((A1,A2,A3,A4,A5,A6,A7)) +INSTANTIATE_WRAPPERS(7, (A1,A2,A3,A4,A5,A6,A7), (vA1,vA2,vA3,vA4,vA5,vA6,vA7), + LOAD_ARG(A1); LOAD_ARG(A2); LOAD_ARG(A3); + LOAD_ARG(A4); LOAD_ARG(A5); LOAD_ARG(A6); + LOAD_ARG(A7);) +INSTANTIATE_WRAPPERS(7, (OSTREAM_ARG,A1,A2,A3,A4,A5,A6,A7), (out,vA1,vA2,vA3,vA4,vA5,vA6,vA7), + LOAD_OSTREAM(out); LOAD_ARG(A1); LOAD_ARG(A2); LOAD_ARG(A3); + LOAD_ARG(A4); LOAD_ARG(A5); LOAD_ARG(A6); LOAD_ARG(A7);) +#undef FW_TARGS + +#define FW_TARGS class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8 +INSTANTIATE_RETURN_TYPE((A1,A2,A3,A4,A5,A6,A7,A8)) #undef FW_TARGS #undef FW_TARGSC -- cgit v1.2.1 From d35d8d3431f1c02f70c281558fa211d3bd7642ca Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Tue, 5 Jun 2012 14:06:29 +0400 Subject: Add the script to fix lagging fat dwarves. --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'library') diff --git a/library/xml b/library/xml index 7d5c349a..8c079448 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 7d5c349a40dc1f211de2d37aeece4a3d9d631ed2 +Subproject commit 8c07944891f09391cc02098074ffc8080b43b184 -- cgit v1.2.1 From 7aff2d6bc06c0fd8e14df08c070517bd53374dbf Mon Sep 17 00:00:00 2001 From: Kelly Martin Date: Tue, 5 Jun 2012 14:33:06 -0500 Subject: Sync structures for .34.11 --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'library') diff --git a/library/xml b/library/xml index 8c079448..fc618cce 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 8c07944891f09391cc02098074ffc8080b43b184 +Subproject commit fc618cce63f0037442ec8d650a11cbe823f0443a -- cgit v1.2.1 From 9dbcaa2733878bf089ac12514ed22d9b8ebe27a9 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Wed, 6 Jun 2012 18:54:06 +0400 Subject: Support adventure mode and stockpile screens in focus strings. --- library/modules/Gui.cpp | 45 ++++++++++++++++++++++++++++++++++++++++++++- library/xml | 2 +- 2 files changed, 45 insertions(+), 2 deletions(-) (limited to 'library') diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index 111ea94c..63ba811c 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -58,12 +58,14 @@ using namespace DFHack; #include "df/viewscreen_layer_overall_healthst.h" #include "df/viewscreen_layer_assigntradest.h" #include "df/viewscreen_layer_militaryst.h" +#include "df/viewscreen_layer_stockpilest.h" #include "df/viewscreen_petst.h" #include "df/viewscreen_tradegoodsst.h" #include "df/viewscreen_storesst.h" #include "df/ui_unit_view_mode.h" #include "df/ui_sidebar_menus.h" #include "df/ui_look_list.h" +#include "df/ui_advmode.h" #include "df/job.h" #include "df/ui_build_selector.h" #include "df/building_workshopst.h" @@ -273,7 +275,9 @@ DEFINE_GET_FOCUS_STRING_HANDLER(dwarfmode) break; case Burrows: - if (ui->burrows.in_add_units_mode) + if (ui->burrows.in_confirm_delete) + focus += "/ConfirmDelete"; + else if (ui->burrows.in_add_units_mode) focus += "/AddUnits"; else if (ui->burrows.in_edit_name_mode) focus += "/EditName"; @@ -288,6 +292,16 @@ DEFINE_GET_FOCUS_STRING_HANDLER(dwarfmode) } } +DEFINE_GET_FOCUS_STRING_HANDLER(dungeonmode) +{ + using df::global::ui_advmode; + + if (!ui_advmode) + return; + + focus += "/" + enum_item_key(ui_advmode->menu); +} + DEFINE_GET_FOCUS_STRING_HANDLER(unitlist) { focus += "/" + enum_item_key(screen->page); @@ -407,6 +421,35 @@ DEFINE_GET_FOCUS_STRING_HANDLER(stores) focus += "/Items"; } +DEFINE_GET_FOCUS_STRING_HANDLER(layer_stockpile) +{ + auto list1 = getLayerList(screen, 0); + auto list2 = getLayerList(screen, 1); + auto list3 = getLayerList(screen, 2); + if (!list1 || !list2 || !list3 || !screen->settings) return; + + auto group = screen->cur_group; + if (group != vector_get(screen->group_ids, list1->cursor)) + return; + + focus += "/" + enum_item_key(group); + + auto bits = vector_get(screen->group_bits, list1->cursor); + if (bits.whole && !(bits.whole & screen->settings->flags.whole)) + { + focus += "/Off"; + return; + } + + focus += "/On"; + + if (list2->bright || list3->bright || screen->list_ids.empty()) { + focus += "/" + enum_item_key(screen->cur_list); + + if (list3->bright) + focus += (screen->item_names.empty() ? "/None" : "/Item"); + } +} std::string Gui::getFocusString(df::viewscreen *top) { diff --git a/library/xml b/library/xml index fc618cce..0a0dc568 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit fc618cce63f0037442ec8d650a11cbe823f0443a +Subproject commit 0a0dc568dff80396efd1b2c9a6ef1614df5786f7 -- cgit v1.2.1 From c97e3bca0ccd84f9a0dc1d481c6a6521566c1aa3 Mon Sep 17 00:00:00 2001 From: Kelly Martin Date: Thu, 7 Jun 2012 21:22:19 -0500 Subject: Sync structures again --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'library') diff --git a/library/xml b/library/xml index 0a0dc568..ff87e784 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 0a0dc568dff80396efd1b2c9a6ef1614df5786f7 +Subproject commit ff87e784a8e274fcc3d1f57e57746735eb7285c2 -- cgit v1.2.1 From c364b4204997af81b6b419fa245ed22c1c56f389 Mon Sep 17 00:00:00 2001 From: jj Date: Wed, 13 Jun 2012 00:21:23 +0200 Subject: fix minor gcc warning --- library/Console-linux.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'library') diff --git a/library/Console-linux.cpp b/library/Console-linux.cpp index 3c0ad893..24d13f42 100644 --- a/library/Console-linux.cpp +++ b/library/Console-linux.cpp @@ -255,7 +255,7 @@ namespace DFHack void color(Console::color_value index) { if(!rawmode) - fprintf(dfout_C,getANSIColor(index)); + fprintf(dfout_C, "%s", getANSIColor(index)); else { const char * colstr = getANSIColor(index); @@ -761,4 +761,4 @@ void Console::msleep (unsigned int msec) { if (msec > 1000) sleep(msec/1000000); usleep((msec % 1000000) * 1000); -} \ No newline at end of file +} -- cgit v1.2.1 From 8d7cf092fd6f3f1cf68e6b48b8f3dc42ef40dcfa Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Wed, 13 Jun 2012 21:12:36 +0400 Subject: Add Lua API for access to some contextual and low-level info. --- library/LuaApi.cpp | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++ library/LuaTools.cpp | 6 +-- 2 files changed, 118 insertions(+), 3 deletions(-) (limited to 'library') diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 8e8a3c4e..aa168db3 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 f794f6b4..752c341b 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()); -- cgit v1.2.1 From c50b605dfc2024bf5bca7d6dfb18fc266b358978 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Wed, 13 Jun 2012 22:26:54 +0400 Subject: Support casting references and allocating arrays of numbers in lua wrapper. --- library/LuaWrapper.cpp | 89 +++++++++++++++++++++++++++++++++++++++++--- library/include/LuaWrapper.h | 1 + 2 files changed, 85 insertions(+), 5 deletions(-) (limited to 'library') diff --git a/library/LuaWrapper.cpp b/library/LuaWrapper.cpp index 471dba64..7c15a27a 100644 --- a/library/LuaWrapper.cpp +++ b/library/LuaWrapper.cpp @@ -447,10 +447,21 @@ Lua::ObjectClass Lua::IsDFObject(lua_State *state, int val_index) } static const char *const primitive_types[] = { - "string", NULL + "string", + "int8_t", "uint8_t", "int16_t", "uint16_t", + "int32_t", "uint32_t", "int64_t", "uint64_t", + "bool", "float", "double", + NULL }; static type_identity *const primitive_identities[] = { - df::identity_traits::get(), NULL + df::identity_traits::get(), + df::identity_traits::get(), df::identity_traits::get(), + df::identity_traits::get(), df::identity_traits::get(), + df::identity_traits::get(), df::identity_traits::get(), + df::identity_traits::get(), df::identity_traits::get(), + df::identity_traits::get(), + df::identity_traits::get(), df::identity_traits::get(), + NULL }; /** @@ -644,12 +655,32 @@ static int meta_new(lua_State *state) { int argc = lua_gettop(state); - if (argc != 1) - luaL_error(state, "Usage: object:new() or df.new(object)"); + if (argc != 1 && argc != 2) + luaL_error(state, "Usage: object:new() or df.new(object) or df.new(ptype,count)"); type_identity *id = get_object_identity(state, 1, "df.new()", true); - void *ptr = id->allocate(); + void *ptr; + + // Support arrays of primitive types + if (argc == 2) + { + int cnt = luaL_checkint(state, 2); + if (cnt <= 0) + luaL_error(state, "Invalid array size in df.new()"); + if (id->type() != IDTYPE_PRIMITIVE) + luaL_error(state, "Cannot allocate arrays of non-primitive types."); + + size_t sz = id->byte_size() * cnt; + ptr = malloc(sz); + if (ptr) + memset(ptr, 0, sz); + } + else + { + ptr = id->allocate(); + } + if (!ptr) luaL_error(state, "Cannot allocate %s", id->getFullName().c_str()); @@ -666,6 +697,48 @@ static int meta_new(lua_State *state) return 1; } +/** + * Method: type casting of pointers. + */ +static int meta_reinterpret_cast(lua_State *state) +{ + int argc = lua_gettop(state); + + if (argc != 2) + luaL_error(state, "Usage: df.reinterpret_cast(type,ptr)"); + + type_identity *id = get_object_identity(state, 1, "df.reinterpret_cast()", true); + + // Find the raw pointer value + void *ptr; + + if (lua_isnil(state, 2)) + ptr = NULL; + else if (lua_isnumber(state, 2)) + ptr = (void*)lua_tointeger(state, 2); + else + { + ptr = get_object_internal(state, NULL, 2, false, true); + if (!ptr) + luaL_error(state, "Invalid pointer argument in df.reinterpret_cast.\n"); + } + + // Convert it to the appropriate representation + if (ptr == NULL) + { + lua_pushnil(state); + } + else if (lua_isuserdata(state, 1)) + { + lua_getmetatable(state, 1); + push_object_ref(state, ptr); + } + else + push_object_internal(state, id, ptr); + + return 1; +} + static void invoke_resize(lua_State *state, int table, lua_Integer size) { lua_getfield(state, table, "resize"); @@ -1432,6 +1505,10 @@ static int DoAttach(lua_State *state) lua_pushcclosure(state, meta_new, 1); lua_setfield(state, LUA_REGISTRYINDEX, DFHACK_NEW_NAME); + lua_rawgetp(state, LUA_REGISTRYINDEX, &DFHACK_TYPETABLE_TOKEN); + lua_pushcclosure(state, meta_reinterpret_cast, 1); + lua_setfield(state, LUA_REGISTRYINDEX, DFHACK_CAST_NAME); + lua_rawgetp(state, LUA_REGISTRYINDEX, &DFHACK_TYPETABLE_TOKEN); lua_pushcclosure(state, meta_assign, 1); lua_setfield(state, LUA_REGISTRYINDEX, DFHACK_ASSIGN_NAME); @@ -1463,6 +1540,8 @@ static int DoAttach(lua_State *state) lua_setfield(state, -2, "assign"); lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_IS_INSTANCE_NAME); lua_setfield(state, -2, "is_instance"); + lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_CAST_NAME); + lua_setfield(state, -2, "reinterpret_cast"); lua_pushlightuserdata(state, NULL); lua_setfield(state, -2, "NULL"); diff --git a/library/include/LuaWrapper.h b/library/include/LuaWrapper.h index 97b2e698..9e449022 100644 --- a/library/include/LuaWrapper.h +++ b/library/include/LuaWrapper.h @@ -77,6 +77,7 @@ namespace DFHack { namespace LuaWrapper { #define DFHACK_ASSIGN_NAME "DFHack::Assign" #define DFHACK_IS_INSTANCE_NAME "DFHack::IsInstance" #define DFHACK_DELETE_NAME "DFHack::Delete" +#define DFHACK_CAST_NAME "DFHack::Cast" extern LuaToken DFHACK_EMPTY_TABLE_TOKEN; -- cgit v1.2.1 From 149f1759096f1fa4117c0e7ac1e6172b669a801b Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Wed, 13 Jun 2012 22:40:39 +0400 Subject: Make primitive refs (i.e. pointers to numbers, etc) behave as arrays. --- library/LuaTypes.cpp | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) (limited to 'library') diff --git a/library/LuaTypes.cpp b/library/LuaTypes.cpp index c58c25d1..8548c5d0 100644 --- a/library/LuaTypes.cpp +++ b/library/LuaTypes.cpp @@ -635,6 +635,28 @@ static int meta_struct_next(lua_State *state) return 2; } +/** + * Field lookup for primitive refs: behave as a quasi-array with numeric indices. + */ +static type_identity *find_primitive_field(lua_State *state, int field, const char *mode, uint8_t **ptr) +{ + if (lua_type(state, field) == LUA_TNUMBER) + { + int idx = lua_tointeger(state, field); + if (idx < 0) + field_error(state, 2, "negative index", mode); + + lua_rawgetp(state, UPVAL_METATABLE, &DFHACK_IDENTITY_FIELD_TOKEN); + auto id = (type_identity *)lua_touserdata(state, -1); + lua_pop(state, 1); + + *ptr += int(id->byte_size()) * idx; + return id; + } + + return (type_identity*)find_field(state, field, mode); +} + /** * Metamethod: __index for primitives, i.e. simple object references. * Fields point to identity, or NULL for metafields. @@ -642,7 +664,7 @@ static int meta_struct_next(lua_State *state) 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"); + auto type = find_primitive_field(state, 2, "read", &ptr); if (!type) return 1; type->lua_read(state, 2, ptr); @@ -655,7 +677,7 @@ static int meta_primitive_index(lua_State *state) 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"); + auto type = find_primitive_field(state, 2, "write", &ptr); if (!type) field_error(state, 2, "builtin property or method", "write"); type->lua_write(state, 2, ptr, 3); -- cgit v1.2.1 From eaac32c7652be14dc45366b9d74101ae6a38fb17 Mon Sep 17 00:00:00 2001 From: Petr Mrázek Date: Thu, 14 Jun 2012 00:29:01 +0200 Subject: Version bump and text updates. --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'library') diff --git a/library/xml b/library/xml index f0e93193..c3818846 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit f0e931933dd553ad1e9b2a9acde2cca59791ed9e +Subproject commit c381884664c71adefbec44258a734def2c88dacc -- cgit v1.2.1 From 316973c463acaab570f2afb6f792f9806e7779a3 Mon Sep 17 00:00:00 2001 From: Petr Mrázek Date: Thu, 14 Jun 2012 02:15:43 +0200 Subject: Re-add fake SDL headers, get rid of real SDL use. --- library/Core.cpp | 71 ++++----- library/include/Core.h | 8 +- library/include/Hooks.h | 6 +- library/include/SDL_events.h | 210 ++++++++++++++++++++++++++ library/include/SDL_keyboard.h | 61 ++++++++ library/include/SDL_keysym.h | 329 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 643 insertions(+), 42 deletions(-) create mode 100644 library/include/SDL_events.h create mode 100644 library/include/SDL_keyboard.h create mode 100644 library/include/SDL_keysym.h (limited to 'library') diff --git a/library/Core.cpp b/library/Core.cpp index 94d408b8..165f5e5e 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -68,6 +68,8 @@ using namespace DFHack; #include #include "tinythread.h" +#include "SDL_events.h" + using namespace tthread; using namespace df::enums; using df::global::init; @@ -1218,29 +1220,31 @@ bool Core::ncurses_wgetch(int in, int & out) return true; } -int Core::UnicodeAwareSym(const SDL_KeyboardEvent& ke) +int UnicodeAwareSym(const SDL::Event& event) { + auto ke = (const SDL::KeyboardEvent &) event; // Assume keyboard layouts don't change the order of numbers: - if( '0' <= ke.keysym.sym && ke.keysym.sym <= '9') return ke.keysym.sym; - if(SDLK_F1 <= ke.keysym.sym && ke.keysym.sym <= SDLK_F12) return ke.keysym.sym; + if( '0' <= ke.ksym.sym && ke.ksym.sym <= '9') return ke.ksym.sym; + if(SDL::K_F1 <= ke.ksym.sym && ke.ksym.sym <= SDL::K_F12) return ke.ksym.sym; // These keys are mapped to the same control codes as Ctrl-? - switch (ke.keysym.sym) { - case SDLK_RETURN: - case SDLK_KP_ENTER: - case SDLK_TAB: - case SDLK_ESCAPE: - case SDLK_DELETE: - return ke.keysym.sym; - default: - break; + switch (ke.ksym.sym) + { + case SDL::K_RETURN: + case SDL::K_KP_ENTER: + case SDL::K_TAB: + case SDL::K_ESCAPE: + case SDL::K_DELETE: + return ke.ksym.sym; + default: + break; } - int unicode = ke.keysym.unicode; + int unicode = ke.ksym.unicode; // convert Ctrl characters to their 0x40-0x5F counterparts: if (unicode < ' ') - { + { unicode += 'A' - 1; } @@ -1248,7 +1252,7 @@ int Core::UnicodeAwareSym(const SDL_KeyboardEvent& ke) if('A' < unicode && unicode < 'Z') { unicode += 'a' - 'A'; - } + } // convert various other punctuation marks: if('\"' == unicode) unicode = '\''; @@ -1265,29 +1269,30 @@ int Core::UnicodeAwareSym(const SDL_KeyboardEvent& ke) return unicode; } + //MEMO: return false if event is consumed -int Core::DFH_SDL_Event(SDL_Event* ev) +int Core::DFH_SDL_Event(SDL::Event* ev) { // do NOT process events before we are ready. if(!started) return true; if(!ev) return true; - if(ev && (ev->type == SDL_KEYDOWN || ev->type == SDL_KEYUP)) + if(ev && (ev->type == SDL::ET_KEYDOWN || ev->type == SDL::ET_KEYUP)) { - SDL_KeyboardEvent * ke = (SDL_KeyboardEvent *)ev; + auto ke = (SDL::KeyboardEvent *)ev; - if(ke->state == SDL_PRESSED && !hotkey_states[ke->keysym.sym]) + if(ke->state == SDL::BTN_PRESSED && !hotkey_states[ke->ksym.sym]) { - hotkey_states[ke->keysym.sym] = true; + hotkey_states[ke->ksym.sym] = true; int mod = 0; - if (ke->keysym.mod & KMOD_SHIFT) mod |= 1; - if (ke->keysym.mod & KMOD_CTRL) mod |= 2; - if (ke->keysym.mod & KMOD_ALT) mod |= 4; + if (ke->ksym.mod & SDL::KMOD_SHIFT) mod |= 1; + if (ke->ksym.mod & SDL::KMOD_CTRL) mod |= 2; + if (ke->ksym.mod & SDL::KMOD_ALT) mod |= 4; // Use unicode so Windows gives the correct value for the // user's Input Language - if((ke->keysym.unicode & 0xff80) == 0) + if((ke->ksym.unicode & 0xff80) == 0) { int key = UnicodeAwareSym(*ke); SelectHotkey(key, mod); @@ -1295,12 +1300,12 @@ int Core::DFH_SDL_Event(SDL_Event* ev) else { // Pretend non-ascii characters don't happen: - SelectHotkey(ke->keysym.sym, mod); + SelectHotkey(ke->ksym.sym, mod); } } - else if(ke->state == SDL_RELEASED) + else if(ke->state == SDL::BTN_RELEASED) { - hotkey_states[ke->keysym.sym] = false; + hotkey_states[ke->ksym.sym] = false; } } return true; @@ -1317,8 +1322,8 @@ bool Core::SelectHotkey(int sym, int modifiers) while (screen->child) screen = screen->child; - if (sym == SDLK_KP_ENTER) - sym = SDLK_RETURN; + if (sym == SDL::K_KP_ENTER) + sym = SDL::K_RETURN; std::string cmd; @@ -1341,7 +1346,7 @@ bool Core::SelectHotkey(int sym, int modifiers) if (cmd.empty()) { // Check the hotkey keybindings - int idx = sym - SDLK_F1; + int idx = sym - SDL::K_F1; if(idx >= 0 && idx < 8) { if (modifiers & 1) @@ -1396,13 +1401,13 @@ static bool parseKeySpec(std::string keyspec, int *psym, int *pmod, std::string } if (keyspec.size() == 1 && keyspec[0] >= 'A' && keyspec[0] <= 'Z') { - *psym = SDLK_a + (keyspec[0]-'A'); + *psym = SDL::K_a + (keyspec[0]-'A'); return true; } else if (keyspec.size() == 2 && keyspec[0] == 'F' && keyspec[1] >= '1' && keyspec[1] <= '9') { - *psym = SDLK_F1 + (keyspec[1]-'1'); + *psym = SDL::K_F1 + (keyspec[1]-'1'); return true; } else if (keyspec == "Enter") { - *psym = SDLK_RETURN; + *psym = SDL::K_RETURN; return true; } else return false; diff --git a/library/include/Core.h b/library/include/Core.h index 2810ff14..e4d1080d 100644 --- a/library/include/Core.h +++ b/library/include/Core.h @@ -33,7 +33,6 @@ distribution. #include #include "Console.h" #include "modules/Graphic.h" -#include "SDL_events.h" #include "RemoteClient.h" @@ -86,14 +85,14 @@ namespace DFHack { friend int ::SDL_NumJoysticks(void); friend void ::SDL_Quit(void); - friend int ::SDL_PollEvent(SDL_Event *); + friend int ::SDL_PollEvent(SDL::Event *); friend int ::SDL_Init(uint32_t flags); friend int ::wgetch(WINDOW * w); friend int ::egg_init(void); friend int ::egg_shutdown(void); friend int ::egg_tick(void); friend int ::egg_prerender(void); - friend int ::egg_sdl_event(SDL_Event* event); + friend int ::egg_sdl_event(SDL::Event* event); friend int ::egg_curses_event(int orig_return); public: /// Get the single Core instance or make one. @@ -170,7 +169,7 @@ namespace DFHack int Update (void); int TileUpdate (void); int Shutdown (void); - int DFH_SDL_Event(SDL_Event* event); + int DFH_SDL_Event(SDL::Event* event); bool ncurses_wgetch(int in, int & out); void onUpdate(color_ostream &out); @@ -215,7 +214,6 @@ namespace DFHack tthread::mutex * HotkeyMutex; tthread::condition_variable * HotkeyCond; - int UnicodeAwareSym(const SDL_KeyboardEvent& ke); bool SelectHotkey(int key, int modifiers); // for state change tracking diff --git a/library/include/Hooks.h b/library/include/Hooks.h index 83a39ea1..418a5ce3 100644 --- a/library/include/Hooks.h +++ b/library/include/Hooks.h @@ -33,8 +33,6 @@ distribution. #include #include -#include "SDL.h" - // function and variable pointer... we don't try to understand what SDL does here typedef void * fPtr; typedef void * vPtr; @@ -48,7 +46,7 @@ namespace SDL // be declared as friend functions/known DFhackCExport int SDL_NumJoysticks(void); DFhackCExport void SDL_Quit(void); -DFhackCExport int SDL_PollEvent(SDL_Event* event); +DFhackCExport int SDL_PollEvent(SDL::Event* event); DFhackCExport int SDL_Init(uint32_t flags); DFhackCExport int wgetch(WINDOW * win); @@ -65,7 +63,7 @@ DFhackCExport int egg_tick(void); DFhackCExport int egg_prerender(void); // hook - called for each SDL event, can filter both the event and the return value -DFhackCExport int egg_sdl_event(SDL_Event* event); +DFhackCExport int egg_sdl_event(SDL::Event* event); // hook - ncurses event. return -1 to consume DFhackCExport int egg_curses_event(int orig_return); diff --git a/library/include/SDL_events.h b/library/include/SDL_events.h new file mode 100644 index 00000000..0457dbca --- /dev/null +++ b/library/include/SDL_events.h @@ -0,0 +1,210 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2009 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ + +// Fake - only structs. Shamelessly pilfered from the SDL library. +// Needed for processing its event types without polluting our namespaces with C garbage + +#pragma once +#include "SDL_keyboard.h" + +namespace SDL +{ + enum ButtonState + { + BTN_RELEASED = 0, + BTN_PRESSED = 1 + }; + + /** Event enumerations */ + enum EventType + { + ET_NOEVENT = 0, /**< Unused (do not remove) */ + ET_ACTIVEEVENT, /**< Application loses/gains visibility */ + ET_KEYDOWN, /**< Keys pressed */ + ET_KEYUP, /**< Keys released */ + ET_MOUSEMOTION, /**< Mouse moved */ + ET_MOUSEBUTTONDOWN, /**< Mouse button pressed */ + ET_MOUSEBUTTONUP, /**< Mouse button released */ + ET_JOYAXISMOTION, /**< Joystick axis motion */ + ET_JOYBALLMOTION, /**< Joystick trackball motion */ + ET_JOYHATMOTION, /**< Joystick hat position change */ + ET_JOYBUTTONDOWN, /**< Joystick button pressed */ + ET_JOYBUTTONUP, /**< Joystick button released */ + ET_QUIT, /**< User-requested quit */ + ET_SYSWMEVENT, /**< System specific event */ + ET_EVENT_RESERVEDA, /**< Reserved for future use.. */ + ET_EVENT_RESERVEDB, /**< Reserved for future use.. */ + ET_VIDEORESIZE, /**< User resized video mode */ + ET_VIDEOEXPOSE, /**< Screen needs to be redrawn */ + ET_EVENT_RESERVED2, /**< Reserved for future use.. */ + ET_EVENT_RESERVED3, /**< Reserved for future use.. */ + ET_EVENT_RESERVED4, /**< Reserved for future use.. */ + ET_EVENT_RESERVED5, /**< Reserved for future use.. */ + ET_EVENT_RESERVED6, /**< Reserved for future use.. */ + ET_EVENT_RESERVED7, /**< Reserved for future use.. */ + /** Events ET_USEREVENT through ET_MAXEVENTS-1 are for your use */ + ET_USEREVENT = 24, + /** This last event is only for bounding internal arrays + * It is the number of bits in the event mask datatype -- Uint32 + */ + ET_NUMEVENTS = 32 + }; + + /** Application visibility event structure */ + struct ActiveEvent + { + uint8_t type; /**< ET_ACTIVEEVENT */ + uint8_t gain; /**< Whether given states were gained or lost (1/0) */ + uint8_t state; /**< A mask of the focus states */ + }; + + /** Keyboard event structure */ + struct KeyboardEvent + { + uint8_t type; /**< ET_KEYDOWN or ET_KEYUP */ + uint8_t which; /**< The keyboard device index */ + uint8_t state; /**< BTN_PRESSED or BTN_RELEASED */ + keysym ksym; + }; + + /** Mouse motion event structure */ + struct MouseMotionEvent + { + uint8_t type; /**< ET_MOUSEMOTION */ + uint8_t which; /**< The mouse device index */ + uint8_t state; /**< The current button state */ + uint16_t x, y; /**< The X/Y coordinates of the mouse */ + int16_t xrel; /**< The relative motion in the X direction */ + int16_t yrel; /**< The relative motion in the Y direction */ + }; + + /** Mouse button event structure */ + struct MouseButtonEvent + { + uint8_t type; /**< ET_MOUSEBUTTONDOWN or ET_MOUSEBUTTONUP */ + uint8_t which; /**< The mouse device index */ + uint8_t button; /**< The mouse button index */ + uint8_t state; /**< BTN_PRESSED or BTN_RELEASED */ + uint16_t x, y; /**< The X/Y coordinates of the mouse at press time */ + }; + + /** Joystick axis motion event structure */ + struct JoyAxisEvent + { + uint8_t type; /**< ET_JOYAXISMOTION */ + uint8_t which; /**< The joystick device index */ + uint8_t axis; /**< The joystick axis index */ + int16_t value; /**< The axis value (range: -32768 to 32767) */ + }; + + /** Joystick trackball motion event structure */ + struct JoyBallEvent + { + uint8_t type; /**< ET_JOYBALLMOTION */ + uint8_t which; /**< The joystick device index */ + uint8_t ball; /**< The joystick trackball index */ + int16_t xrel; /**< The relative motion in the X direction */ + int16_t yrel; /**< The relative motion in the Y direction */ + }; + + /** Joystick hat position change event structure */ + struct JoyHatEvent + { + uint8_t type; /**< ET_JOYHATMOTION */ + uint8_t which; /**< The joystick device index */ + uint8_t hat; /**< The joystick hat index */ + uint8_t value; /**< The hat position value: + * SDL_HAT_LEFTUP SDL_HAT_UP SDL_HAT_RIGHTUP + * SDL_HAT_LEFT SDL_HAT_CENTERED SDL_HAT_RIGHT + * SDL_HAT_LEFTDOWN SDL_HAT_DOWN SDL_HAT_RIGHTDOWN + * Note that zero means the POV is centered. + */ + }; + + /** Joystick button event structure */ + struct JoyButtonEvent + { + uint8_t type; /**< ET_JOYBUTTONDOWN or ET_JOYBUTTONUP */ + uint8_t which; /**< The joystick device index */ + uint8_t button; /**< The joystick button index */ + uint8_t state; /**< BTN_PRESSED or BTN_RELEASED */ + }; + + /** The "window resized" event + * When you get this event, you are responsible for setting a new video + * mode with the new width and height. + */ + struct ResizeEvent + { + uint8_t type; /**< ET_VIDEORESIZE */ + int w; /**< New width */ + int h; /**< New height */ + }; + + /** The "screen redraw" event */ + struct ExposeEvent + { + uint8_t type; /**< ET_VIDEOEXPOSE */ + }; + + /** The "quit requested" event */ + struct QuitEvent + { + uint8_t type; /**< ET_QUIT */ + }; + + /** A user-defined event type */ + struct UserEvent + { + uint8_t type; /**< ETL_USEREVENT through ET_NUMEVENTS-1 */ + int code; /**< User defined event code */ + void *data1; /**< User defined data pointer */ + void *data2; /**< User defined data pointer */ + }; + + /** If you want to use this event, you should include SDL_syswm.h */ + struct SysWMmsg; + struct SysWMEvent + { + uint8_t type; + SysWMmsg *msg; + }; + + /** General event structure */ + union Event + { + uint8_t type; + ActiveEvent active; + KeyboardEvent key; + MouseMotionEvent motion; + MouseButtonEvent button; + JoyAxisEvent jaxis; + JoyBallEvent jball; + JoyHatEvent jhat; + JoyButtonEvent jbutton; + ResizeEvent resize; + ExposeEvent expose; + QuitEvent quit; + UserEvent user; + SysWMEvent syswm; + }; +} \ No newline at end of file diff --git a/library/include/SDL_keyboard.h b/library/include/SDL_keyboard.h new file mode 100644 index 00000000..f0d325f5 --- /dev/null +++ b/library/include/SDL_keyboard.h @@ -0,0 +1,61 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2009 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ + +// Fake - only structs. Shamelessly pilfered from the SDL library. +// Needed for processing its event types without polluting our namespaces with C garbage + +#pragma once +#include "SDL_keysym.h" +#include + +namespace SDL +{ + /** Keysym structure + * + * - The scancode is hardware dependent, and should not be used by general + * applications. If no hardware scancode is available, it will be 0. + * + * - The 'unicode' translated character is only available when character + * translation is enabled by the SDL_EnableUNICODE() API. If non-zero, + * this is a UNICODE character corresponding to the keypress. If the + * high 9 bits of the character are 0, then this maps to the equivalent + * ASCII character: + * @code + * char ch; + * if ( (keysym.unicode & 0xFF80) == 0 ) { + * ch = keysym.unicode & 0x7F; + * } else { + * An international character.. + * } + * @endcode + */ + typedef struct keysym + { + uint8_t scancode; /**< hardware specific scancode */ + Key sym; /**< SDL virtual keysym */ + Mod mod; /**< current key modifiers */ + uint16_t unicode; /**< translated character */ + } keysym; + + /** This is the mask which refers to all hotkey bindings */ + #define ALL_HOTKEYS 0xFFFFFFFF +} \ No newline at end of file diff --git a/library/include/SDL_keysym.h b/library/include/SDL_keysym.h new file mode 100644 index 00000000..4f01cfa9 --- /dev/null +++ b/library/include/SDL_keysym.h @@ -0,0 +1,329 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2009 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ + +// Fake - only structs. Shamelessly pilfered from the SDL library. +// Needed for processing its event types without polluting our namespaces with C garbage + +#pragma once + +namespace SDL +{ + /** What we really want is a mapping of every raw key on the keyboard. + * To support international keyboards, we use the range 0xA1 - 0xFF + * as international virtual keycodes. We'll follow in the footsteps of X11... + * @brief The names of the keys + */ + enum Key + { + /** @name ASCII mapped keysyms + * The keyboard syms have been cleverly chosen to map to ASCII + */ + /*@{*/ + K_UNKNOWN = 0, + K_FIRST = 0, + K_BACKSPACE = 8, + K_TAB = 9, + K_CLEAR = 12, + K_RETURN = 13, + K_PAUSE = 19, + K_ESCAPE = 27, + K_SPACE = 32, + K_EXCLAIM = 33, + K_QUOTEDBL = 34, + K_HASH = 35, + K_DOLLAR = 36, + K_AMPERSAND = 38, + K_QUOTE = 39, + K_LEFTPAREN = 40, + K_RIGHTPAREN = 41, + K_ASTERISK = 42, + K_PLUS = 43, + K_COMMA = 44, + K_MINUS = 45, + K_PERIOD = 46, + K_SLASH = 47, + K_0 = 48, + K_1 = 49, + K_2 = 50, + K_3 = 51, + K_4 = 52, + K_5 = 53, + K_6 = 54, + K_7 = 55, + K_8 = 56, + K_9 = 57, + K_COLON = 58, + K_SEMICOLON = 59, + K_LESS = 60, + K_EQUALS = 61, + K_GREATER = 62, + K_QUESTION = 63, + K_AT = 64, + /* + Skip uppercase letters + */ + K_LEFTBRACKET = 91, + K_BACKSLASH = 92, + K_RIGHTBRACKET = 93, + K_CARET = 94, + K_UNDERSCORE = 95, + K_BACKQUOTE = 96, + K_a = 97, + K_b = 98, + K_c = 99, + K_d = 100, + K_e = 101, + K_f = 102, + K_g = 103, + K_h = 104, + K_i = 105, + K_j = 106, + K_k = 107, + K_l = 108, + K_m = 109, + K_n = 110, + K_o = 111, + K_p = 112, + K_q = 113, + K_r = 114, + K_s = 115, + K_t = 116, + K_u = 117, + K_v = 118, + K_w = 119, + K_x = 120, + K_y = 121, + K_z = 122, + K_DELETE = 127, + /* End of ASCII mapped keysyms */ + /*@}*/ + + /** @name International keyboard syms */ + /*@{*/ + K_WORLD_0 = 160, /* 0xA0 */ + K_WORLD_1 = 161, + K_WORLD_2 = 162, + K_WORLD_3 = 163, + K_WORLD_4 = 164, + K_WORLD_5 = 165, + K_WORLD_6 = 166, + K_WORLD_7 = 167, + K_WORLD_8 = 168, + K_WORLD_9 = 169, + K_WORLD_10 = 170, + K_WORLD_11 = 171, + K_WORLD_12 = 172, + K_WORLD_13 = 173, + K_WORLD_14 = 174, + K_WORLD_15 = 175, + K_WORLD_16 = 176, + K_WORLD_17 = 177, + K_WORLD_18 = 178, + K_WORLD_19 = 179, + K_WORLD_20 = 180, + K_WORLD_21 = 181, + K_WORLD_22 = 182, + K_WORLD_23 = 183, + K_WORLD_24 = 184, + K_WORLD_25 = 185, + K_WORLD_26 = 186, + K_WORLD_27 = 187, + K_WORLD_28 = 188, + K_WORLD_29 = 189, + K_WORLD_30 = 190, + K_WORLD_31 = 191, + K_WORLD_32 = 192, + K_WORLD_33 = 193, + K_WORLD_34 = 194, + K_WORLD_35 = 195, + K_WORLD_36 = 196, + K_WORLD_37 = 197, + K_WORLD_38 = 198, + K_WORLD_39 = 199, + K_WORLD_40 = 200, + K_WORLD_41 = 201, + K_WORLD_42 = 202, + K_WORLD_43 = 203, + K_WORLD_44 = 204, + K_WORLD_45 = 205, + K_WORLD_46 = 206, + K_WORLD_47 = 207, + K_WORLD_48 = 208, + K_WORLD_49 = 209, + K_WORLD_50 = 210, + K_WORLD_51 = 211, + K_WORLD_52 = 212, + K_WORLD_53 = 213, + K_WORLD_54 = 214, + K_WORLD_55 = 215, + K_WORLD_56 = 216, + K_WORLD_57 = 217, + K_WORLD_58 = 218, + K_WORLD_59 = 219, + K_WORLD_60 = 220, + K_WORLD_61 = 221, + K_WORLD_62 = 222, + K_WORLD_63 = 223, + K_WORLD_64 = 224, + K_WORLD_65 = 225, + K_WORLD_66 = 226, + K_WORLD_67 = 227, + K_WORLD_68 = 228, + K_WORLD_69 = 229, + K_WORLD_70 = 230, + K_WORLD_71 = 231, + K_WORLD_72 = 232, + K_WORLD_73 = 233, + K_WORLD_74 = 234, + K_WORLD_75 = 235, + K_WORLD_76 = 236, + K_WORLD_77 = 237, + K_WORLD_78 = 238, + K_WORLD_79 = 239, + K_WORLD_80 = 240, + K_WORLD_81 = 241, + K_WORLD_82 = 242, + K_WORLD_83 = 243, + K_WORLD_84 = 244, + K_WORLD_85 = 245, + K_WORLD_86 = 246, + K_WORLD_87 = 247, + K_WORLD_88 = 248, + K_WORLD_89 = 249, + K_WORLD_90 = 250, + K_WORLD_91 = 251, + K_WORLD_92 = 252, + K_WORLD_93 = 253, + K_WORLD_94 = 254, + K_WORLD_95 = 255, /* 0xFF */ + /*@}*/ + + /** @name Numeric keypad */ + /*@{*/ + K_KP0 = 256, + K_KP1 = 257, + K_KP2 = 258, + K_KP3 = 259, + K_KP4 = 260, + K_KP5 = 261, + K_KP6 = 262, + K_KP7 = 263, + K_KP8 = 264, + K_KP9 = 265, + K_KP_PERIOD = 266, + K_KP_DIVIDE = 267, + K_KP_MULTIPLY = 268, + K_KP_MINUS = 269, + K_KP_PLUS = 270, + K_KP_ENTER = 271, + K_KP_EQUALS = 272, + /*@}*/ + + /** @name Arrows + Home/End pad */ + /*@{*/ + K_UP = 273, + K_DOWN = 274, + K_RIGHT = 275, + K_LEFT = 276, + K_INSERT = 277, + K_HOME = 278, + K_END = 279, + K_PAGEUP = 280, + K_PAGEDOWN = 281, + /*@}*/ + + /** @name Function keys */ + /*@{*/ + K_F1 = 282, + K_F2 = 283, + K_F3 = 284, + K_F4 = 285, + K_F5 = 286, + K_F6 = 287, + K_F7 = 288, + K_F8 = 289, + K_F9 = 290, + K_F10 = 291, + K_F11 = 292, + K_F12 = 293, + K_F13 = 294, + K_F14 = 295, + K_F15 = 296, + /*@}*/ + + /** @name Key state modifier keys */ + /*@{*/ + K_NUMLOCK = 300, + K_CAPSLOCK = 301, + K_SCROLLOCK = 302, + K_RSHIFT = 303, + K_LSHIFT = 304, + K_RCTRL = 305, + K_LCTRL = 306, + K_RALT = 307, + K_LALT = 308, + K_RMETA = 309, + K_LMETA = 310, + K_LSUPER = 311, /**< Left "Windows" key */ + K_RSUPER = 312, /**< Right "Windows" key */ + K_MODE = 313, /**< "Alt Gr" key */ + K_COMPOSE = 314, /**< Multi-key compose key */ + /*@}*/ + + /** @name Miscellaneous function keys */ + /*@{*/ + K_HELP = 315, + K_PRINT = 316, + K_SYSREQ = 317, + K_BREAK = 318, + K_MENU = 319, + K_POWER = 320, /**< Power Macintosh power key */ + K_EURO = 321, /**< Some european keyboards */ + K_UNDO = 322, /**< Atari keyboard has Undo */ + /*@}*/ + + /* Add any other keys here */ + + K_LAST + }; + + /** Enumeration of valid key mods (possibly OR'd together) */ + enum Mod { + KMOD_NONE = 0x0000, + KMOD_LSHIFT= 0x0001, + KMOD_RSHIFT= 0x0002, + KMOD_LCTRL = 0x0040, + KMOD_RCTRL = 0x0080, + KMOD_LALT = 0x0100, + KMOD_RALT = 0x0200, + KMOD_LMETA = 0x0400, + KMOD_RMETA = 0x0800, + KMOD_NUM = 0x1000, + KMOD_CAPS = 0x2000, + KMOD_MODE = 0x4000, + KMOD_RESERVED = 0x8000, + KMOD_CTRL = (KMOD_LCTRL|KMOD_RCTRL), + KMOD_SHIFT = (KMOD_LSHIFT|KMOD_RSHIFT), + KMOD_ALT = (KMOD_LALT|KMOD_RALT), + KMOD_META = (KMOD_LMETA|KMOD_RMETA) + }; +} \ No newline at end of file -- cgit v1.2.1 From 2781723f7bf2bef87b7c6c5252aebd6392cbefbf Mon Sep 17 00:00:00 2001 From: Petr Mrázek Date: Thu, 14 Jun 2012 02:25:15 +0200 Subject: Linux build works again. --- library/Core.cpp | 3 +-- library/Hooks-linux.cpp | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'library') diff --git a/library/Core.cpp b/library/Core.cpp index 165f5e5e..620fc81d 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -1220,9 +1220,8 @@ bool Core::ncurses_wgetch(int in, int & out) return true; } -int UnicodeAwareSym(const SDL::Event& event) +int UnicodeAwareSym(const SDL::KeyboardEvent& ke) { - auto ke = (const SDL::KeyboardEvent &) event; // Assume keyboard layouts don't change the order of numbers: if( '0' <= ke.ksym.sym && ke.ksym.sym <= '9') return ke.ksym.sym; if(SDL::K_F1 <= ke.ksym.sym && ke.ksym.sym <= SDL::K_F12) return ke.ksym.sym; diff --git a/library/Hooks-linux.cpp b/library/Hooks-linux.cpp index 3628aab6..ef1a765c 100644 --- a/library/Hooks-linux.cpp +++ b/library/Hooks-linux.cpp @@ -79,7 +79,7 @@ DFhackCExport int SDL_PollEvent(SDL::Event* event) { DFHack::Core & c = DFHack::Core::getInstance(); // if we consume the event, ask SDL for more. - if(!c.SDL_Event(event)) + if(!c.DFH_SDL_Event(event)) goto pollevent_again; } return orig_return; -- cgit v1.2.1 From 7eb4fc19de542db0d3e271123f24773e0c8c481e Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Thu, 14 Jun 2012 12:46:12 +0400 Subject: Make dfhack.run_script usable from other scripts, and document it. --- library/Core.cpp | 10 +++------- library/lua/dfhack.lua | 13 +++++++++---- 2 files changed, 12 insertions(+), 11 deletions(-) (limited to 'library') diff --git a/library/Core.cpp b/library/Core.cpp index 620fc81d..a1090450 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -264,16 +264,12 @@ static bool init_run_script(color_ostream &out, lua_State *state, void *info) return true; } -static command_result runLuaScript(color_ostream &out, std::string filename, vector &args) +static command_result runLuaScript(color_ostream &out, std::string name, vector &args) { ScriptArgs data; - data.pcmd = &filename; + data.pcmd = &name; data.pargs = &args; -#ifndef LINUX_BUILD - filename = toLower(filename); -#endif - bool ok = Lua::RunCoreQueryLoop(out, Lua::Core::State, init_run_script, &data); return ok ? CR_OK : CR_FAILURE; @@ -619,7 +615,7 @@ command_result Core::runCommand(color_ostream &con, const std::string &first, ve { auto filename = getHackPath() + "scripts/" + first + ".lua"; if (fileExists(filename)) - res = runLuaScript(con, filename, parts); + res = runLuaScript(con, first, parts); else con.printerr("%s is not a recognized command.\n", first.c_str()); } diff --git a/library/lua/dfhack.lua b/library/lua/dfhack.lua index 926600c0..4cdb4c95 100644 --- a/library/lua/dfhack.lua +++ b/library/lua/dfhack.lua @@ -273,19 +273,24 @@ end -- Command scripts -dfhack.scripts = dfhack.scripts or {} +dfhack.internal.scripts = dfhack.internal.scripts or {} -function dfhack.run_script(file,...) - local env = dfhack.scripts[file] +local scripts = dfhack.internal.scripts +local hack_path = dfhack.getHackPath() + +function dfhack.run_script(name,...) + local key = string.lower(name) + local file = hack_path..'scripts/'..name..'.lua' + local env = scripts[key] if env == nil then env = {} setmetatable(env, { __index = base_env }) - dfhack.scripts[file] = env end local f,perr = loadfile(file, 't', env) if f == nil then error(perr) end + scripts[key] = env return f(...) end -- cgit v1.2.1 From bbc1fb010ec16ea9260cfc6fe8cc122f79c2d0e6 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Thu, 14 Jun 2012 13:08:39 +0400 Subject: Fix TEXT mode support, even making it work somewhat. - Initialize the global pointers before trying to use init. - Print a message suggesting the use of dfhack-run. - Don't start the console thread if there is no console. - When console is disabled, print anything given to it to stderr. --- library/Console-linux.cpp | 2 ++ library/Core.cpp | 17 ++++++++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) (limited to 'library') diff --git a/library/Console-linux.cpp b/library/Console-linux.cpp index a1ebfad3..6b4de736 100644 --- a/library/Console-linux.cpp +++ b/library/Console-linux.cpp @@ -716,6 +716,8 @@ void Console::add_text(color_value color, const std::string &text) lock_guard g(*wlock); if (inited) d->print_text(color, text); + else + fwrite(text.data(), 1, text.size(), stderr); } int Console::get_columns(void) diff --git a/library/Core.cpp b/library/Core.cpp index a1090450..3a75991c 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -811,14 +811,19 @@ bool Core::Init() } cerr << "Version: " << vinfo->getVersion() << endl; + // Init global object pointers + df::global::InitGlobals(); + cerr << "Initializing Console.\n"; // init the console. bool is_text_mode = false; if(init && init->display.flag.is_set(init_display_flags::TEXT)) { is_text_mode = true; + con.init(true); + cerr << "Console is not available. Use dfhack-run to send commands.\n"; } - if(con.init(is_text_mode)) + else if(con.init(false)) cerr << "Console is running.\n"; else fatal ("Console has failed to initialize!\n", false); @@ -833,7 +838,6 @@ bool Core::Init() */ // initialize data defs virtual_identity::Init(this); - df::global::InitGlobals(); // initialize common lua context Lua::Core::Init(con); @@ -843,12 +847,15 @@ bool Core::Init() cerr << "Initializing Plugins.\n"; // create plugin manager plug_mgr = new PluginManager(this); - cerr << "Starting IO thread.\n"; - // create IO thread IODATA *temp = new IODATA; temp->core = this; temp->plug_mgr = plug_mgr; - thread * IO = new thread(fIOthread, (void *) temp); + if (!is_text_mode) + { + cerr << "Starting IO thread.\n"; + // create IO thread + thread * IO = new thread(fIOthread, (void *) temp); + } cerr << "Starting DF input capture thread.\n"; // set up hotkey capture HotkeyMutex = new mutex(); -- cgit v1.2.1 From 9469f275590e2aca9ce13358847bf16a5791a00c Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Thu, 14 Jun 2012 13:15:37 +0400 Subject: Make the RPC server accept a range of client versions. Otherwise it sort of defeats the purpose of using version handshake. --- library/RemoteServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'library') diff --git a/library/RemoteServer.cpp b/library/RemoteServer.cpp index ed47890f..53428f2b 100644 --- a/library/RemoteServer.cpp +++ b/library/RemoteServer.cpp @@ -220,7 +220,7 @@ void ServerConnection::threadFn() } if (memcmp(header.magic, RPCHandshakeHeader::REQUEST_MAGIC, sizeof(header.magic)) || - header.version != 1) + header.version < 1 || header.version > 255) { out << "In RPC server: invalid handshake header." << endl; return; -- cgit v1.2.1 From 19595f5225b1d74fb7d817e0c11abab8a8c57c0d Mon Sep 17 00:00:00 2001 From: Timothy Collett Date: Thu, 14 Jun 2012 09:55:34 -0400 Subject: Disable a whole bunch of no-longer-necessary debug output --- library/Core.cpp | 22 +++++++++++----------- library/include/Console.h | 12 ++++++------ 2 files changed, 17 insertions(+), 17 deletions(-) (limited to 'library') diff --git a/library/Core.cpp b/library/Core.cpp index 94d408b8..77789746 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -279,29 +279,29 @@ static command_result runLuaScript(color_ostream &out, std::string filename, vec command_result Core::runCommand(color_ostream &out, const std::string &command) { - fprintf(stderr,"Inside runCommand"); - fprintf(stderr," with command %s\n",command.c_str()); + //fprintf(stderr,"Inside runCommand"); + //fprintf(stderr," with command %s\n",command.c_str()); if (!command.empty()) { - fprintf(stderr,"Command is not empty, tokenizing\n"); + //fprintf(stderr,"Command is not empty, tokenizing\n"); vector parts; Core::cheap_tokenise(command,parts); - fprintf(stderr,"Tokenized, got %d parts\n",parts.size()); + //fprintf(stderr,"Tokenized, got %d parts\n",parts.size()); if(parts.size() == 0) return CR_NOT_IMPLEMENTED; string first = parts[0]; - fprintf(stderr,"Erasing beginning\n"); + //fprintf(stderr,"Erasing beginning\n"); parts.erase(parts.begin()); - fprintf(stderr,"I think we're about there\n"); + //fprintf(stderr,"I think we're about there\n"); if (first[0] == '#') return CR_OK; cerr << "Invoking: " << command << endl; - fprintf(stderr,"Returning with the next recursion\n"); + //fprintf(stderr,"Returning with the next recursion\n"); return runCommand(out, first, parts); } else @@ -682,7 +682,7 @@ void fIOthread(void * iodata) { string command = ""; int ret = con.lineedit("[DFHack]# ",command, main_history); - fprintf(stderr,"Command: [%s]\n",command.c_str()); + //fprintf(stderr,"Command: [%s]\n",command.c_str()); if(ret == -2) { cerr << "Console is shutting down properly." << endl; @@ -696,13 +696,13 @@ void fIOthread(void * iodata) else if(ret) { // a proper, non-empty command was entered - fprintf(stderr,"Adding command to history\n"); + //fprintf(stderr,"Adding command to history\n"); main_history.add(command); - fprintf(stderr,"Saving history\n"); + //fprintf(stderr,"Saving history\n"); main_history.save("dfhack.history"); } - fprintf(stderr,"Running command\n"); + //fprintf(stderr,"Running command\n"); auto rv = core->runCommand(con, command); diff --git a/library/include/Console.h b/library/include/Console.h index 196a1c27..ba59324e 100644 --- a/library/include/Console.h +++ b/library/include/Console.h @@ -65,20 +65,20 @@ namespace DFHack bool save (const char * filename) { std::ofstream outfile (filename); - fprintf(stderr,"Save: Initialized stream\n"); + //fprintf(stderr,"Save: Initialized stream\n"); if(outfile.bad()) return false; - fprintf(stderr,"Save: Iterating...\n"); + //fprintf(stderr,"Save: Iterating...\n"); for(auto iter = history.begin();iter < history.end(); iter++) { - fprintf(stderr,"Save: Dumping %s\n",(*iter).c_str()); + //fprintf(stderr,"Save: Dumping %s\n",(*iter).c_str()); outfile << *iter << std::endl; - fprintf(stderr,"Save: Flushing\n"); + //fprintf(stderr,"Save: Flushing\n"); outfile.flush(); } - fprintf(stderr,"Save: Closing\n"); + //fprintf(stderr,"Save: Closing\n"); outfile.close(); - fprintf(stderr,"Save: Done\n"); + //fprintf(stderr,"Save: Done\n"); return true; } /// add a command to the history -- cgit v1.2.1 From 0ced9d99410c65dcf1e3ac2ac62cc1dd0b7c89bf Mon Sep 17 00:00:00 2001 From: Timothy Collett Date: Thu, 14 Jun 2012 09:56:20 -0400 Subject: Hopefully fix DFHack's attempt to pull libstdc++ from somewhere silly (for portability) --- library/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'library') diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 2035a5ce..10514539 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -267,8 +267,9 @@ SET_TARGET_PROPERTIES(dfhack PROPERTIES DEBUG_POSTFIX "-debug" ) IF(APPLE) SET(SDL_LIBRARY ${CMAKE_INSTALL_PREFIX}/libs/SDL.framework) + SET(CXX_LIBRARY ${CMAKE_INSTALL_PREFIX}/libs/libstdc++.6.dylib) TARGET_LINK_LIBRARIES(dfhack ${SDL_LIBRARY}) -# TARGET_LINK_LIBRARIES(dfhack /usr/lib/libc++.dylib) + TARGET_LINK_LIBRARIES(dfhack ${CXX_LIBRARY}) SET_TARGET_PROPERTIES(dfhack PROPERTIES VERSION 1.0.0) SET_TARGET_PROPERTIES(dfhack PROPERTIES SOVERSION 1.0.0) ENDIF() -- cgit v1.2.1 From 94dfdb486d0a2bbc832f60fd58847732ac670390 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Thu, 14 Jun 2012 20:32:23 +0400 Subject: Change the field names returned from dfhack.internal.getMemRanges() 'end' is a lua keyword, so it cannot be used conveniently. --- library/LuaApi.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'library') diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index aa168db3..59956a2c 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1076,9 +1076,9 @@ static int internal_getMemRanges(lua_State *L) { lua_newtable(L); lua_pushnumber(L, (uint32_t)ranges[i].start); - lua_setfield(L, -2, "start"); + lua_setfield(L, -2, "start_addr"); lua_pushnumber(L, (uint32_t)ranges[i].end); - lua_setfield(L, -2, "end"); + lua_setfield(L, -2, "end_addr"); lua_pushstring(L, ranges[i].name); lua_setfield(L, -2, "name"); lua_pushboolean(L, ranges[i].read); -- cgit v1.2.1 From 12543d6a5b4afc4cbba20670f3e463672ed9fac4 Mon Sep 17 00:00:00 2001 From: Timothy Collett Date: Thu, 14 Jun 2012 13:42:06 -0400 Subject: Make offsets with "darwin" os-type recognized as Apple, rather than ignored --- library/VersionInfoFactory.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'library') diff --git a/library/VersionInfoFactory.cpp b/library/VersionInfoFactory.cpp index 972ab31b..4ac53dd1 100644 --- a/library/VersionInfoFactory.cpp +++ b/library/VersionInfoFactory.cpp @@ -105,6 +105,12 @@ void VersionInfoFactory::ParseVersion (TiXmlElement* entry, VersionInfo* mem) // this is wrong... I'm not going to do base image relocation on linux though. mem->setBase(0x0); } + else if(os == "darwin") + { + mem->setOS(OS_APPLE); + // this is wrong... I'm not going to do base image relocation on linux though. + mem->setBase(0x0); + } else { return; // ignore it if it's invalid -- cgit v1.2.1 From f2a30c1a929d14a79ee95402b72565b3f23eab7a Mon Sep 17 00:00:00 2001 From: Timothy Collett Date: Thu, 14 Jun 2012 13:42:40 -0400 Subject: Remove build-time dependency on SDL --- library/Hooks-darwin.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'library') diff --git a/library/Hooks-darwin.cpp b/library/Hooks-darwin.cpp index 347881ee..ef89105d 100644 --- a/library/Hooks-darwin.cpp +++ b/library/Hooks-darwin.cpp @@ -83,8 +83,8 @@ DFhackCExport void SDL_Quit(void) } // called by DF to check input events -static int (*_SDL_PollEvent)(SDL_Event* event) = 0; -DFhackCExport int SDL_PollEvent(SDL_Event* event) +static int (*_SDL_PollEvent)(SDL::Event* event) = 0; +DFhackCExport int SDL_PollEvent(SDL::Event* event) { pollevent_again: // if SDL returns 0 here, it means there are no more events. return 0 @@ -140,7 +140,7 @@ DFhackCExport int SDL_Init(uint32_t flags) fprintf(stderr,"dfhack: saving real SDL functions\n"); _SDL_Init = (int (*)( uint32_t )) dlsym(RTLD_NEXT, "SDL_Init"); _SDL_Quit = (void (*)( void )) dlsym(RTLD_NEXT, "SDL_Quit"); - _SDL_PollEvent = (int (*)(SDL_Event*))dlsym(RTLD_NEXT,"SDL_PollEvent"); + _SDL_PollEvent = (int (*)(SDL::Event*))dlsym(RTLD_NEXT,"SDL_PollEvent"); fprintf(stderr,"dfhack: saved real SDL functions\n"); // check if we got them -- cgit v1.2.1 From 9c35e9fa597199fd2ed639d06a7d6fd3cadc8cd3 Mon Sep 17 00:00:00 2001 From: Timothy Collett Date: Thu, 14 Jun 2012 13:43:03 -0400 Subject: Ensure that the appropriate libz.dylib is used --- library/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) (limited to 'library') diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 10514539..73f6c9ec 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -268,8 +268,10 @@ SET_TARGET_PROPERTIES(dfhack PROPERTIES DEBUG_POSTFIX "-debug" ) IF(APPLE) SET(SDL_LIBRARY ${CMAKE_INSTALL_PREFIX}/libs/SDL.framework) SET(CXX_LIBRARY ${CMAKE_INSTALL_PREFIX}/libs/libstdc++.6.dylib) + SET(ZIP_LIBRARY /usr/lib/libz.dylib) TARGET_LINK_LIBRARIES(dfhack ${SDL_LIBRARY}) TARGET_LINK_LIBRARIES(dfhack ${CXX_LIBRARY}) + TARGET_LINK_LIBRARIES(dfhack ${ZIP_LIBRARY}) SET_TARGET_PROPERTIES(dfhack PROPERTIES VERSION 1.0.0) SET_TARGET_PROPERTIES(dfhack PROPERTIES SOVERSION 1.0.0) ENDIF() -- cgit v1.2.1 From 14a3e5cd9e8630d156de8323a911d3cb5a466969 Mon Sep 17 00:00:00 2001 From: Timothy Collett Date: Thu, 14 Jun 2012 13:43:20 -0400 Subject: Implement getMemRanges() on the Mac --- library/Process-darwin.cpp | 85 +++++++++++++++++++++++++++++++++------------- 1 file changed, 62 insertions(+), 23 deletions(-) (limited to 'library') diff --git a/library/Process-darwin.cpp b/library/Process-darwin.cpp index a4b95186..d043e5b1 100644 --- a/library/Process-darwin.cpp +++ b/library/Process-darwin.cpp @@ -124,33 +124,72 @@ string Process::doReadClassName (void * vptr) return raw.substr(start,end-start); } -//FIXME: cross-reference with ELF segment entries? +#include +#include +#include +#include +#include + void Process::getMemRanges( vector & ranges ) { - char buffer[1024]; - char permissions[5]; // r/-, w/-, x/-, p/s, 0 - FILE *mapFile = ::fopen("/proc/self/maps", "r"); - size_t start, end, offset, device1, device2, node; + kern_return_t kr; + task_t the_task; - while (fgets(buffer, 1024, mapFile)) - { - t_memrange temp; - temp.name[0] = 0; - sscanf(buffer, "%zx-%zx %s %zx %2zx:%2zx %zu %[^\n]", - &start, - &end, - (char*)&permissions, - &offset, &device1, &device2, &node, - (char*)temp.name); - temp.start = (void *) start; - temp.end = (void *) end; - temp.read = permissions[0] == 'r'; - temp.write = permissions[1] == 'w'; - temp.execute = permissions[2] == 'x'; - temp.shared = permissions[3] == 's'; - temp.valid = true; - ranges.push_back(temp); + the_task = mach_task_self(); + + vm_size_t vmsize; + vm_address_t address; + vm_region_basic_info_data_t info; + mach_msg_type_number_t info_count; + vm_region_flavor_t flavor; + memory_object_name_t object; + + kr = KERN_SUCCESS; + address = 0; + + do { + flavor = VM_REGION_BASIC_INFO; + info_count = VM_REGION_BASIC_INFO_COUNT; + kr = vm_region(the_task, &address, &vmsize, flavor, + (vm_region_info_t)&info, &info_count, &object); + if (kr == KERN_SUCCESS) { + if (info.reserved==1) { + address += vmsize; + continue; + } + Dl_info dlinfo; + int dlcheck; + dlcheck = dladdr((const void*)address, &dlinfo); + if (dlcheck==0) { + dlinfo.dli_fname = "(none)"; + } + + t_memrange temp; + strncpy( temp.name, dlinfo.dli_fname, 1023 ); + temp.name[1023] = 0; + temp.start = (void *) address; + temp.end = (void *) (address+vmsize); + temp.read = (info.protection & VM_PROT_READ); + temp.write = (info.protection & VM_PROT_WRITE); + temp.execute = (info.protection & VM_PROT_EXECUTE); + temp.shared = info.shared; + temp.valid = true; + ranges.push_back(temp); + + address += vmsize; + } else if (kr != KERN_INVALID_ADDRESS) { + + if (the_task != MACH_PORT_NULL) { + mach_port_deallocate(mach_task_self(), the_task); + } + return; + } + } while (kr != KERN_INVALID_ADDRESS); + + + if (the_task != MACH_PORT_NULL) { + mach_port_deallocate(mach_task_self(), the_task); } } -- cgit v1.2.1 From dc5bef2cb84cceb30179df750d986eecdef8b474 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Sat, 16 Jun 2012 13:33:49 +0400 Subject: Add lua internal api functions needed for scanning memory. --- library/LuaApi.cpp | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 105 insertions(+), 1 deletion(-) (limited to 'library') diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 59956a2c..50458f11 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1021,6 +1021,21 @@ static const luaL_Reg dfhack_constructions_funcs[] = { /***** Internal module *****/ +static void *checkaddr(lua_State *L, int idx, bool allow_null = false) +{ + luaL_checkany(L, idx); + void *rv; + if (lua_isnil(L, idx)) + rv = NULL; + else if (lua_type(L, idx) == LUA_TNUMBER) + rv = (void*)lua_tointeger(L, idx); + else + rv = Lua::CheckDFObject(L, NULL, idx); + if (!rv && !allow_null) + luaL_argerror(L, idx, "null pointer"); + return rv; +} + static uint32_t getBase() { return Core::getInstance().p->getBase(); } static const LuaWrapper::FunctionReg dfhack_internal_module[] = { @@ -1042,7 +1057,7 @@ static int internal_getAddress(lua_State *L) static int internal_setAddress(lua_State *L) { std::string name = luaL_checkstring(L, 1); - uint32_t addr = luaL_checkint(L, 2); + uint32_t addr = (uint32_t)checkaddr(L, 2, true); internal_getAddress(L); // Set the address @@ -1097,10 +1112,99 @@ static int internal_getMemRanges(lua_State *L) return 1; } +static int internal_memmove(lua_State *L) +{ + void *dest = checkaddr(L, 1); + void *src = checkaddr(L, 2); + int size = luaL_checkint(L, 3); + if (size < 0) luaL_argerror(L, 1, "negative size"); + memmove(dest, src, size); + return 0; +} + +static int internal_memcmp(lua_State *L) +{ + void *dest = checkaddr(L, 1); + void *src = checkaddr(L, 2); + int size = luaL_checkint(L, 3); + if (size < 0) luaL_argerror(L, 1, "negative size"); + lua_pushinteger(L, memcmp(dest, src, size)); + return 1; +} + +static int internal_memscan(lua_State *L) +{ + uint8_t *haystack = (uint8_t*)checkaddr(L, 1); + int hcount = luaL_checkint(L, 2); + int hstep = luaL_checkint(L, 3); + if (hstep == 0) luaL_argerror(L, 3, "zero step"); + void *needle = checkaddr(L, 4); + int nsize = luaL_checkint(L, 5); + if (nsize < 0) luaL_argerror(L, 5, "negative size"); + + for (int i = 0; i <= hcount; i++) + { + uint8_t *p = haystack + i*hstep; + if (memcmp(p, needle, nsize) == 0) { + lua_pushinteger(L, i); + lua_pushinteger(L, (lua_Integer)p); + return 2; + } + } + + lua_pushnil(L); + return 1; +} + +static int internal_diffscan(lua_State *L) +{ + lua_settop(L, 8); + void *old_data = checkaddr(L, 1); + void *new_data = checkaddr(L, 2); + int start_idx = luaL_checkint(L, 3); + int end_idx = luaL_checkint(L, 4); + int eltsize = luaL_checkint(L, 5); + bool has_oldv = !lua_isnil(L, 6); + bool has_newv = !lua_isnil(L, 7); + bool has_diffv = !lua_isnil(L, 8); + +#define LOOP(esz, etype) \ + case esz: { \ + etype *pold = (etype*)old_data; \ + etype *pnew = (etype*)new_data; \ + etype oldv = (etype)luaL_optint(L, 6, 0); \ + etype newv = (etype)luaL_optint(L, 7, 0); \ + etype diffv = (etype)luaL_optint(L, 8, 0); \ + for (int i = start_idx; i < end_idx; i++) { \ + if (pold[i] == pnew[i]) continue; \ + if (has_oldv && pold[i] != oldv) continue; \ + if (has_newv && pnew[i] != newv) continue; \ + if (has_diffv && etype(pnew[i]-pold[i]) != diffv) continue; \ + lua_pushinteger(L, i); return 1; \ + } \ + break; \ + } + switch (eltsize) { + LOOP(1, uint8_t); + LOOP(2, uint16_t); + LOOP(4, uint32_t); + default: + luaL_argerror(L, 5, "invalid element size"); + } +#undef LOOP + + lua_pushnil(L); + return 1; +} + static const luaL_Reg dfhack_internal_funcs[] = { { "getAddress", internal_getAddress }, { "setAddress", internal_setAddress }, { "getMemRanges", internal_getMemRanges }, + { "memmove", internal_memmove }, + { "memcmp", internal_memcmp }, + { "memscan", internal_memscan }, + { "diffscan", internal_diffscan }, { NULL, NULL } }; -- cgit v1.2.1 From db91850464a98e785ff53cfdc5df46b10229cfdb Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Sat, 16 Jun 2012 14:42:56 +0400 Subject: Sync to the change in gamemode/gametype globals. --- library/RemoteTools.cpp | 16 ++++++++-------- library/include/modules/World.h | 31 +++++++------------------------ library/modules/World.cpp | 10 +++++----- library/xml | 2 +- 4 files changed, 21 insertions(+), 38 deletions(-) (limited to 'library') diff --git a/library/RemoteTools.cpp b/library/RemoteTools.cpp index 689c783a..95c495e9 100644 --- a/library/RemoteTools.cpp +++ b/library/RemoteTools.cpp @@ -379,19 +379,19 @@ static command_result GetWorldInfo(color_ostream &stream, if (!ui || !world || !Core::getInstance().isWorldLoaded()) return CR_NOT_FOUND; - t_gamemodes mode; - if (!Core::getInstance().getWorld()->ReadGameMode(mode)) - mode.g_type = GAMETYPE_DWARF_MAIN; + df::game_type gt = game_type::DWARF_MAIN; + if (df::global::gametype) + gt = *df::global::gametype; out->set_save_dir(world->cur_savegame.save_dir); if (world->world_data->name.has_name) describeName(out->mutable_world_name(), &world->world_data->name); - switch (mode.g_type) + switch (gt) { - case GAMETYPE_DWARF_MAIN: - case GAMETYPE_DWARF_RECLAIM: + case game_type::DWARF_MAIN: + case game_type::DWARF_RECLAIM: out->set_mode(GetWorldInfoOut::MODE_DWARF); out->set_civ_id(ui->civ_id); out->set_site_id(ui->site_id); @@ -399,7 +399,7 @@ static command_result GetWorldInfo(color_ostream &stream, out->set_race_id(ui->race_id); break; - case GAMETYPE_ADVENTURE_MAIN: + case game_type::ADVENTURE_MAIN: out->set_mode(GetWorldInfoOut::MODE_ADVENTURE); if (auto unit = vector_get(world->units.active, 0)) @@ -423,7 +423,7 @@ static command_result GetWorldInfo(color_ostream &stream, } break; - case GAMETYPE_VIEW_LEGENDS: + case game_type::VIEW_LEGENDS: out->set_mode(GetWorldInfoOut::MODE_LEGENDS); break; diff --git a/library/include/modules/World.h b/library/include/modules/World.h index 81ebfbd6..8b0fe3f5 100644 --- a/library/include/modules/World.h +++ b/library/include/modules/World.h @@ -35,32 +35,15 @@ distribution. #include "Module.h" #include +#include "DataDefs.h" + namespace DFHack { - /** - * \ingroup grp_world - */ - enum GameMode - { - GAMEMODE_DWARF, - GAMEMODE_ADVENTURE, - GAMEMODENUM, - GAMEMODE_NONE - }; - /** - * \ingroup grp_world - */ - enum GameType - { - GAMETYPE_DWARF_MAIN, - GAMETYPE_ADVENTURE_MAIN, - GAMETYPE_VIEW_LEGENDS, - GAMETYPE_DWARF_RECLAIM, - GAMETYPE_DWARF_ARENA, - GAMETYPE_ADVENTURE_ARENA, - GAMETYPENUM, - GAMETYPE_NONE - }; + typedef df::game_mode GameMode; + typedef df::game_type GameType; + +#define GAMEMODE_ADVENTURE df::enums::game_mode::ADVENTURE + /** * \ingroup grp_world */ diff --git a/library/modules/World.cpp b/library/modules/World.cpp index 4b50b44c..393e7cbf 100644 --- a/library/modules/World.cpp +++ b/library/modules/World.cpp @@ -85,7 +85,7 @@ World::World() if(df::global::current_weather) d->StartedWeather = true; - if (df::global::game_mode && df::global::control_mode) + if (df::global::gamemode && df::global::gametype) d->StartedMode = true; d->Inited = true; @@ -132,8 +132,8 @@ bool World::ReadGameMode(t_gamemodes& rd) { if(d->Inited && d->StartedMode) { - rd.g_mode = (DFHack::GameMode)*df::global::control_mode; - rd.g_type = (DFHack::GameType)*df::global::game_mode; + rd.g_mode = (DFHack::GameMode)*df::global::gamemode; + rd.g_type = (DFHack::GameType)*df::global::gametype; return true; } return false; @@ -142,8 +142,8 @@ bool World::WriteGameMode(const t_gamemodes & wr) { if(d->Inited && d->StartedMode) { - *df::global::control_mode = wr.g_mode; - *df::global::game_mode = wr.g_type; + *df::global::gamemode = wr.g_mode; + *df::global::gametype = wr.g_type; return true; } return false; diff --git a/library/xml b/library/xml index c3818846..bc757db6 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit c381884664c71adefbec44258a734def2c88dacc +Subproject commit bc757db69514b54eb66d4d38e9cc1354d3761907 -- cgit v1.2.1 From 927ce6ce5adf019fd4f5fe18024b4f1b4c17fc20 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Sat, 16 Jun 2012 17:09:58 +0400 Subject: Fix a problem with number to address cast for high-half addresses. If the address is out of the signed int range, lua_tointeger produces unspecified result. lua_tounsigned is guaranteed to wrap. --- library/LuaApi.cpp | 2 +- library/LuaWrapper.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'library') diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 50458f11..cdfd4789 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1028,7 +1028,7 @@ static void *checkaddr(lua_State *L, int idx, bool allow_null = false) if (lua_isnil(L, idx)) rv = NULL; else if (lua_type(L, idx) == LUA_TNUMBER) - rv = (void*)lua_tointeger(L, idx); + rv = (void*)lua_tounsigned(L, idx); else rv = Lua::CheckDFObject(L, NULL, idx); if (!rv && !allow_null) diff --git a/library/LuaWrapper.cpp b/library/LuaWrapper.cpp index 7c15a27a..9f2fc2f1 100644 --- a/library/LuaWrapper.cpp +++ b/library/LuaWrapper.cpp @@ -715,7 +715,7 @@ static int meta_reinterpret_cast(lua_State *state) if (lua_isnil(state, 2)) ptr = NULL; else if (lua_isnumber(state, 2)) - ptr = (void*)lua_tointeger(state, 2); + ptr = (void*)lua_tounsigned(state, 2); else { ptr = get_object_internal(state, NULL, 2, false, true); -- cgit v1.2.1 From 67536da2fe718b103f4200b95f00cd30000cb7ad Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Sat, 16 Jun 2012 19:51:15 +0400 Subject: Add an interactive script finding a limited subset of linux offsets. --- library/lua/memscan.lua | 419 ++++++++++++++++++++++++++++++++++++++++++++++++ library/lua/utils.lua | 44 +++++ 2 files changed, 463 insertions(+) create mode 100644 library/lua/memscan.lua (limited to 'library') diff --git a/library/lua/memscan.lua b/library/lua/memscan.lua new file mode 100644 index 00000000..e5a0c6f7 --- /dev/null +++ b/library/lua/memscan.lua @@ -0,0 +1,419 @@ +-- Utilities for offset scan scripts. + +local _ENV = mkmodule('memscan') + +local utils = require('utils') + +-- A length-checked view on a memory buffer + +CheckedArray = CheckedArray or {} + +function CheckedArray.new(type,saddr,eaddr) + local data = df.reinterpret_cast(type,saddr) + local esize = data:sizeof() + local count = math.floor((eaddr-saddr)/esize) + local obj = { + type = type, start = saddr, size = count*esize, + esize = esize, data = data, count = count + } + setmetatable(obj, CheckedArray) + return obj +end + +function CheckedArray:__len() + return self.count +end +function CheckedArray:__index(idx) + if type(idx) == number then + if idx >= self.count then + error('Index out of bounds: '..tostring(idx)) + end + return self.data[idx] + else + return CheckedArray[idx] + end +end +function CheckedArray:__newindex(idx, val) + if idx >= self.count then + error('Index out of bounds: '..tostring(idx)) + end + self.data[idx] = val +end +function CheckedArray:addr2idx(addr, round) + local off = addr - self.start + if off >= 0 and off < self.size and (round or (off % self.esize) == 0) then + return math.floor(off / self.esize), off + end +end +function CheckedArray:idx2addr(idx) + if idx >= 0 and idx < self.count then + return self.start + idx*self.esize + end +end + +-- Search methods + +function CheckedArray:find(data,sidx,eidx,reverse) + local dcnt = #data + sidx = math.max(0, sidx or 0) + eidx = math.min(self.count, eidx or self.count) + if (eidx - sidx) >= dcnt and dcnt > 0 then + return dfhack.with_temp_object( + df.new(self.type, dcnt), + function(buffer) + for i = 1,dcnt do + buffer[i-1] = data[i] + end + local cnt = eidx - sidx - dcnt + local step = self.esize + local sptr = self.start + sidx*step + local ksize = dcnt*step + if reverse then + local idx, addr = dfhack.internal.memscan(sptr + cnt*step, cnt, -step, buffer, ksize) + if idx then + return sidx + cnt - idx, addr + end + else + local idx, addr = dfhack.internal.memscan(sptr, cnt, step, buffer, ksize) + if idx then + return sidx + idx, addr + end + end + end + ) + end +end +function CheckedArray:find_one(data,sidx,eidx,reverse) + local idx, addr = self:find(data,sidx,eidx,reverse) + if idx then + -- Verify this is the only match + if reverse then + eidx = idx+#data-1 + else + sidx = idx+1 + end + if self:find(data,sidx,eidx,reverse) then + return nil + end + end + return idx, addr +end +function CheckedArray:list_changes(old_arr,old_val,new_val,delta) + if old_arr.type ~= self.type or old_arr.count ~= self.count then + error('Incompatible arrays') + end + local eidx = self.count + local optr = old_arr.start + local nptr = self.start + local esize = self.esize + local rv + local sidx = 0 + while true do + local idx = dfhack.internal.diffscan(optr, nptr, sidx, eidx, esize, old_val, new_val, delta) + if not idx then + break + end + rv = rv or {} + rv[#rv+1] = idx + sidx = idx+1 + end + return rv +end +function CheckedArray:filter_changes(prev_list,old_arr,old_val,new_val,delta) + if old_arr.type ~= self.type or old_arr.count ~= self.count then + error('Incompatible arrays') + end + local eidx = self.count + local optr = old_arr.start + local nptr = self.start + local esize = self.esize + local rv + for i=1,#prev_list do + local idx = prev_list[i] + if idx < 0 or idx >= eidx then + error('Index out of bounds: '..idx) + end + if dfhack.internal.diffscan(optr, nptr, idx, idx+1, esize, old_val, new_val, delta) then + rv = rv or {} + rv[#rv+1] = idx + end + end + return rv +end + +-- A raw memory area class + +MemoryArea = MemoryArea or {} +MemoryArea.__index = MemoryArea + +function MemoryArea.new(astart, aend) + local obj = { + start_addr = astart, end_addr = aend, size = aend - astart, + int8_t = CheckedArray.new('int8_t',astart,aend), + uint8_t = CheckedArray.new('uint8_t',astart,aend), + int16_t = CheckedArray.new('int16_t',astart,aend), + uint16_t = CheckedArray.new('uint16_t',astart,aend), + int32_t = CheckedArray.new('int32_t',astart,aend), + uint32_t = CheckedArray.new('uint32_t',astart,aend) + } + setmetatable(obj, MemoryArea) + return obj +end + +function MemoryArea:__gc() + df.delete(self.buffer) +end + +function MemoryArea:__tostring() + return string.format('', self.start_addr, self.end_addr) +end +function MemoryArea:contains_range(start,size) + return start >= self.start_addr and (start+size) <= self.end_addr +end +function MemoryArea:contains_obj(obj,count) + local size, base = df.sizeof(obj) + return size and base and self:contains_range(base, size*(count or 1)) +end + +function MemoryArea:clone() + local buffer = df.new('int8_t', self.size) + local _, base = buffer:sizeof() + local rv = MemoryArea.new(base, base+self.size) + rv.buffer = buffer + return rv +end +function MemoryArea:copy_from(area2) + if area2.size ~= self.size then + error('Size mismatch') + end + dfhack.internal.memmove(self.start_addr, area2.start_addr, self.size) +end +function MemoryArea:delete() + setmetatable(self, nil) + df.delete(self.buffer) + for k,v in pairs(self) do self[k] = nil end +end + +-- Static data segment search + +local function find_data_segment() + local data_start, data_end + + for i,mem in ipairs(dfhack.internal.getMemRanges()) do + if data_end then + if mem.start_addr == data_end and mem.read and mem.write then + data_end = mem.end_addr + else + break + end + elseif mem.read and mem.write + and (string.match(mem.name,'/dwarfort%.exe$') + or string.match(mem.name,'/Dwarf_Fortress$')) + then + data_start = mem.start_addr + data_end = mem.end_addr + end + end + + return data_start, data_end +end + +function get_data_segment() + local s, e = find_data_segment() + if s and e then + return MemoryArea.new(s, e) + end +end + +-- Register a found offset, or report an error. + +function found_offset(name,val) + local cval = dfhack.internal.getAddress(name) + + if not val then + print('Could not find offset '..name) + if not cval and not utils.prompt_yes_no('Continue with the script?') then + error('User quit') + end + return + end + + if df.isvalid(val) then + _,val = val:sizeof() + end + + print(string.format('Found offset %s: %x', name, val)) + + if cval then + if cval ~= val then + error(string.format('Mismatch with the current value: %x',val)) + end + else + dfhack.internal.setAddress(name, val) + end +end + +-- Offset of a field within struct + +function field_ref(handle,...) + local items = table.pack(...) + for i=1,items.n-1 do + handle = handle[items[i]] + end + return handle:_field(items[items.n]) +end + +function field_offset(type,...) + local handle = df.reinterpret_cast(type,1) + local _,addr = df.sizeof(field_ref(handle,...)) + return addr-1 +end + +function MemoryArea:object_by_field(addr,type,...) + if not addr then + return nil + end + local base = addr - field_offset(type,...) + local obj = df.reinterpret_cast(type, base) + if not self:contains_obj(obj) then + obj = nil + end + return obj, base +end + +-- Validation + +function is_valid_vector(ref,size) + local ints = df.reinterpret_cast('uint32_t', ref) + return ints[0] <= ints[1] and ints[1] <= ints[2] + and (size == nil or (ints[1] - ints[0]) % size == 0) +end + +-- Difference search helper + +DiffSearcher = DiffSearcher or {} +DiffSearcher.__index = DiffSearcher + +function DiffSearcher.new(area) + local obj = { area = area } + setmetatable(obj, DiffSearcher) + return obj +end + +function DiffSearcher:begin_search(type) + self.type = type + self.old_value = nil + self.search_sets = nil + if not self.save_area then + self.save_area = self.area:clone() + end +end +function DiffSearcher:advance_search(new_value,delta) + if self.search_sets then + local nsets = #self.search_sets + local ovec = self.save_area[self.type] + local nvec = self.area[self.type] + local new_set + if nsets > 0 then + local last_set = self.search_sets[nsets] + new_set = nvec:filter_changes(last_set,ovec,self.old_value,new_value,delta) + else + new_set = nvec:list_changes(ovec,self.old_value,new_value,delta) + end + if new_set then + self.search_sets[nsets+1] = new_set + self.old_value = new_value + self.save_area:copy_from(self.area) + return #new_set, new_set + end + else + self.old_value = new_value + self.search_sets = {} + self.save_area:copy_from(self.area) + return #self.save_area[self.type], nil + end +end +function DiffSearcher:reset() + self.search_sets = nil + if self.save_area then + self.save_area:delete() + self.save_area = nil + end +end +function DiffSearcher:idx2addr(idx) + return self.area[self.type]:idx2addr(idx) +end + +-- Menu search utility + +function find_menu_cursor(searcher,prompt,data_type,choices,enum) + enum = enum or {} + + -- Loop for restarting search from scratch + while true do + print('\n'..prompt) + + searcher:begin_search(data_type) + + local found = false + local ccursor = 0 + + -- Loop through choices + while true do + local choice + + -- Select the next value to search for + if type(choices) == 'function' then + print('') + + choice = choices(ccursor) + ccursor = ccursor + 1 + + if not choice then + break + end + else + choice = choices[ccursor+1] + ccursor = (ccursor+1) % #choices + + local cname = enum[choice] or choice + if type(choice) == 'string' and type(cname) == 'number' then + choice, cname = cname, choice + end + if cname ~= choice then + cname = cname..' ('..choice..')' + end + + -- Ask the user to select it + print('\n Please select: '..cname) + if not utils.prompt_yes_no(' Continue?', true) then + break + end + end + + -- Search for it in the memory + local cnt, set = searcher:advance_search(choice) + if not cnt then + dfhack.printerr(' Converged to zero candidates; probably a mistake somewhere.') + break + elseif set and cnt == 1 then + -- To confirm, wait for two 1-candidate results in a row + if found then + local addr = searcher:idx2addr(set[1]) + print(string.format(' Confirmed address: %x\n', addr)) + return addr, set[1] + else + found = true + end + end + + print(' '..cnt..' candidates remaining.') + end + + if not utils.prompt_yes_no('\nRetry search from the start?') then + return nil + end + end +end + +return _ENV diff --git a/library/lua/utils.lua b/library/lua/utils.lua index e67801f4..4fac56ec 100644 --- a/library/lua/utils.lua +++ b/library/lua/utils.lua @@ -361,4 +361,48 @@ function insert_or_update(vector,item,field,cmp) return added,cur,pos end +-- Ask a yes-no question +function prompt_yes_no(msg,default) + local prompt = msg + if default == nil then + prompt = prompt..' (y/n): ' + elseif default then + prompt = prompt..' (y/n/enter=y): ' + else + prompt = prompt..' (y/n/enter=n): ' + end + while true do + local rv = dfhack.lineedit(prompt) + if rv then + if string.match(rv,'^[Yy]') then + return true + elseif string.match(rv,'^[Nn]') then + return false + elseif rv == '' and default ~= nil then + return default + end + end + end +end + +-- Ask for input with check function +function prompt_input(prompt,check,quit_str) + quit_str = quit_str or '~~~' + while true do + local rv = dfhack.lineedit(prompt) + if rv == quit_str then + return nil + end + local rtbl = table.pack(check(rv)) + if rtbl[1] then + return table.unpack(rtbl,2,rtbl.n) + end + end +end + +function check_number(text) + local nv = tonumber(text) + return nv ~= nil, nv +end + return _ENV \ No newline at end of file -- cgit v1.2.1 From fa41a27f2643afe8c8b601aab3e2ab3b1403411d Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Sun, 17 Jun 2012 14:26:27 +0400 Subject: Add an api function to get vtable address from version info. --- library/LuaApi.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'library') diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index cdfd4789..631b3c49 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1080,6 +1080,17 @@ static int internal_setAddress(lua_State *L) return 1; } +static int internal_getVTable(lua_State *L) +{ + const char *name = luaL_checkstring(L, 1); + uint32_t addr = (uint32_t)Core::getInstance().vinfo->getVTable(name); + if (addr) + lua_pushnumber(L, addr); + else + lua_pushnil(L); + return 1; +} + static int internal_getMemRanges(lua_State *L) { std::vector ranges; @@ -1200,6 +1211,7 @@ static int internal_diffscan(lua_State *L) static const luaL_Reg dfhack_internal_funcs[] = { { "getAddress", internal_getAddress }, { "setAddress", internal_setAddress }, + { "getVTable", internal_getVTable }, { "getMemRanges", internal_getMemRanges }, { "memmove", internal_memmove }, { "memcmp", internal_memcmp }, -- cgit v1.2.1 From dc6cb61979458d00aa5c9a8d1f635d35891ca6ee Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Sun, 17 Jun 2012 18:44:59 +0400 Subject: Add more offset finders to the script. --- library/lua/memscan.lua | 98 +++++++++++++++++++++++++++++++++---------------- library/lua/utils.lua | 6 ++- 2 files changed, 71 insertions(+), 33 deletions(-) (limited to 'library') diff --git a/library/lua/memscan.lua b/library/lua/memscan.lua index e5a0c6f7..95b9197b 100644 --- a/library/lua/memscan.lua +++ b/library/lua/memscan.lua @@ -344,62 +344,41 @@ function DiffSearcher:idx2addr(idx) return self.area[self.type]:idx2addr(idx) end --- Menu search utility +-- Interactive search utility -function find_menu_cursor(searcher,prompt,data_type,choices,enum) +function DiffSearcher:find_interactive(prompt,data_type,condition_cb) enum = enum or {} -- Loop for restarting search from scratch while true do print('\n'..prompt) - searcher:begin_search(data_type) + self:begin_search(data_type) local found = false local ccursor = 0 -- Loop through choices while true do - local choice + print('') - -- Select the next value to search for - if type(choices) == 'function' then - print('') + local ok, value, delta = condition_cb(ccursor) - choice = choices(ccursor) - ccursor = ccursor + 1 - - if not choice then - break - end - else - choice = choices[ccursor+1] - ccursor = (ccursor+1) % #choices + ccursor = ccursor + 1 - local cname = enum[choice] or choice - if type(choice) == 'string' and type(cname) == 'number' then - choice, cname = cname, choice - end - if cname ~= choice then - cname = cname..' ('..choice..')' - end - - -- Ask the user to select it - print('\n Please select: '..cname) - if not utils.prompt_yes_no(' Continue?', true) then - break - end + if not ok then + break end -- Search for it in the memory - local cnt, set = searcher:advance_search(choice) + local cnt, set = self:advance_search(value, delta) if not cnt then dfhack.printerr(' Converged to zero candidates; probably a mistake somewhere.') break elseif set and cnt == 1 then -- To confirm, wait for two 1-candidate results in a row if found then - local addr = searcher:idx2addr(set[1]) + local addr = self:idx2addr(set[1]) print(string.format(' Confirmed address: %x\n', addr)) return addr, set[1] else @@ -416,4 +395,61 @@ function find_menu_cursor(searcher,prompt,data_type,choices,enum) end end +function DiffSearcher:find_menu_cursor(prompt,data_type,choices,enum) + enum = enum or {} + + return self:find_interactive( + prompt, data_type, + function(ccursor) + local choice + + -- Select the next value to search for + if type(choices) == 'function' then + choice = choices(ccursor) + + if not choice then + return false + end + else + choice = choices[(ccursor % #choices) + 1] + end + + -- Ask the user to select it + if enum ~= 'noprompt' then + local cname = enum[choice] or choice + if type(choice) == 'string' and type(cname) == 'number' then + choice, cname = cname, choice + end + if cname ~= choice then + cname = cname..' ('..choice..')' + end + + print(' Please select: '..cname) + if not utils.prompt_yes_no(' Continue?', true) then + return false + end + end + + return true, choice + end + ) +end + +function DiffSearcher:find_counter(prompt,data_type,delta,action_prompt) + delta = delta or 1 + + return self:find_interactive( + prompt, data_type, + function(ccursor) + if ccursor > 0 then + print(" "..(action_prompt or 'Please do the action.')) + end + if not utils.prompt_yes_no(' Continue?', true) then + return false + end + return true, nil, delta + end + ) +end + return _ENV diff --git a/library/lua/utils.lua b/library/lua/utils.lua index 4fac56ec..93ee840c 100644 --- a/library/lua/utils.lua +++ b/library/lua/utils.lua @@ -367,9 +367,9 @@ function prompt_yes_no(msg,default) if default == nil then prompt = prompt..' (y/n): ' elseif default then - prompt = prompt..' (y/n/enter=y): ' + prompt = prompt..' (y/n)[y]: ' else - prompt = prompt..' (y/n/enter=n): ' + prompt = prompt..' (y/n)[n]: ' end while true do local rv = dfhack.lineedit(prompt) @@ -378,6 +378,8 @@ function prompt_yes_no(msg,default) return true elseif string.match(rv,'^[Nn]') then return false + elseif rv == 'abort' then + error('User abort in utils.prompt_yes_no()') elseif rv == '' and default ~= nil then return default end -- cgit v1.2.1 From 40e764a46b4af3d0fe073a74421f8724a0c5d6a8 Mon Sep 17 00:00:00 2001 From: Timothy Collett Date: Tue, 19 Jun 2012 10:51:47 -0400 Subject: Some more tweaks to the memory-finding code --- library/Process-darwin.cpp | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) (limited to 'library') diff --git a/library/Process-darwin.cpp b/library/Process-darwin.cpp index d043e5b1..5a97d9e0 100644 --- a/library/Process-darwin.cpp +++ b/library/Process-darwin.cpp @@ -130,6 +130,16 @@ string Process::doReadClassName (void * vptr) #include #include +const char * +inheritance_strings[] = { + "SHARE", "COPY", "NONE", "DONATE_COPY", +}; + +const char * +behavior_strings[] = { + "DEFAULT", "RANDOM", "SEQUENTIAL", "RESQNTL", "WILLNEED", "DONTNEED", +}; + void Process::getMemRanges( vector & ranges ) { @@ -162,7 +172,7 @@ void Process::getMemRanges( vector & ranges ) int dlcheck; dlcheck = dladdr((const void*)address, &dlinfo); if (dlcheck==0) { - dlinfo.dli_fname = "(none)"; + dlinfo.dli_fname = ""; } t_memrange temp; @@ -177,20 +187,36 @@ void Process::getMemRanges( vector & ranges ) temp.valid = true; ranges.push_back(temp); + fprintf(stderr, + "%08x-%08x %8uK %c%c%c/%c%c%c %11s %6s %10s uwir=%hu sub=%u dlname: %s\n", + address, (address + vmsize), (vmsize >> 10), + (info.protection & VM_PROT_READ) ? 'r' : '-', + (info.protection & VM_PROT_WRITE) ? 'w' : '-', + (info.protection & VM_PROT_EXECUTE) ? 'x' : '-', + (info.max_protection & VM_PROT_READ) ? 'r' : '-', + (info.max_protection & VM_PROT_WRITE) ? 'w' : '-', + (info.max_protection & VM_PROT_EXECUTE) ? 'x' : '-', + inheritance_strings[info.inheritance], + (info.shared) ? "shared" : "-", + behavior_strings[info.behavior], + info.user_wired_count, + info.reserved, + dlinfo.dli_fname); + address += vmsize; } else if (kr != KERN_INVALID_ADDRESS) { - if (the_task != MACH_PORT_NULL) { + /*if (the_task != MACH_PORT_NULL) { mach_port_deallocate(mach_task_self(), the_task); - } + }*/ return; } } while (kr != KERN_INVALID_ADDRESS); - if (the_task != MACH_PORT_NULL) { +/* if (the_task != MACH_PORT_NULL) { mach_port_deallocate(mach_task_self(), the_task); - } + }*/ } uint32_t Process::getBase() -- cgit v1.2.1 From 707fcc55e5dcd480551eba7bcc287fae19408301 Mon Sep 17 00:00:00 2001 From: Timothy Collett Date: Tue, 19 Jun 2012 10:52:08 -0400 Subject: Update xml repo --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'library') diff --git a/library/xml b/library/xml index bc757db6..18c1d3e3 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit bc757db69514b54eb66d4d38e9cc1354d3761907 +Subproject commit 18c1d3e3d0185d0bf80161d1e8410f08dd46d1e1 -- cgit v1.2.1