From 7eb4fc19de542db0d3e271123f24773e0c8c481e Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Thu, 14 Jun 2012 12:46:12 +0400
Subject: [PATCH 01/14] Make dfhack.run_script usable from other scripts, and
document it.
---
LUA_API.rst | 12 ++++++++++++
Lua API.html | 10 ++++++++++
library/Core.cpp | 10 +++-------
library/lua/dfhack.lua | 13 +++++++++----
4 files changed, 34 insertions(+), 11 deletions(-)
diff --git a/LUA_API.rst b/LUA_API.rst
index f40b786d2..2859f8678 100644
--- a/LUA_API.rst
+++ b/LUA_API.rst
@@ -491,6 +491,13 @@ Currently it defines the following features:
Compares to coroutine.resume like dfhack.safecall vs pcall.
+* ``dfhack.run_script(name[,args...])``
+
+ Run a lua script in hack/scripts/, as if it was started from dfhack command-line.
+ The ``name`` argument should be the name stem, as would be used on the command line.
+ Note that the script is re-read from the file every time it is called, and errors
+ are propagated to the caller.
+
* ``dfhack.with_suspend(f[,args...])``
Calls ``f`` with arguments after grabbing the DF core suspend lock.
@@ -1148,6 +1155,11 @@ Internal API
These functions are intended for the use by dfhack developers,
and are only documented here for completeness:
+* ``dfhack.internal.scripts``
+
+ The table used by ``dfhack.run_script()`` to give every script its own
+ global environment, persistent between calls to the script.
+
* ``dfhack.internal.getAddress(name)``
Returns the global address ``name``, or *nil*.
diff --git a/Lua API.html b/Lua API.html
index 5574c55b8..047457985 100644
--- a/Lua API.html
+++ b/Lua API.html
@@ -766,6 +766,12 @@ returning. Intended as a convenience function.
dfhack.saferesume(coroutine[,args...])
Compares to coroutine.resume like dfhack.safecall vs pcall.
+dfhack.run_script(name[,args...])
+Run a lua script in hack/scripts/, as if it was started from dfhack command-line.
+The name argument should be the name stem, as would be used on the command line.
+Note that the script is re-read from the file every time it is called, and errors
+are propagated to the caller.
+
dfhack.with_suspend(f[,args...])
Calls f with arguments after grabbing the DF core suspend lock.
Suspending is necessary for accessing a consistent state of DF memory.
@@ -1310,6 +1316,10 @@ Returns true, was_only_planned if removed; or false if none fo
These functions are intended for the use by dfhack developers,
and are only documented here for completeness:
+dfhack.internal.scripts
+The table used by dfhack.run_script() to give every script its own
+global environment, persistent between calls to the script.
+
dfhack.internal.getAddress(name)
Returns the global address name, or nil.
diff --git a/library/Core.cpp b/library/Core.cpp
index 620fc81d2..a1090450f 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 926600c0f..4cdb4c950 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
From bbc1fb010ec16ea9260cfc6fe8cc122f79c2d0e6 Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Thu, 14 Jun 2012 13:08:39 +0400
Subject: [PATCH 02/14] 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(-)
diff --git a/library/Console-linux.cpp b/library/Console-linux.cpp
index a1ebfad36..6b4de736d 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 a1090450f..3a75991c1 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();
From 9469f275590e2aca9ce13358847bf16a5791a00c Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Thu, 14 Jun 2012 13:15:37 +0400
Subject: [PATCH 03/14] 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(-)
diff --git a/library/RemoteServer.cpp b/library/RemoteServer.cpp
index ed47890f7..53428f2bd 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;
From 94dfdb486d0a2bbc832f60fd58847732ac670390 Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Thu, 14 Jun 2012 20:32:23 +0400
Subject: [PATCH 04/14] 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(-)
diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp
index aa168db3a..59956a2c8 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);
From dc5bef2cb84cceb30179df750d986eecdef8b474 Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Sat, 16 Jun 2012 13:33:49 +0400
Subject: [PATCH 05/14] Add lua internal api functions needed for scanning
memory.
---
LUA_API.rst | 20 +++++++++
Lua API.html | 16 +++++++
library/LuaApi.cpp | 106 ++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 141 insertions(+), 1 deletion(-)
diff --git a/LUA_API.rst b/LUA_API.rst
index 2859f8678..f3d26eaca 100644
--- a/LUA_API.rst
+++ b/LUA_API.rst
@@ -1176,6 +1176,26 @@ and are only documented here for completeness:
Returns a sequence of tables describing virtual memory ranges of the process.
+* ``dfhack.internal.memmove(dest,src,count)``
+
+ Wraps the standard memmove function. Accepts both numbers and refs as pointers.
+
+* ``dfhack.internal.memcmp(ptr1,ptr2,count)``
+
+ Wraps the standard memcmp function.
+
+* ``dfhack.internal.memscan(haystack,count,step,needle,nsize)``
+
+ Searches for ``needle`` of ``nsize`` bytes in ``haystack``,
+ using ``count`` steps of ``step`` bytes.
+ Returns: *step_idx, sum_idx, found_ptr*, or *nil* if not found.
+
+* ``dfhack.internal.diffscan(old_data, new_data, start_idx, end_idx, eltsize[, oldval, newval, delta])``
+
+ Searches for differences between buffers at ptr1 and ptr2, as integers of size eltsize.
+ The oldval, newval or delta arguments may be used to specify additional constraints.
+ Returns: *found_index*, or *nil* if end reached.
+
Core interpreter context
========================
diff --git a/Lua API.html b/Lua API.html
index 047457985..90e612116 100644
--- a/Lua API.html
+++ b/Lua API.html
@@ -1332,6 +1332,22 @@ global environment, persistent between calls to the script.
dfhack.internal.getMemRanges()
Returns a sequence of tables describing virtual memory ranges of the process.
+dfhack.internal.memmove(dest,src,count)
+Wraps the standard memmove function. Accepts both numbers and refs as pointers.
+
+dfhack.internal.memcmp(ptr1,ptr2,count)
+Wraps the standard memcmp function.
+
+dfhack.internal.memscan(haystack,count,step,needle,nsize)
+Searches for needle of nsize bytes in haystack,
+using count steps of step bytes.
+Returns: step_idx, sum_idx, found_ptr, or nil if not found.
+
+dfhack.internal.diffscan(old_data, new_data, start_idx, end_idx, eltsize[, oldval, newval, delta])
+Searches for differences between buffers at ptr1 and ptr2, as integers of size eltsize.
+The oldval, newval or delta arguments may be used to specify additional constraints.
+Returns: found_index, or nil if end reached.
+
diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp
index 59956a2c8..50458f119 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 }
};
From db91850464a98e785ff53cfdc5df46b10229cfdb Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Sat, 16 Jun 2012 14:42:56 +0400
Subject: [PATCH 06/14] 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 +-
plugins/burrows.cpp | 4 +--
plugins/mode.cpp | 48 ++++++++++++++++-----------------
plugins/reveal.cpp | 10 +++----
plugins/seedwatch.cpp | 4 +--
8 files changed, 54 insertions(+), 71 deletions(-)
diff --git a/library/RemoteTools.cpp b/library/RemoteTools.cpp
index 689c783a8..95c495e93 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 81ebfbd60..8b0fe3f59 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 4b50b44ca..393e7cbfe 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 c38188466..bc757db69 160000
--- a/library/xml
+++ b/library/xml
@@ -1 +1 @@
-Subproject commit c381884664c71adefbec44258a734def2c88dacc
+Subproject commit bc757db69514b54eb66d4d38e9cc1354d3761907
diff --git a/plugins/burrows.cpp b/plugins/burrows.cpp
index 9ff902c3d..0b66a7b9a 100644
--- a/plugins/burrows.cpp
+++ b/plugins/burrows.cpp
@@ -101,8 +101,8 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan
switch (event) {
case SC_MAP_LOADED:
deinit_map(out);
- if (df::global::game_mode &&
- *df::global::game_mode == GAMEMODE_DWARF)
+ if (df::global::gamemode &&
+ *df::global::gamemode == game_mode::DWARF)
init_map(out);
break;
case SC_MAP_UNLOADED:
diff --git a/plugins/mode.cpp b/plugins/mode.cpp
index 33dd5875f..f9e6cd10c 100644
--- a/plugins/mode.cpp
+++ b/plugins/mode.cpp
@@ -10,7 +10,7 @@ using namespace std;
#include "modules/World.h"
#include
using namespace DFHack;
-
+using namespace df::enums;
command_result mode (color_ostream &out, vector & parameters);
@@ -44,28 +44,28 @@ void printCurrentModes(t_gamemodes gm, Console & con)
con << "Current game type:\t" << gm.g_type << " (";
switch(gm.g_type)
{
- case GAMETYPE_DWARF_MAIN:
+ case game_type::DWARF_MAIN:
con << "Fortress)" << endl;
break;
- case GAMETYPE_ADVENTURE_MAIN:
+ case game_type::ADVENTURE_MAIN:
con << "Adventurer)" << endl;
break;
- case GAMETYPE_VIEW_LEGENDS:
+ case game_type::VIEW_LEGENDS:
con << "Legends)" << endl;
break;
- case GAMETYPE_DWARF_RECLAIM:
+ case game_type::DWARF_RECLAIM:
con << "Reclaim)" << endl;
break;
- case GAMETYPE_DWARF_ARENA:
+ case game_type::DWARF_ARENA:
con << "Arena)" << endl;
break;
- case GAMETYPE_ADVENTURE_ARENA:
+ case game_type::ADVENTURE_ARENA:
con << "Arena - control creature)" << endl;
break;
- case GAMETYPENUM:
+ case game_type::num:
con << "INVALID)" << endl;
break;
- case GAMETYPE_NONE:
+ case game_type::NONE:
con << "NONE)" << endl;
break;
default:
@@ -75,16 +75,16 @@ void printCurrentModes(t_gamemodes gm, Console & con)
con << "Current game mode:\t" << gm.g_mode << " (";
switch (gm.g_mode)
{
- case GAMEMODE_DWARF:
+ case game_mode::DWARF:
con << "Dwarf)" << endl;
break;
- case GAMEMODE_ADVENTURE:
+ case game_mode::ADVENTURE:
con << "Adventure)" << endl;
break;
- case GAMEMODENUM:
+ case game_mode::num:
con << "INVALID)" << endl;
break;
- case GAMEMODE_NONE:
+ case game_mode::NONE:
con << "NONE)" << endl;
break;
default:
@@ -132,7 +132,7 @@ command_result mode (color_ostream &out_, vector & parameters)
{
if(!abuse)
{
- if( gm.g_mode == GAMEMODE_NONE || gm.g_type == GAMETYPE_VIEW_LEGENDS)
+ if( gm.g_mode == game_mode::NONE || gm.g_type == game_type::VIEW_LEGENDS)
{
out.printerr("It is not safe to set modes in menus.\n");
return CR_FAILURE;
@@ -163,24 +163,24 @@ command_result mode (color_ostream &out_, vector & parameters)
switch(select)
{
case 0:
- gm.g_mode = GAMEMODE_DWARF;
- gm.g_type = GAMETYPE_DWARF_MAIN;
+ gm.g_mode = game_mode::DWARF;
+ gm.g_type = game_type::DWARF_MAIN;
break;
case 1:
- gm.g_mode = GAMEMODE_ADVENTURE;
- gm.g_type = GAMETYPE_ADVENTURE_MAIN;
+ gm.g_mode = game_mode::ADVENTURE;
+ gm.g_type = game_type::ADVENTURE_MAIN;
break;
case 2:
- gm.g_mode = GAMEMODE_DWARF;
- gm.g_type = GAMETYPE_DWARF_ARENA;
+ gm.g_mode = game_mode::DWARF;
+ gm.g_type = game_type::DWARF_ARENA;
break;
case 3:
- gm.g_mode = GAMEMODE_ADVENTURE;
- gm.g_type = GAMETYPE_ADVENTURE_ARENA;
+ gm.g_mode = game_mode::ADVENTURE;
+ gm.g_type = game_type::ADVENTURE_ARENA;
break;
case 4:
- gm.g_mode = GAMEMODE_DWARF;
- gm.g_type = GAMETYPE_DWARF_RECLAIM;
+ gm.g_mode = game_mode::DWARF;
+ gm.g_type = game_type::DWARF_RECLAIM;
break;
}
}
diff --git a/plugins/reveal.cpp b/plugins/reveal.cpp
index 513eededb..f35424309 100644
--- a/plugins/reveal.cpp
+++ b/plugins/reveal.cpp
@@ -90,7 +90,7 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out )
World *World = Core::getInstance().getWorld();
t_gamemodes gm;
World->ReadGameMode(gm);
- if(gm.g_mode == GAMEMODE_DWARF)
+ if(gm.g_mode == game_mode::DWARF)
{
// if the map is revealed and we're in fortress mode, force the game to pause.
if(revealed == REVEALED)
@@ -193,12 +193,12 @@ command_result reveal(color_ostream &out, vector & params)
}
t_gamemodes gm;
World->ReadGameMode(gm);
- if(gm.g_mode == GAMEMODE_ADVENTURE)
+ if(gm.g_mode == game_mode::ADVENTURE)
{
revealAdventure(out);
return CR_OK;
}
- if(gm.g_mode != GAMEMODE_DWARF)
+ if(gm.g_mode != game_mode::DWARF)
{
con.printerr("Only in fortress mode.\n");
return CR_FAILURE;
@@ -272,7 +272,7 @@ command_result unreveal(color_ostream &out, vector & params)
}
t_gamemodes gm;
World->ReadGameMode(gm);
- if(gm.g_mode != GAMEMODE_DWARF)
+ if(gm.g_mode != game_mode::DWARF)
{
con.printerr("Only in fortress mode.\n");
return CR_FAILURE;
@@ -350,7 +350,7 @@ command_result revflood(color_ostream &out, vector & params)
}
t_gamemodes gm;
World->ReadGameMode(gm);
- if(gm.g_type != GAMETYPE_DWARF_MAIN && gm.g_mode != GAMEMODE_DWARF )
+ if(gm.g_type != game_type::DWARF_MAIN && gm.g_mode != game_mode::DWARF )
{
out.printerr("Only in proper dwarf mode.\n");
return CR_FAILURE;
diff --git a/plugins/seedwatch.cpp b/plugins/seedwatch.cpp
index b6097f628..ae9ff0e14 100755
--- a/plugins/seedwatch.cpp
+++ b/plugins/seedwatch.cpp
@@ -111,7 +111,7 @@ command_result df_seedwatch(color_ostream &out, vector& parameters)
w->ReadGameMode(gm);// FIXME: check return value
// if game mode isn't fortress mode
- if(gm.g_mode != GAMEMODE_DWARF || gm.g_type != GAMETYPE_DWARF_MAIN)
+ if(gm.g_mode != game_mode::DWARF || gm.g_type != game_type::DWARF_MAIN)
{
// just print the help
printHelp(out);
@@ -299,7 +299,7 @@ DFhackCExport command_result plugin_onupdate(color_ostream &out)
t_gamemodes gm;
w->ReadGameMode(gm);// FIXME: check return value
// if game mode isn't fortress mode
- if(gm.g_mode != GAMEMODE_DWARF || gm.g_type != GAMETYPE_DWARF_MAIN)
+ if(gm.g_mode != game_mode::DWARF || gm.g_type != game_type::DWARF_MAIN)
{
// stop running.
running = false;
From 927ce6ce5adf019fd4f5fe18024b4f1b4c17fc20 Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Sat, 16 Jun 2012 17:09:58 +0400
Subject: [PATCH 07/14] 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(-)
diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp
index 50458f119..cdfd47892 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 7c15a27aa..9f2fc2f16 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);
From 67536da2fe718b103f4200b95f00cd30000cb7ad Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Sat, 16 Jun 2012 19:51:15 +0400
Subject: [PATCH 08/14] Add an interactive script finding a limited subset of
linux offsets.
---
library/lua/memscan.lua | 419 +++++++++++++++++++++++++++++++++
library/lua/utils.lua | 44 ++++
scripts/devel/find-offsets.lua | 368 +++++++++++++++++++++++++++++
3 files changed, 831 insertions(+)
create mode 100644 library/lua/memscan.lua
create mode 100644 scripts/devel/find-offsets.lua
diff --git a/library/lua/memscan.lua b/library/lua/memscan.lua
new file mode 100644
index 000000000..e5a0c6f72
--- /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 e67801f4f..4fac56ece 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
diff --git a/scripts/devel/find-offsets.lua b/scripts/devel/find-offsets.lua
new file mode 100644
index 000000000..ef16026e3
--- /dev/null
+++ b/scripts/devel/find-offsets.lua
@@ -0,0 +1,368 @@
+-- Find some offsets for linux.
+
+local utils = require 'utils'
+local ms = require 'memscan'
+
+local scan_all = false
+local is_known = dfhack.internal.getAddress
+
+collectgarbage()
+
+print[[
+WARNING: THIS SCRIPT IS STRICTLY FOR DFHACK DEVELOPERS.
+
+Running this script on a new DF version will NOT
+MAKE IT RUN CORRECTLY if any data structures
+changed, thus possibly leading to CRASHES AND/OR
+PERMANENT SAVE CORRUPTION.
+
+This script should be initially started immediately
+after loading the game, WITHOUT first loading a world.
+It expects vanilla game configuration, without any
+custom tilesets or init file changes.
+]]
+
+if not utils.prompt_yes_no('Proceed?') then
+ return
+end
+
+-- Data segment location
+
+local data = ms.get_data_segment()
+if not data then
+ error('Could not find data segment')
+end
+
+print('Data section: '..tostring(data))
+if data.size < 5000000 then
+ error('Data segment too short.')
+end
+
+local searcher = ms.DiffSearcher.new(data)
+
+local function validate_offset(name,validator,addr,tname,...)
+ local obj = data:object_by_field(addr,tname,...)
+ if obj and not validator(obj) then
+ obj = nil
+ end
+ ms.found_offset(name,obj)
+end
+
+--
+-- Cursor group
+--
+
+local function find_cursor()
+ print('\nPlease navigate to the title screen to find cursor.')
+ if not utils.prompt_yes_no('Proceed?', true) then
+ return false
+ end
+
+ -- Unpadded version
+ local idx, addr = data.int32_t:find_one{
+ -30000, -30000, -30000,
+ -30000, -30000, -30000, -30000, -30000, -30000,
+ df.game_mode.NONE, df.game_type.NONE
+ }
+ if idx then
+ ms.found_offset('cursor', addr)
+ ms.found_offset('selection_rect', addr + 12)
+ ms.found_offset('gamemode', addr + 12 + 24)
+ ms.found_offset('gametype', addr + 12 + 24 + 4)
+ return true
+ end
+
+ -- Padded version
+ idx, addr = data.int32_t:find_one{
+ -30000, -30000, -30000, 0,
+ -30000, -30000, -30000, -30000, -30000, -30000, 0, 0,
+ df.game_mode.NONE, 0, 0, 0, df.game_type.NONE
+ }
+ if idx then
+ ms.found_offset('cursor', addr)
+ ms.found_offset('selection_rect', addr + 0x10)
+ ms.found_offset('gamemode', addr + 0x30)
+ ms.found_offset('gametype', addr + 0x40)
+ return true
+ end
+
+ dfhack.printerr('Could not find cursor.')
+ return false
+end
+
+if scan_all or not (
+ is_known 'cursor' and is_known 'selection_rect' and
+ is_known 'gamemode' and is_known 'gametype'
+) then
+ find_cursor()
+end
+
+--
+-- Announcements
+--
+
+local function find_announcements()
+ idx, addr = data.int32_t:find_one{
+ 25, 25, 31, 31, 24, 24, 40, 40, 40, 40, 40, 40, 40
+ }
+ if idx then
+ ms.found_offset('announcements', addr)
+ return
+ end
+
+ dfhack.printerr('Could not find announcements.')
+end
+
+if scan_all or not is_known 'announcements' then
+ find_announcements()
+end
+
+--
+-- d_init
+--
+
+local function is_valid_d_init(di)
+ if di.sky_tile ~= 178 then
+ print('Sky tile expected 178, found: '..di.sky_tile)
+ if not utils.prompt_yes_no('Ignore?') then
+ return false
+ end
+ end
+
+ local ann = is_known 'announcements'
+ local size,ptr = di:sizeof()
+ if ann and ptr+size ~= ann then
+ print('Announcements not immediately after d_init.')
+ if not utils.prompt_yes_no('Ignore?') then
+ return false
+ end
+ end
+
+ return true
+end
+
+local function find_d_init()
+ idx, addr = data.int16_t:find_one{
+ 1,0, 2,0, 5,0, 25,0, -- path_cost
+ 4,4, -- embark_rect
+ 20,1000,1000,1000,1000 -- store_dist
+ }
+ if idx then
+ validate_offset('d_init', is_valid_d_init, addr, df.d_init, 'path_cost')
+ return
+ end
+
+ dfhack.printerr('Could not find d_init')
+end
+
+if scan_all or not is_known 'd_init' then
+ find_d_init()
+end
+
+--
+-- World
+--
+
+local function is_valid_world(world)
+ if not ms.is_valid_vector(world.units.all, 4)
+ or not ms.is_valid_vector(world.units.bad, 4)
+ or not ms.is_valid_vector(world.history.figures, 4)
+ or not ms.is_valid_vector(world.cur_savegame.map_features, 4)
+ then
+ dfhack.printerr('Vector layout check failed.')
+ return false
+ end
+
+ if #world.units.all == 0 or #world.units.all ~= #world.units.bad then
+ print('Different or zero size of units.all and units.bad:'..#world.units.all..' vs '..#world.units.bad)
+ if not utils.prompt_yes_no('Ignore?') then
+ return false
+ end
+ end
+
+ return true
+end
+
+local function find_world()
+ local addr = ms.find_menu_cursor(
+ searcher, [[
+Searching for world. Please open the stockpile creation
+menu, and follow instructions below:]],
+ 'int32_t',
+ { 'Corpses', 'Refuse', 'Stone', 'Wood', 'Gems', 'Bars', 'Cloth', 'Leather', 'Ammo', 'Coins' },
+ df.stockpile_category
+ )
+ validate_offset('world', is_valid_world, addr, df.world, 'selected_stockpile_type')
+end
+
+if scan_all or not is_known 'world' then
+ find_world()
+end
+
+--
+-- UI
+--
+
+local function is_valid_ui(ui)
+ if not ms.is_valid_vector(ui.economic_stone, 1)
+ or not ms.is_valid_vector(ui.dipscripts, 4)
+ then
+ dfhack.printerr('Vector layout check failed.')
+ return false
+ end
+
+ if ui.follow_item ~= -1 or ui.follow_unit ~= -1 then
+ print('Invalid follow state: '..ui.follow_item..', '..ui.follow_unit)
+ return false
+ end
+
+ return true
+end
+
+local function find_ui()
+ local addr = ms.find_menu_cursor(
+ searcher, [[
+Searching for ui. Please open the designation
+menu, and follow instructions below:]],
+ 'int16_t',
+ { 'DesignateMine', 'DesignateChannel', 'DesignateRemoveRamps', 'DesignateUpStair',
+ 'DesignateDownStair', 'DesignateUpDownStair', 'DesignateUpRamp', 'DesignateChopTrees' },
+ df.ui_sidebar_mode
+ )
+ validate_offset('ui', is_valid_ui, addr, df.ui, 'main', 'mode')
+end
+
+if scan_all or not is_known 'ui' then
+ find_ui()
+end
+
+--
+-- ui_sidebar_menus
+--
+
+local function is_valid_ui_sidebar_menus(usm)
+ if not ms.is_valid_vector(usm.workshop_job.choices_all, 4)
+ or not ms.is_valid_vector(usm.workshop_job.choices_visible, 4)
+ then
+ dfhack.printerr('Vector layout check failed.')
+ return false
+ end
+
+ if #usm.workshop_job.choices_all == 0
+ or #usm.workshop_job.choices_all ~= #usm.workshop_job.choices_visible then
+ print('Different or zero size of visible and all choices:'..
+ #usm.workshop_job.choices_all..' vs '..#usm.workshop_job.choices_visible)
+ if not utils.prompt_yes_no('Ignore?') then
+ return false
+ end
+ end
+
+ return true
+end
+
+local function find_ui_sidebar_menus()
+ local addr = ms.find_menu_cursor(
+ searcher, [[
+Searching for ui_sidebar_menus. Please open the add job
+ui of Mason, Craftsdwarfs, or Carpenters workshop, and
+select entries in the list:]],
+ 'int32_t',
+ { 0, 1, 2, 3, 4, 5, 6 }
+ )
+ validate_offset('ui_sidebar_menus', is_valid_ui_sidebar_menus,
+ addr, df.ui_sidebar_menus, 'workshop_job', 'cursor')
+end
+
+if scan_all or not is_known 'ui_sidebar_menus' then
+ find_ui_sidebar_menus()
+end
+
+--
+-- ui_build_selector
+--
+
+local function is_valid_ui_build_selector(ubs)
+ if not ms.is_valid_vector(ubs.requirements, 4)
+ or not ms.is_valid_vector(ubs.choices, 4)
+ then
+ dfhack.printerr('Vector layout check failed.')
+ return false
+ end
+
+ if ubs.building_type ~= df.building_type.Trap
+ or ubs.building_subtype ~= df.trap_type.PressurePlate then
+ print('Invalid building type and subtype:'..ubs.building_type..','..ubs.building_subtype)
+ return false
+ end
+
+ return true
+end
+
+local function find_ui_build_selector()
+ local addr = ms.find_menu_cursor(
+ searcher, [[
+Searching for ui_build_selector. Please start constructing
+a pressure plate, and enable creatures. Then change the min
+weight as requested, remembering that the ui truncates the
+number, so when it shows "Min (5000df", it means 50000:]],
+ 'int32_t',
+ { 50000, 49000, 48000, 47000, 46000, 45000, 44000 }
+ )
+ validate_offset('ui_build_selector', is_valid_ui_build_selector,
+ addr, df.ui_build_selector, 'plate_info', 'unit_min')
+end
+
+if scan_all or not is_known 'ui_build_selector' then
+ find_ui_build_selector()
+end
+
+--
+-- ui_selected_unit
+--
+
+local function find_ui_selected_unit()
+ if not is_known 'world' then
+ dfhack.printerr('Cannot find ui_selected_unit: no world')
+ return
+ end
+
+ for i,unit in ipairs(df.global.world.units.active) do
+ dfhack.units.setNickname(unit, i)
+ end
+
+ local addr = ms.find_menu_cursor(
+ searcher, [[
+Searching for ui_selected_unit. Please activate the 'v'
+mode, point it at units, and enter their numeric nickname
+into the prompts below:]],
+ 'int32_t',
+ function()
+ return utils.prompt_input(' Enter index: ', utils.check_number)
+ end
+ )
+ ms.found_offset('ui_selected_unit', addr)
+end
+
+if scan_all or not is_known 'ui_selected_unit' then
+ find_ui_selected_unit()
+end
+
+--
+-- ui_unit_view_mode
+--
+
+local function find_ui_unit_view_mode()
+ local addr = ms.find_menu_cursor(
+ searcher, [[
+Searching for ui_unit_view_mode. Having selected a unit
+with 'v', switch the pages as requested:]],
+ 'int32_t',
+ { 'General', 'Inventory', 'Preferences', 'Wounds' },
+ df.ui_unit_view_mode.T_value
+ )
+ ms.found_offset('ui_unit_view_mode', addr)
+end
+
+if scan_all or not is_known 'ui_unit_view_mode' then
+ find_ui_unit_view_mode()
+end
From fa41a27f2643afe8c8b601aab3e2ab3b1403411d Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Sun, 17 Jun 2012 14:26:27 +0400
Subject: [PATCH 09/14] Add an api function to get vtable address from version
info.
---
LUA_API.rst | 4 ++++
Lua API.html | 3 +++
library/LuaApi.cpp | 12 ++++++++++++
3 files changed, 19 insertions(+)
diff --git a/LUA_API.rst b/LUA_API.rst
index f3d26eaca..1723711d3 100644
--- a/LUA_API.rst
+++ b/LUA_API.rst
@@ -1168,6 +1168,10 @@ and are only documented here for completeness:
Sets the global address ``name``. Returns the value of ``getAddress`` before the change.
+* ``dfhack.internal.getVTable(name)``
+
+ Returns the pre-extracted vtable address ``name``, or *nil*.
+
* ``dfhack.internal.getBase()``
Returns the base address of the process.
diff --git a/Lua API.html b/Lua API.html
index 90e612116..f1bdd17d2 100644
--- a/Lua API.html
+++ b/Lua API.html
@@ -1326,6 +1326,9 @@ global environment, persistent between calls to the script.
dfhack.internal.setAddress(name, value)
Sets the global address name. Returns the value of getAddress before the change.
+dfhack.internal.getVTable(name)
+Returns the pre-extracted vtable address name, or nil.
+
dfhack.internal.getBase()
Returns the base address of the process.
diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp
index cdfd47892..631b3c499 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 },
From 534367546d137998231ca95103c7ec0d260bdc13 Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Sun, 17 Jun 2012 15:59:03 +0400
Subject: [PATCH 10/14] Update to Lua 5.2.1
---
depends/lua/include/lfunc.h | 5 +-
depends/lua/include/lgc.h | 10 +-
depends/lua/include/llimits.h | 17 +-
depends/lua/include/lobject.h | 75 +++---
depends/lua/include/lparser.h | 6 +-
depends/lua/include/lstate.h | 20 +-
depends/lua/include/lstring.h | 17 +-
depends/lua/include/lua.h | 8 +-
depends/lua/include/luaconf.h | 125 ++++++----
depends/lua/include/lundump.h | 4 +-
depends/lua/src/lapi.c | 20 +-
depends/lua/src/lauxlib.c | 17 +-
depends/lua/src/lbaselib.c | 3 +-
depends/lua/src/lcorolib.c | 5 +-
depends/lua/src/ldblib.c | 21 +-
depends/lua/src/ldebug.c | 13 +-
depends/lua/src/ldo.c | 32 ++-
depends/lua/src/ldump.c | 7 +-
depends/lua/src/lfunc.c | 20 +-
depends/lua/src/lgc.c | 456 +++++++++++++++++++++-------------
depends/lua/src/llex.c | 27 +-
depends/lua/src/lmathlib.c | 12 +-
depends/lua/src/lmem.c | 18 +-
depends/lua/src/loadlib.c | 97 ++++----
depends/lua/src/lopcodes.c | 3 +-
depends/lua/src/loslib.c | 17 +-
depends/lua/src/lparser.c | 153 +++++++-----
depends/lua/src/lstate.c | 42 +++-
depends/lua/src/lstring.c | 115 +++++++--
depends/lua/src/lstrlib.c | 35 +--
depends/lua/src/ltable.c | 27 +-
depends/lua/src/lua.c | 31 +--
depends/lua/src/lundump.c | 38 ++-
depends/lua/src/lvm.c | 50 ++--
depends/lua/src/lzio.c | 4 +-
35 files changed, 935 insertions(+), 615 deletions(-)
diff --git a/depends/lua/include/lfunc.h b/depends/lua/include/lfunc.h
index da1892315..e236a717c 100644
--- a/depends/lua/include/lfunc.h
+++ b/depends/lua/include/lfunc.h
@@ -1,5 +1,5 @@
/*
-** $Id: lfunc.h,v 2.6 2010/06/04 13:06:15 roberto Exp $
+** $Id: lfunc.h,v 2.8 2012/05/08 13:53:33 roberto Exp $
** Auxiliary functions to manipulate prototypes and closures
** See Copyright Notice in lua.h
*/
@@ -20,12 +20,11 @@
LUAI_FUNC Proto *luaF_newproto (lua_State *L);
LUAI_FUNC Closure *luaF_newCclosure (lua_State *L, int nelems);
-LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, Proto *p);
+LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, int nelems);
LUAI_FUNC UpVal *luaF_newupval (lua_State *L);
LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
LUAI_FUNC void luaF_close (lua_State *L, StkId level);
LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
-LUAI_FUNC void luaF_freeclosure (lua_State *L, Closure *c);
LUAI_FUNC void luaF_freeupval (lua_State *L, UpVal *uv);
LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,
int pc);
diff --git a/depends/lua/include/lgc.h b/depends/lua/include/lgc.h
index aa5dfce21..bdd5cce6c 100644
--- a/depends/lua/include/lgc.h
+++ b/depends/lua/include/lgc.h
@@ -1,5 +1,5 @@
/*
-** $Id: lgc.h,v 2.52 2011/10/03 17:54:25 roberto Exp $
+** $Id: lgc.h,v 2.56 2012/05/23 15:43:14 roberto Exp $
** Garbage Collector
** See Copyright Notice in lua.h
*/
@@ -25,6 +25,14 @@
*/
+
+/* how much to allocate before next GC step */
+#if !defined(GCSTEPSIZE)
+/* ~100 small strings */
+#define GCSTEPSIZE (cast_int(100 * sizeof(TString)))
+#endif
+
+
/*
** Possible states of the Garbage Collector
*/
diff --git a/depends/lua/include/llimits.h b/depends/lua/include/llimits.h
index 48dc81f76..fc9de1a11 100644
--- a/depends/lua/include/llimits.h
+++ b/depends/lua/include/llimits.h
@@ -1,5 +1,5 @@
/*
-** $Id: llimits.h,v 1.95 2011/12/06 16:58:36 roberto Exp $
+** $Id: llimits.h,v 1.99 2012/05/28 20:32:28 roberto Exp $
** Limits, basic types, and some other `installation-dependent' definitions
** See Copyright Notice in lua.h
*/
@@ -31,6 +31,8 @@ typedef unsigned char lu_byte;
#define MAX_LUMEM ((lu_mem)(~(lu_mem)0)-2)
+#define MAX_LMEM ((l_mem) ((MAX_LUMEM >> 1) - 2))
+
#define MAX_INT (INT_MAX-2) /* maximum value of an int (-2 for safety) */
@@ -209,31 +211,36 @@ typedef lu_int32 Instruction;
#elif defined(LUA_IEEE754TRICK) /* }{ */
/* the next trick should work on any machine using IEEE754 with
- a 32-bit integer type */
+ a 32-bit int type */
union luai_Cast { double l_d; LUA_INT32 l_p[2]; };
#if !defined(LUA_IEEEENDIAN) /* { */
#define LUAI_EXTRAIEEE \
static const union luai_Cast ieeeendian = {-(33.0 + 6755399441055744.0)};
-#define LUA_IEEEENDIAN (ieeeendian.l_p[1] == 33)
+#define LUA_IEEEENDIANLOC (ieeeendian.l_p[1] == 33)
#else
+#define LUA_IEEEENDIANLOC LUA_IEEEENDIAN
#define LUAI_EXTRAIEEE /* empty */
#endif /* } */
#define lua_number2int32(i,n,t) \
{ LUAI_EXTRAIEEE \
volatile union luai_Cast u; u.l_d = (n) + 6755399441055744.0; \
- (i) = (t)u.l_p[LUA_IEEEENDIAN]; }
+ (i) = (t)u.l_p[LUA_IEEEENDIANLOC]; }
#define luai_hashnum(i,n) \
{ volatile union luai_Cast u; u.l_d = (n) + 1.0; /* avoid -0 */ \
(i) = u.l_p[0]; (i) += u.l_p[1]; } /* add double bits for his hash */
#define lua_number2int(i,n) lua_number2int32(i, n, int)
-#define lua_number2integer(i,n) lua_number2int32(i, n, lua_Integer)
#define lua_number2unsigned(i,n) lua_number2int32(i, n, lua_Unsigned)
+/* the trick can be expanded to lua_Integer when it is a 32-bit value */
+#if defined(LUA_IEEELL)
+#define lua_number2integer(i,n) lua_number2int32(i, n, lua_Integer)
+#endif
+
#endif /* } */
diff --git a/depends/lua/include/lobject.h b/depends/lua/include/lobject.h
index 06246bfa5..ca75a028c 100644
--- a/depends/lua/include/lobject.h
+++ b/depends/lua/include/lobject.h
@@ -1,5 +1,5 @@
/*
-** $Id: lobject.h,v 2.64 2011/10/31 17:48:22 roberto Exp $
+** $Id: lobject.h,v 2.70 2012/05/11 14:10:50 roberto Exp $
** Type definitions for Lua objects
** See Copyright Notice in lua.h
*/
@@ -36,6 +36,9 @@
** bit 6: whether value is collectable
*/
+#define VARBITS (3 << 4)
+
+
/*
** LUA_TFUNCTION variants:
** 0 - Lua function
@@ -49,6 +52,12 @@
#define LUA_TCCL (LUA_TFUNCTION | (2 << 4)) /* C closure */
+/*
+** LUA_TSTRING variants */
+#define LUA_TSHRSTR (LUA_TSTRING | (0 << 4)) /* short strings */
+#define LUA_TLNGSTR (LUA_TSTRING | (1 << 4)) /* long strings */
+
+
/* Bit mark for collectable types */
#define BIT_ISCOLLECTABLE (1 << 6)
@@ -109,23 +118,28 @@ typedef struct lua_TValue TValue;
/* raw type tag of a TValue */
#define rttype(o) ((o)->tt_)
+/* tag with no variants (bits 0-3) */
+#define novariant(x) ((x) & 0x0F)
+
/* type tag of a TValue (bits 0-3 for tags + variant bits 4-5) */
#define ttype(o) (rttype(o) & 0x3F)
-
/* type tag of a TValue with no variants (bits 0-3) */
-#define ttypenv(o) (rttype(o) & 0x0F)
+#define ttypenv(o) (novariant(rttype(o)))
/* Macros to test type */
#define checktag(o,t) (rttype(o) == (t))
+#define checktype(o,t) (ttypenv(o) == (t))
#define ttisnumber(o) checktag((o), LUA_TNUMBER)
#define ttisnil(o) checktag((o), LUA_TNIL)
#define ttisboolean(o) checktag((o), LUA_TBOOLEAN)
#define ttislightuserdata(o) checktag((o), LUA_TLIGHTUSERDATA)
-#define ttisstring(o) checktag((o), ctb(LUA_TSTRING))
+#define ttisstring(o) checktype((o), LUA_TSTRING)
+#define ttisshrstring(o) checktag((o), ctb(LUA_TSHRSTR))
+#define ttislngstring(o) checktag((o), ctb(LUA_TLNGSTR))
#define ttistable(o) checktag((o), ctb(LUA_TTABLE))
-#define ttisfunction(o) (ttypenv(o) == LUA_TFUNCTION)
+#define ttisfunction(o) checktype(o, LUA_TFUNCTION)
#define ttisclosure(o) ((rttype(o) & 0x1F) == LUA_TFUNCTION)
#define ttisCclosure(o) checktag((o), ctb(LUA_TCCL))
#define ttisLclosure(o) checktag((o), ctb(LUA_TLCL))
@@ -161,7 +175,7 @@ typedef struct lua_TValue TValue;
/* Macros for internal tests */
-#define righttt(obj) (ttypenv(obj) == gcvalue(obj)->gch.tt)
+#define righttt(obj) (ttype(obj) == gcvalue(obj)->gch.tt)
#define checkliveness(g,obj) \
lua_longassert(!iscollectable(obj) || \
@@ -193,7 +207,8 @@ typedef struct lua_TValue TValue;
#define setsvalue(L,obj,x) \
{ TValue *io=(obj); \
- val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TSTRING)); \
+ TString *x_ = (x); \
+ val_(io).gc=cast(GCObject *, x_); settt_(io, ctb(x_->tsv.tt)); \
checkliveness(G(L),io); }
#define setuvalue(L,obj,x) \
@@ -221,11 +236,6 @@ typedef struct lua_TValue TValue;
val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TTABLE)); \
checkliveness(G(L),io); }
-#define setptvalue(L,obj,x) \
- { TValue *io=(obj); \
- val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TPROTO)); \
- checkliveness(G(L),io); }
-
#define setdeadvalue(obj) settt_(obj, LUA_TDEADKEY)
@@ -256,6 +266,8 @@ typedef struct lua_TValue TValue;
#define setsvalue2n setsvalue
+/* check whether a number is valid (useful only for NaN trick) */
+#define luai_checknum(L,o,c) { /* empty */ }
/*
@@ -263,10 +275,7 @@ typedef struct lua_TValue TValue;
** NaN Trick
** =======================================================
*/
-
-#if defined(LUA_NANTRICK) \
- || defined(LUA_NANTRICK_LE) \
- || defined(LUA_NANTRICK_BE)
+#if defined(LUA_NANTRICK)
/*
** numbers are represented in the 'd_' field. All other values have the
@@ -274,15 +283,23 @@ typedef struct lua_TValue TValue;
** a "signaled NaN", which is never generated by regular operations by
** the CPU (nor by 'strtod')
*/
-#if !defined(NNMARK)
+
+/* allows for external implementation for part of the trick */
+#if !defined(NNMARK) /* { */
+
+
+#if !defined(LUA_IEEEENDIAN)
+#error option 'LUA_NANTRICK' needs 'LUA_IEEEENDIAN'
+#endif
+
+
#define NNMARK 0x7FF7A500
#define NNMASK 0x7FFFFF00
-#endif
#undef TValuefields
#undef NILCONSTANT
-#if defined(LUA_NANTRICK_LE)
+#if (LUA_IEEEENDIAN == 0) /* { */
/* little endian */
#define TValuefields \
@@ -293,7 +310,7 @@ typedef struct lua_TValue TValue;
#define d_(o) ((o)->u.d__)
#define tt_(o) ((o)->u.i.tt__)
-#elif defined(LUA_NANTRICK_BE)
+#else /* }{ */
/* big endian */
#define TValuefields \
@@ -304,10 +321,9 @@ typedef struct lua_TValue TValue;
#define d_(o) ((o)->u.d__)
#define tt_(o) ((o)->u.i.tt__)
-#elif !defined(TValuefields)
-#error option 'LUA_NANTRICK' needs declaration for 'TValuefields'
+#endif /* } */
-#endif
+#endif /* } */
/* correspondence with standard representation */
@@ -348,21 +364,18 @@ typedef struct lua_TValue TValue;
*/
#undef checktag
+#undef checktype
#define checktag(o,t) (tt_(o) == tag2tt(t))
+#define checktype(o,t) (ctb(tt_(o) | VARBITS) == ctb(tag2tt(t) | VARBITS))
#undef ttisequal
#define ttisequal(o1,o2) \
(ttisnumber(o1) ? ttisnumber(o2) : (tt_(o1) == tt_(o2)))
-
+#undef luai_checknum
#define luai_checknum(L,o,c) { if (!ttisnumber(o)) c; }
-
-#else
-
-#define luai_checknum(L,o,c) { /* empty */ }
-
#endif
/* }====================================================== */
@@ -401,7 +414,7 @@ typedef union TString {
L_Umaxalign dummy; /* ensures maximum alignment for strings */
struct {
CommonHeader;
- lu_byte reserved;
+ lu_byte extra; /* reserved words for short strings; "has hash" for longs */
unsigned int hash;
size_t len; /* number of characters in string */
} tsv;
@@ -501,7 +514,7 @@ typedef struct UpVal {
*/
#define ClosureHeader \
- CommonHeader; lu_byte isC; lu_byte nupvalues; GCObject *gclist
+ CommonHeader; lu_byte nupvalues; GCObject *gclist
typedef struct CClosure {
ClosureHeader;
diff --git a/depends/lua/include/lparser.h b/depends/lua/include/lparser.h
index caabf46cc..301167d4f 100644
--- a/depends/lua/include/lparser.h
+++ b/depends/lua/include/lparser.h
@@ -1,5 +1,5 @@
/*
-** $Id: lparser.h,v 1.69 2011/07/27 18:09:01 roberto Exp $
+** $Id: lparser.h,v 1.70 2012/05/08 13:53:33 roberto Exp $
** Lua Parser
** See Copyright Notice in lua.h
*/
@@ -112,8 +112,8 @@ typedef struct FuncState {
} FuncState;
-LUAI_FUNC Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
- Dyndata *dyd, const char *name, int firstchar);
+LUAI_FUNC Closure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
+ Dyndata *dyd, const char *name, int firstchar);
#endif
diff --git a/depends/lua/include/lstate.h b/depends/lua/include/lstate.h
index 4743d7410..29f810ba0 100644
--- a/depends/lua/include/lstate.h
+++ b/depends/lua/include/lstate.h
@@ -1,5 +1,5 @@
/*
-** $Id: lstate.h,v 2.74 2011/09/30 12:45:07 roberto Exp $
+** $Id: lstate.h,v 2.81 2012/06/08 15:14:04 roberto Exp $
** Global State
** See Copyright Notice in lua.h
*/
@@ -72,6 +72,7 @@ typedef struct CallInfo {
struct CallInfo *previous, *next; /* dynamic call link */
short nresults; /* expected number of results from this function */
lu_byte callstatus;
+ ptrdiff_t extra;
union {
struct { /* only for Lua functions */
StkId base; /* base for this function */
@@ -81,7 +82,6 @@ typedef struct CallInfo {
int ctx; /* context info. in case of yields */
lua_CFunction k; /* continuation in case of yields */
ptrdiff_t old_errfunc;
- ptrdiff_t extra;
lu_byte old_allowhook;
lu_byte status;
} c;
@@ -100,6 +100,7 @@ typedef struct CallInfo {
#define CIST_YPCALL (1<<4) /* call is a yieldable protected call */
#define CIST_STAT (1<<5) /* call has an error status (pcall) */
#define CIST_TAIL (1<<6) /* call was tail called */
+#define CIST_HOOKYIELD (1<<7) /* last hook called yielded */
#define isLua(ci) ((ci)->callstatus & CIST_LUA)
@@ -113,9 +114,11 @@ typedef struct global_State {
void *ud; /* auxiliary data to `frealloc' */
lu_mem totalbytes; /* number of bytes currently allocated - GCdebt */
l_mem GCdebt; /* bytes allocated not yet compensated by the collector */
- lu_mem lastmajormem; /* memory in use after last major collection */
+ lu_mem GCmemtrav; /* memory traversed by the GC */
+ lu_mem GCestimate; /* an estimate of the non-garbage memory in use */
stringtable strt; /* hash table for strings */
TValue l_registry;
+ unsigned int seed; /* randomized seed for hashes */
lu_byte currentwhite;
lu_byte gcstate; /* state of garbage collector */
lu_byte gckind; /* kind of GC running */
@@ -123,7 +126,8 @@ typedef struct global_State {
int sweepstrgc; /* position of sweep in `strt' */
GCObject *allgc; /* list of all collectable objects */
GCObject *finobj; /* list of collectable objects with finalizers */
- GCObject **sweepgc; /* current position of sweep */
+ GCObject **sweepgc; /* current position of sweep in list 'allgc' */
+ GCObject **sweepfin; /* current position of sweep in list 'finobj' */
GCObject *gray; /* list of gray objects */
GCObject *grayagain; /* list of objects to be traversed atomically */
GCObject *weak; /* list of tables with weak values */
@@ -193,11 +197,15 @@ union GCObject {
#define gch(o) (&(o)->gch)
/* macros to convert a GCObject into a specific value */
-#define rawgco2ts(o) check_exp((o)->gch.tt == LUA_TSTRING, &((o)->ts))
+#define rawgco2ts(o) \
+ check_exp(novariant((o)->gch.tt) == LUA_TSTRING, &((o)->ts))
#define gco2ts(o) (&rawgco2ts(o)->tsv)
#define rawgco2u(o) check_exp((o)->gch.tt == LUA_TUSERDATA, &((o)->u))
#define gco2u(o) (&rawgco2u(o)->uv)
-#define gco2cl(o) check_exp((o)->gch.tt == LUA_TFUNCTION, &((o)->cl))
+#define gco2lcl(o) check_exp((o)->gch.tt == LUA_TLCL, &((o)->cl.l))
+#define gco2ccl(o) check_exp((o)->gch.tt == LUA_TCCL, &((o)->cl.c))
+#define gco2cl(o) \
+ check_exp(novariant((o)->gch.tt) == LUA_TFUNCTION, &((o)->cl))
#define gco2t(o) check_exp((o)->gch.tt == LUA_TTABLE, &((o)->h))
#define gco2p(o) check_exp((o)->gch.tt == LUA_TPROTO, &((o)->p))
#define gco2uv(o) check_exp((o)->gch.tt == LUA_TUPVAL, &((o)->uv))
diff --git a/depends/lua/include/lstring.h b/depends/lua/include/lstring.h
index d708a1b09..d312ff3d2 100644
--- a/depends/lua/include/lstring.h
+++ b/depends/lua/include/lstring.h
@@ -1,5 +1,5 @@
/*
-** $Id: lstring.h,v 1.46 2010/04/05 16:26:37 roberto Exp $
+** $Id: lstring.h,v 1.49 2012/02/01 21:57:15 roberto Exp $
** String table (keep all strings handled by Lua)
** See Copyright Notice in lua.h
*/
@@ -23,11 +23,20 @@
/*
-** as all string are internalized, string equality becomes
-** pointer equality
+** test whether a string is a reserved word
*/
-#define eqstr(a,b) ((a) == (b))
+#define isreserved(s) ((s)->tsv.tt == LUA_TSHRSTR && (s)->tsv.extra > 0)
+
+/*
+** equality for short strings, which are always internalized
+*/
+#define eqshrstr(a,b) check_exp((a)->tsv.tt == LUA_TSHRSTR, (a) == (b))
+
+
+LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, unsigned int seed);
+LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b);
+LUAI_FUNC int luaS_eqstr (TString *a, TString *b);
LUAI_FUNC void luaS_resize (lua_State *L, int newsize);
LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s, Table *e);
LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l);
diff --git a/depends/lua/include/lua.h b/depends/lua/include/lua.h
index 1fafa45e4..a3a3a70c6 100644
--- a/depends/lua/include/lua.h
+++ b/depends/lua/include/lua.h
@@ -1,5 +1,5 @@
/*
-** $Id: lua.h,v 1.282 2011/11/29 15:55:08 roberto Exp $
+** $Id: lua.h,v 1.283 2012/04/20 13:18:26 roberto Exp $
** Lua - A Scripting Language
** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
** See Copyright Notice at the end of this file
@@ -19,11 +19,11 @@
#define LUA_VERSION_MAJOR "5"
#define LUA_VERSION_MINOR "2"
#define LUA_VERSION_NUM 502
-#define LUA_VERSION_RELEASE "0"
+#define LUA_VERSION_RELEASE "1"
#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
-#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2011 Lua.org, PUC-Rio"
+#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2012 Lua.org, PUC-Rio"
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
@@ -413,7 +413,7 @@ struct lua_Debug {
/******************************************************************************
-* Copyright (C) 1994-2011 Lua.org, PUC-Rio. All rights reserved.
+* Copyright (C) 1994-2012 Lua.org, PUC-Rio.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
diff --git a/depends/lua/include/luaconf.h b/depends/lua/include/luaconf.h
index fca66ce48..e4335df90 100644
--- a/depends/lua/include/luaconf.h
+++ b/depends/lua/include/luaconf.h
@@ -1,5 +1,5 @@
/*
-** $Id: luaconf.h,v 1.170 2011/12/06 16:58:36 roberto Exp $
+** $Id: luaconf.h,v 1.172 2012/05/11 14:14:42 roberto Exp $
** Configuration file for Lua
** See Copyright Notice in lua.h
*/
@@ -89,21 +89,25 @@
** In Windows, any exclamation mark ('!') in the path is replaced by the
** path of the directory of the executable file of the current process.
*/
-#define LUA_LDIR "!\\hack\\lua\\"
+#define LUA_LDIR "!\\lua\\"
#define LUA_CDIR "!\\"
#define LUA_PATH_DEFAULT \
- LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" ".\\?.lua"
+ LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \
+ LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua;" ".\\?.lua"
#define LUA_CPATH_DEFAULT \
- LUA_CDIR"?.dll;" ".\\?.dll"
+ LUA_CDIR"?.dll;" LUA_CDIR"loadall.dll;" ".\\?.dll"
#else /* }{ */
-#define LUA_LDIR "./hack/lua/"
-#define LUA_CDIR "./hack/"
+#define LUA_VDIR LUA_VERSION_MAJOR "." LUA_VERSION_MINOR "/"
+#define LUA_ROOT "/usr/local/"
+#define LUA_LDIR LUA_ROOT "share/lua/" LUA_VDIR
+#define LUA_CDIR LUA_ROOT "lib/lua/" LUA_VDIR
#define LUA_PATH_DEFAULT \
- LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" "./?.lua"
+ LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \
+ LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua;" "./?.lua"
#define LUA_CPATH_DEFAULT \
- LUA_CDIR"?.so;" "./?.so"
+ LUA_CDIR"?.so;" LUA_CDIR"loadall.so;" "./?.so"
#endif /* } */
@@ -138,15 +142,11 @@
*/
#if defined(LUA_BUILD_AS_DLL) /* { */
-#if defined(_MSC_VER)
#if defined(LUA_CORE) || defined(LUA_LIB) /* { */
#define LUA_API __declspec(dllexport)
#else /* }{ */
#define LUA_API __declspec(dllimport)
#endif /* } */
-#else
-#define LUA_API __attribute__ ((visibility("default")))
-#endif
#else /* }{ */
@@ -223,6 +223,13 @@
(fprintf(stderr, (s), (p)), fflush(stderr))
+/*
+@@ LUAI_MAXSHORTLEN is the maximum length for short strings, that is,
+** strings that are internalized. (Cannot be smaller than reserved words
+** or tags for metamethods, as these strings must be internalized;
+** #("function") = 8, #("__newindex") = 10.)
+*/
+#define LUAI_MAXSHORTLEN 40
@@ -453,66 +460,76 @@
#define LUA_UNSIGNED unsigned LUA_INT32
-#if defined(LUA_CORE) /* { */
-#if defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) /* { */
+/*
+** Some tricks with doubles
+*/
+
+#if defined(LUA_CORE) && \
+ defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) /* { */
+/*
+** The next definitions activate some tricks to speed up the
+** conversion from doubles to integer types, mainly to LUA_UNSIGNED.
+**
+@@ MS_ASMTRICK uses Microsoft assembler to avoid clashes with a
+** DirectX idiosyncrasy.
+**
+@@ LUA_IEEE754TRICK uses a trick that should work on any machine
+** using IEEE754 with a 32-bit integer type.
+**
+@@ LUA_IEEELL extends the trick to LUA_INTEGER; should only be
+** defined when LUA_INTEGER is a 32-bit integer.
+**
+@@ LUA_IEEEENDIAN is the endianness of doubles in your machine
+** (0 for little endian, 1 for big endian); if not defined, Lua will
+** check it dynamically for LUA_IEEE754TRICK (but not for LUA_NANTRICK).
+**
+@@ LUA_NANTRICK controls the use of a trick to pack all types into
+** a single double value, using NaN values to represent non-number
+** values. The trick only works on 32-bit machines (ints and pointers
+** are 32-bit values) with numbers represented as IEEE 754-2008 doubles
+** with conventional endianess (12345678 or 87654321), in CPUs that do
+** not produce signaling NaN values (all NaNs are quiet).
+*/
-/* On a Microsoft compiler on a Pentium, use assembler to avoid clashes
- with a DirectX idiosyncrasy */
+/* Microsoft compiler on a Pentium (32 bit) ? */
#if defined(LUA_WIN) && defined(_MSC_VER) && defined(_M_IX86) /* { */
#define MS_ASMTRICK
+#define LUA_IEEEENDIAN 0
+#define LUA_NANTRICK
-#else /* }{ */
-/* the next definition uses a trick that should work on any machine
- using IEEE754 with a 32-bit integer type */
-
-#define LUA_IEEE754TRICK
-
-/*
-@@ LUA_IEEEENDIAN is the endianness of doubles in your machine
-** (0 for little endian, 1 for big endian); if not defined, Lua will
-** check it dynamically.
-*/
-/* check for known architectures */
-#if defined(__i386__) || defined(__i386) || defined(__X86__) || \
- defined (__x86_64)
-#define LUA_IEEEENDIAN 0
-#elif defined(__POWERPC__) || defined(__ppc__)
-#define LUA_IEEEENDIAN 1
-#endif
-#endif /* } */
+/* pentium 32 bits? */
+#elif defined(__i386__) || defined(__i386) || defined(__X86__) /* }{ */
-#endif /* } */
+#define LUA_IEEE754TRICK
+#define LUA_IEEELL
+#define LUA_IEEEENDIAN 0
+#define LUA_NANTRICK
-#endif /* } */
+/* pentium 64 bits? */
+#elif defined(__x86_64) /* }{ */
-/* }================================================================== */
+#define LUA_IEEE754TRICK
+#define LUA_IEEEENDIAN 0
+#elif defined(__POWERPC__) || defined(__ppc__) /* }{ */
-/*
-@@ LUA_NANTRICK_LE/LUA_NANTRICK_BE controls the use of a trick to
-** pack all types into a single double value, using NaN values to
-** represent non-number values. The trick only works on 32-bit machines
-** (ints and pointers are 32-bit values) with numbers represented as
-** IEEE 754-2008 doubles with conventional endianess (12345678 or
-** 87654321), in CPUs that do not produce signaling NaN values (all NaNs
-** are quiet).
-*/
-#if defined(LUA_CORE) && \
- defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) /* { */
+#define LUA_IEEE754TRICK
+#define LUA_IEEEENDIAN 1
-/* little-endian architectures that satisfy those conditions */
-#if defined(__i386__) || defined(__i386) || defined(__X86__) || \
- defined(_M_IX86)
+#else /* }{ */
-#define LUA_NANTRICK_LE
+/* assume IEEE754 and a 32-bit integer type */
+#define LUA_IEEE754TRICK
-#endif
+#endif /* } */
#endif /* } */
+/* }================================================================== */
+
diff --git a/depends/lua/include/lundump.h b/depends/lua/include/lundump.h
index b63993ffe..2b8accecb 100644
--- a/depends/lua/include/lundump.h
+++ b/depends/lua/include/lundump.h
@@ -1,5 +1,5 @@
/*
-** $Id: lundump.h,v 1.44 2011/05/06 13:35:17 lhf Exp $
+** $Id: lundump.h,v 1.39 2012/05/08 13:53:33 roberto Exp $
** load precompiled Lua chunks
** See Copyright Notice in lua.h
*/
@@ -11,7 +11,7 @@
#include "lzio.h"
/* load one chunk; from lundump.c */
-LUAI_FUNC Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name);
+LUAI_FUNC Closure* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name);
/* make header; from lundump.c */
LUAI_FUNC void luaU_header (lu_byte* h);
diff --git a/depends/lua/src/lapi.c b/depends/lua/src/lapi.c
index e96ceb9e1..1854fe615 100644
--- a/depends/lua/src/lapi.c
+++ b/depends/lua/src/lapi.c
@@ -1,5 +1,5 @@
/*
-** $Id: lapi.c,v 2.159 2011/11/30 12:32:05 roberto Exp $
+** $Id: lapi.c,v 2.164 2012/06/08 15:14:04 roberto Exp $
** Lua API
** See Copyright Notice in lua.h
*/
@@ -950,7 +950,7 @@ LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc,
ci->u.c.k = k; /* save continuation */
ci->u.c.ctx = ctx; /* save context */
/* save information for error recovery */
- ci->u.c.extra = savestack(L, c.func);
+ ci->extra = savestack(L, c.func);
ci->u.c.old_allowhook = L->allowhook;
ci->u.c.old_errfunc = L->errfunc;
L->errfunc = func;
@@ -1045,17 +1045,17 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
}
case LUA_GCSTEP: {
if (g->gckind == KGC_GEN) { /* generational mode? */
- res = (g->lastmajormem == 0); /* 1 if will do major collection */
+ res = (g->GCestimate == 0); /* true if it will do major collection */
luaC_forcestep(L); /* do a single step */
}
else {
- while (data-- >= 0) {
- luaC_forcestep(L);
- if (g->gcstate == GCSpause) { /* end of cycle? */
- res = 1; /* signal it */
- break;
- }
- }
+ lu_mem debt = cast(lu_mem, data) * 1024 - GCSTEPSIZE;
+ if (g->gcrunning)
+ debt += g->GCdebt; /* include current debt */
+ luaE_setdebt(g, debt);
+ luaC_forcestep(L);
+ if (g->gcstate == GCSpause) /* end of cycle? */
+ res = 1; /* signal it */
}
break;
}
diff --git a/depends/lua/src/lauxlib.c b/depends/lua/src/lauxlib.c
index c1b715f34..36ae7e629 100644
--- a/depends/lua/src/lauxlib.c
+++ b/depends/lua/src/lauxlib.c
@@ -1,5 +1,5 @@
/*
-** $Id: lauxlib.c,v 1.240 2011/12/06 16:33:55 roberto Exp $
+** $Id: lauxlib.c,v 1.244 2012/05/31 20:28:45 roberto Exp $
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
@@ -520,11 +520,11 @@ LUALIB_API char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz) {
LUALIB_API int luaL_ref (lua_State *L, int t) {
int ref;
- t = lua_absindex(L, t);
if (lua_isnil(L, -1)) {
lua_pop(L, 1); /* remove from stack */
return LUA_REFNIL; /* `nil' has a unique fixed reference */
}
+ t = lua_absindex(L, t);
lua_rawgeti(L, t, freelist); /* get first free element */
ref = (int)lua_tointeger(L, -1); /* ref = t[freelist] */
lua_pop(L, 1); /* remove it from stack */
@@ -616,8 +616,10 @@ static int skipBOM (LoadF *lf) {
static int skipcomment (LoadF *lf, int *cp) {
int c = *cp = skipBOM(lf);
if (c == '#') { /* first line is a comment (Unix exec. file)? */
- while ((c = getc(lf->f)) != EOF && c != '\n') ; /* skip first line */
- *cp = getc(lf->f); /* skip end-of-line */
+ do { /* skip first line */
+ c = getc(lf->f);
+ } while (c != EOF && c != '\n') ;
+ *cp = getc(lf->f); /* skip end-of-line, if present */
return 1; /* there was a comment */
}
else return 0; /* no comment */
@@ -843,6 +845,7 @@ LUALIB_API void luaL_openlib (lua_State *L, const char *libname,
** Returns with only the table at the stack.
*/
LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
+ luaL_checkversion(L);
luaL_checkstack(L, nup, "too many upvalues");
for (; l->name != NULL; l++) { /* fill the table with given functions */
int i;
@@ -889,10 +892,8 @@ LUALIB_API void luaL_requiref (lua_State *L, const char *modname,
lua_setfield(L, -2, modname); /* _LOADED[modname] = module */
lua_pop(L, 1); /* remove _LOADED table */
if (glb) {
- lua_pushglobaltable(L);
- lua_pushvalue(L, -2); /* copy of 'mod' */
- lua_setfield(L, -2, modname); /* _G[modname] = module */
- lua_pop(L, 1); /* remove _G table */
+ lua_pushvalue(L, -1); /* copy of 'mod' */
+ lua_setglobal(L, modname); /* _G[modname] = module */
}
}
diff --git a/depends/lua/src/lbaselib.c b/depends/lua/src/lbaselib.c
index 1dfae3014..dbfcb02cf 100644
--- a/depends/lua/src/lbaselib.c
+++ b/depends/lua/src/lbaselib.c
@@ -1,5 +1,5 @@
/*
-** $Id: lbaselib.c,v 1.273 2011/11/30 13:03:24 roberto Exp $
+** $Id: lbaselib.c,v 1.274 2012/04/27 14:13:19 roberto Exp $
** Basic library
** See Copyright Notice in lua.h
*/
@@ -293,6 +293,7 @@ static const char *generic_reader (lua_State *L, void *ud, size_t *size) {
lua_pushvalue(L, 1); /* get function */
lua_call(L, 0, 1); /* call it */
if (lua_isnil(L, -1)) {
+ lua_pop(L, 1); /* pop result */
*size = 0;
return NULL;
}
diff --git a/depends/lua/src/lcorolib.c b/depends/lua/src/lcorolib.c
index 0edde26da..c7932d90f 100644
--- a/depends/lua/src/lcorolib.c
+++ b/depends/lua/src/lcorolib.c
@@ -1,5 +1,5 @@
/*
-** $Id: lcorolib.c,v 1.3 2011/08/23 17:24:34 roberto Exp $
+** $Id: lcorolib.c,v 1.4 2012/04/27 18:59:04 roberto Exp $
** Coroutine Library
** See Copyright Notice in lua.h
*/
@@ -80,8 +80,9 @@ static int luaB_auxwrap (lua_State *L) {
static int luaB_cocreate (lua_State *L) {
- lua_State *NL = lua_newthread(L);
+ lua_State *NL;
luaL_checktype(L, 1, LUA_TFUNCTION);
+ NL = lua_newthread(L);
lua_pushvalue(L, 1); /* move function to top */
lua_xmove(L, NL, 1); /* move function from L to NL */
return 1;
diff --git a/depends/lua/src/ldblib.c b/depends/lua/src/ldblib.c
index 3c2f15957..c02269457 100644
--- a/depends/lua/src/ldblib.c
+++ b/depends/lua/src/ldblib.c
@@ -1,5 +1,5 @@
/*
-** $Id: ldblib.c,v 1.131 2011/10/24 14:54:05 roberto Exp $
+** $Id: ldblib.c,v 1.132 2012/01/19 20:14:44 roberto Exp $
** Interface from Lua to its debug API
** See Copyright Notice in lua.h
*/
@@ -253,14 +253,15 @@ static int db_upvaluejoin (lua_State *L) {
}
-#define gethooktable(L) luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY);
+#define gethooktable(L) luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY)
static void hookf (lua_State *L, lua_Debug *ar) {
static const char *const hooknames[] =
{"call", "return", "line", "count", "tail call"};
gethooktable(L);
- lua_rawgetp(L, -1, L);
+ lua_pushthread(L);
+ lua_rawget(L, -2);
if (lua_isfunction(L, -1)) {
lua_pushstring(L, hooknames[(int)ar->event]);
if (ar->currentline >= 0)
@@ -306,10 +307,15 @@ static int db_sethook (lua_State *L) {
count = luaL_optint(L, arg+3, 0);
func = hookf; mask = makemask(smask, count);
}
- gethooktable(L);
+ if (gethooktable(L) == 0) { /* creating hook table? */
+ lua_pushstring(L, "k");
+ lua_setfield(L, -2, "__mode"); /** hooktable.__mode = "k" */
+ lua_pushvalue(L, -1);
+ lua_setmetatable(L, -2); /* setmetatable(hooktable) = hooktable */
+ }
+ lua_pushthread(L1); lua_xmove(L1, L, 1);
lua_pushvalue(L, arg+1);
- lua_rawsetp(L, -2, L1); /* set new hook */
- lua_pop(L, 1); /* remove hook table */
+ lua_rawset(L, -3); /* set new hook */
lua_sethook(L1, func, mask, count); /* set hooks */
return 0;
}
@@ -325,7 +331,8 @@ static int db_gethook (lua_State *L) {
lua_pushliteral(L, "external hook");
else {
gethooktable(L);
- lua_rawgetp(L, -1, L1); /* get hook */
+ lua_pushthread(L1); lua_xmove(L1, L, 1);
+ lua_rawget(L, -2); /* get hook */
lua_remove(L, -2); /* remove hook table */
}
lua_pushstring(L, unmakemask(mask, buff));
diff --git a/depends/lua/src/ldebug.c b/depends/lua/src/ldebug.c
index 31b7ae401..43f8f046f 100644
--- a/depends/lua/src/ldebug.c
+++ b/depends/lua/src/ldebug.c
@@ -1,5 +1,5 @@
/*
-** $Id: ldebug.c,v 2.88 2011/11/30 12:43:51 roberto Exp $
+** $Id: ldebug.c,v 2.89 2012/01/20 22:05:50 roberto Exp $
** Debug Interface
** See Copyright Notice in lua.h
*/
@@ -30,6 +30,9 @@
+#define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_TCCL)
+
+
static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name);
@@ -173,7 +176,7 @@ LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
static void funcinfo (lua_Debug *ar, Closure *cl) {
- if (cl == NULL || cl->c.isC) {
+ if (noLuaClosure(cl)) {
ar->source = "=[C]";
ar->linedefined = -1;
ar->lastlinedefined = -1;
@@ -191,7 +194,7 @@ static void funcinfo (lua_Debug *ar, Closure *cl) {
static void collectvalidlines (lua_State *L, Closure *f) {
- if (f == NULL || f->c.isC) {
+ if (noLuaClosure(f)) {
setnilvalue(L->top);
incr_top(L);
}
@@ -210,7 +213,7 @@ static void collectvalidlines (lua_State *L, Closure *f) {
static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
- Closure *f, CallInfo *ci) {
+ Closure *f, CallInfo *ci) {
int status = 1;
for (; *what; what++) {
switch (*what) {
@@ -224,7 +227,7 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
}
case 'u': {
ar->nups = (f == NULL) ? 0 : f->c.nupvalues;
- if (f == NULL || f->c.isC) {
+ if (noLuaClosure(f)) {
ar->isvararg = 1;
ar->nparams = 0;
}
diff --git a/depends/lua/src/ldo.c b/depends/lua/src/ldo.c
index e0f13c44e..d18e33cd4 100644
--- a/depends/lua/src/ldo.c
+++ b/depends/lua/src/ldo.c
@@ -1,5 +1,5 @@
/*
-** $Id: ldo.c,v 2.102 2011/11/29 15:55:08 roberto Exp $
+** $Id: ldo.c,v 2.105 2012/06/08 15:14:04 roberto Exp $
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/
@@ -402,8 +402,6 @@ static void finishCcall (lua_State *L) {
int n;
lua_assert(ci->u.c.k != NULL); /* must have a continuation */
lua_assert(L->nny == 0);
- /* finish 'luaD_call' */
- //L->nCcalls--;
/* finish 'lua_callk' */
adjustresults(L, ci->nresults);
/* call continuation function */
@@ -453,7 +451,7 @@ static int recover (lua_State *L, int status) {
CallInfo *ci = findpcall(L);
if (ci == NULL) return 0; /* no recovery point */
/* "finish" luaD_pcall */
- oldtop = restorestack(L, ci->u.c.extra);
+ oldtop = restorestack(L, ci->extra);
luaF_close(L, oldtop);
seterrorobj(L, status, oldtop);
L->ci = ci;
@@ -484,9 +482,10 @@ static l_noret resume_error (lua_State *L, const char *msg, StkId firstArg) {
** do the work for 'lua_resume' in protected mode
*/
static void resume (lua_State *L, void *ud) {
+ int nCcalls = L->nCcalls;
StkId firstArg = cast(StkId, ud);
CallInfo *ci = L->ci;
- if (L->nCcalls >= LUAI_MAXCCALLS)
+ if (nCcalls >= LUAI_MAXCCALLS)
resume_error(L, "C stack overflow", firstArg);
if (L->status == LUA_OK) { /* may be starting a coroutine */
if (ci != &L->base_ci) /* not in base level? */
@@ -499,10 +498,10 @@ static void resume (lua_State *L, void *ud) {
resume_error(L, "cannot resume dead coroutine", firstArg);
else { /* resuming from previous yield */
L->status = LUA_OK;
+ ci->func = restorestack(L, ci->extra);
if (isLua(ci)) /* yielded inside a hook? */
luaV_execute(L); /* just continue running Lua code */
else { /* 'common' yield */
- ci->func = restorestack(L, ci->u.c.extra);
if (ci->u.c.k != NULL) { /* does it have a continuation? */
int n;
ci->u.c.status = LUA_YIELD; /* 'default' status */
@@ -513,11 +512,11 @@ static void resume (lua_State *L, void *ud) {
api_checknelems(L, n);
firstArg = L->top - n; /* yield results come from continuation */
}
- //L->nCcalls--; /* finish 'luaD_call' */
luaD_poscall(L, firstArg); /* finish 'luaD_precall' */
}
unroll(L, NULL);
}
+ lua_assert(nCcalls == L->nCcalls);
}
@@ -564,13 +563,13 @@ LUA_API int lua_yieldk (lua_State *L, int nresults, int ctx, lua_CFunction k) {
luaG_runerror(L, "attempt to yield from outside a coroutine");
}
L->status = LUA_YIELD;
+ ci->extra = savestack(L, ci->func); /* save current 'func' */
if (isLua(ci)) { /* inside a hook? */
api_check(L, k == NULL, "hooks cannot continue after yielding");
}
else {
if ((ci->u.c.k = k) != NULL) /* is there a continuation? */
ci->u.c.ctx = ctx; /* save context */
- ci->u.c.extra = savestack(L, ci->func); /* save current 'func' */
ci->func = L->top - nresults - 1; /* protect stack below results */
luaD_throw(L, LUA_YIELD);
}
@@ -627,24 +626,23 @@ static void checkmode (lua_State *L, const char *mode, const char *x) {
static void f_parser (lua_State *L, void *ud) {
int i;
- Proto *tf;
Closure *cl;
struct SParser *p = cast(struct SParser *, ud);
int c = zgetc(p->z); /* read first character */
if (c == LUA_SIGNATURE[0]) {
checkmode(L, p->mode, "binary");
- tf = luaU_undump(L, p->z, &p->buff, p->name);
+ cl = luaU_undump(L, p->z, &p->buff, p->name);
}
else {
checkmode(L, p->mode, "text");
- tf = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c);
+ cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c);
+ }
+ lua_assert(cl->l.nupvalues == cl->l.p->sizeupvalues);
+ for (i = 0; i < cl->l.nupvalues; i++) { /* initialize upvalues */
+ UpVal *up = luaF_newupval(L);
+ cl->l.upvals[i] = up;
+ luaC_objbarrier(L, cl, up);
}
- setptvalue2s(L, L->top, tf);
- incr_top(L);
- cl = luaF_newLclosure(L, tf);
- setclLvalue(L, L->top - 1, cl);
- for (i = 0; i < tf->sizeupvalues; i++) /* initialize upvalues */
- cl->l.upvals[i] = luaF_newupval(L);
}
diff --git a/depends/lua/src/ldump.c b/depends/lua/src/ldump.c
index 699e1dc4e..d5e6a47cb 100644
--- a/depends/lua/src/ldump.c
+++ b/depends/lua/src/ldump.c
@@ -1,5 +1,5 @@
/*
-** $Id: ldump.c,v 1.19 2011/11/23 17:48:18 lhf Exp $
+** $Id: ldump.c,v 2.17 2012/01/23 23:02:10 roberto Exp $
** save precompiled Lua chunks
** See Copyright Notice in lua.h
*/
@@ -84,8 +84,8 @@ static void DumpConstants(const Proto* f, DumpState* D)
for (i=0; ik[i];
- DumpChar(ttype(o),D);
- switch (ttype(o))
+ DumpChar(ttypenv(o),D);
+ switch (ttypenv(o))
{
case LUA_TNIL:
break;
@@ -98,6 +98,7 @@ static void DumpConstants(const Proto* f, DumpState* D)
case LUA_TSTRING:
DumpString(rawtsvalue(o),D);
break;
+ default: lua_assert(0);
}
}
n=f->sizep;
diff --git a/depends/lua/src/lfunc.c b/depends/lua/src/lfunc.c
index 1a1a8bb8b..4fd27fe5e 100644
--- a/depends/lua/src/lfunc.c
+++ b/depends/lua/src/lfunc.c
@@ -1,5 +1,5 @@
/*
-** $Id: lfunc.c,v 2.27 2010/06/30 14:11:17 roberto Exp $
+** $Id: lfunc.c,v 2.29 2012/05/08 13:53:33 roberto Exp $
** Auxiliary functions to manipulate prototypes and closures
** See Copyright Notice in lua.h
*/
@@ -21,18 +21,15 @@
Closure *luaF_newCclosure (lua_State *L, int n) {
- Closure *c = &luaC_newobj(L, LUA_TFUNCTION, sizeCclosure(n), NULL, 0)->cl;
- c->c.isC = 1;
+ Closure *c = &luaC_newobj(L, LUA_TCCL, sizeCclosure(n), NULL, 0)->cl;
c->c.nupvalues = cast_byte(n);
return c;
}
-Closure *luaF_newLclosure (lua_State *L, Proto *p) {
- int n = p->sizeupvalues;
- Closure *c = &luaC_newobj(L, LUA_TFUNCTION, sizeLclosure(n), NULL, 0)->cl;
- c->l.isC = 0;
- c->l.p = p;
+Closure *luaF_newLclosure (lua_State *L, int n) {
+ Closure *c = &luaC_newobj(L, LUA_TLCL, sizeLclosure(n), NULL, 0)->cl;
+ c->l.p = NULL;
c->l.nupvalues = cast_byte(n);
while (n--) c->l.upvals[n] = NULL;
return c;
@@ -146,13 +143,6 @@ void luaF_freeproto (lua_State *L, Proto *f) {
}
-void luaF_freeclosure (lua_State *L, Closure *c) {
- int size = (c->c.isC) ? sizeCclosure(c->c.nupvalues) :
- sizeLclosure(c->l.nupvalues);
- luaM_freemem(L, c, size);
-}
-
-
/*
** Look for n-th local variable at line `line' in function `func'.
** Returns NULL if not found.
diff --git a/depends/lua/src/lgc.c b/depends/lua/src/lgc.c
index cdd92e524..06f972a72 100644
--- a/depends/lua/src/lgc.c
+++ b/depends/lua/src/lgc.c
@@ -1,5 +1,5 @@
/*
-** $Id: lgc.c,v 2.116 2011/12/02 13:18:41 roberto Exp $
+** $Id: lgc.c,v 2.133 2012/05/31 21:28:59 roberto Exp $
** Garbage Collector
** See Copyright Notice in lua.h
*/
@@ -24,34 +24,40 @@
-/* how much to allocate before next GC step */
-#define GCSTEPSIZE 1024
+/*
+** cost of sweeping one element (the size of a small object divided
+** by some adjust for the sweep speed)
+*/
+#define GCSWEEPCOST ((sizeof(TString) + 4) / 4)
/* maximum number of elements to sweep in each single step */
-#define GCSWEEPMAX 40
-
-/* cost of sweeping one element */
-#define GCSWEEPCOST 1
+#define GCSWEEPMAX (cast_int((GCSTEPSIZE / GCSWEEPCOST) / 4))
/* maximum number of finalizers to call in each GC step */
#define GCFINALIZENUM 4
-/* cost of marking the root set */
-#define GCROOTCOST 10
-/* cost of atomic step */
-#define GCATOMICCOST 1000
+/*
+** macro to adjust 'stepmul': 'stepmul' is actually used like
+** 'stepmul / STEPMULADJ' (value chosen by tests)
+*/
+#define STEPMULADJ 200
+
+/*
+** macro to adjust 'pause': 'pause' is actually used like
+** 'pause / PAUSEADJ' (value chosen by tests)
+*/
+#define PAUSEADJ 200
+
-/* basic cost to traverse one object (to be added to the links the
- object may have) */
-#define TRAVCOST 5
/*
** standard negative debt for GC; a reasonable "time" to wait before
** starting a new cycle
*/
-#define stddebt(g) (-cast(l_mem, gettotalbytes(g)/100) * g->gcpause)
+#define stddebtest(g,e) (-cast(l_mem, (e)/PAUSEADJ) * g->gcpause)
+#define stddebt(g) stddebtest(g, gettotalbytes(g))
/*
@@ -65,8 +71,6 @@
#define white2gray(x) resetbits(gch(x)->marked, WHITEBITS)
#define black2gray(x) resetbit(gch(x)->marked, BLACKBIT)
-#define stringmark(s) ((void)((s) && resetbits((s)->tsv.marked, WHITEBITS)))
-
#define isfinalized(x) testbit(gch(x)->marked, FINALIZEDBIT)
@@ -123,10 +127,10 @@ static void removeentry (Node *n) {
** other objects: if really collected, cannot keep them; for objects
** being finalized, keep them in keys, but not in values
*/
-static int iscleared (const TValue *o) {
+static int iscleared (global_State *g, const TValue *o) {
if (!iscollectable(o)) return 0;
else if (ttisstring(o)) {
- stringmark(rawtsvalue(o)); /* strings are `values', so are never weak */
+ markobject(g, rawtsvalue(o)); /* strings are `values', so are never weak */
return 0;
}
else return iswhite(gcvalue(o));
@@ -217,7 +221,8 @@ void luaC_checkupvalcolor (global_State *g, UpVal *uv) {
GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, GCObject **list,
int offset) {
global_State *g = G(L);
- GCObject *o = obj2gco(cast(char *, luaM_newobject(L, tt, sz)) + offset);
+ char *raw = cast(char *, luaM_newobject(L, novariant(tt), sz));
+ GCObject *o = obj2gco(raw + offset);
if (list == NULL)
list = &g->allgc; /* standard list for collectable objects */
gch(o)->marked = luaC_white(g);
@@ -239,54 +244,63 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, GCObject **list,
/*
-** mark an object. Userdata and closed upvalues are visited and turned
-** black here. Strings remain gray (it is the same as making them
-** black). Other objects are marked gray and added to appropriate list
-** to be visited (and turned black) later. (Open upvalues are already
-** linked in 'headuv' list.)
+** mark an object. Userdata, strings, and closed upvalues are visited
+** and turned black here. Other objects are marked gray and added
+** to appropriate list to be visited (and turned black) later. (Open
+** upvalues are already linked in 'headuv' list.)
*/
static void reallymarkobject (global_State *g, GCObject *o) {
- lua_assert(iswhite(o) && !isdead(g, o));
+ lu_mem size;
white2gray(o);
switch (gch(o)->tt) {
- case LUA_TSTRING: {
- return; /* for strings, gray is as good as black */
+ case LUA_TSHRSTR:
+ case LUA_TLNGSTR: {
+ size = sizestring(gco2ts(o));
+ break; /* nothing else to mark; make it black */
}
case LUA_TUSERDATA: {
Table *mt = gco2u(o)->metatable;
markobject(g, mt);
markobject(g, gco2u(o)->env);
- gray2black(o); /* all pointers marked */
- return;
+ size = sizeudata(gco2u(o));
+ break;
}
case LUA_TUPVAL: {
UpVal *uv = gco2uv(o);
markvalue(g, uv->v);
- if (uv->v == &uv->u.value) /* closed? (open upvalues remain gray) */
- gray2black(o); /* make it black */
+ if (uv->v != &uv->u.value) /* open? */
+ return; /* open upvalues remain gray */
+ size = sizeof(UpVal);
+ break;
+ }
+ case LUA_TLCL: {
+ gco2lcl(o)->gclist = g->gray;
+ g->gray = o;
return;
}
- case LUA_TFUNCTION: {
- gco2cl(o)->c.gclist = g->gray;
+ case LUA_TCCL: {
+ gco2ccl(o)->gclist = g->gray;
g->gray = o;
- break;
+ return;
}
case LUA_TTABLE: {
linktable(gco2t(o), &g->gray);
- break;
+ return;
}
case LUA_TTHREAD: {
gco2th(o)->gclist = g->gray;
g->gray = o;
- break;
+ return;
}
case LUA_TPROTO: {
gco2p(o)->gclist = g->gray;
g->gray = o;
- break;
+ return;
}
- default: lua_assert(0);
+ default: lua_assert(0); return;
}
+ gray2black(o);
+ g->GCmemtrav += size;
}
@@ -359,7 +373,7 @@ static void traverseweakvalue (global_State *g, Table *h) {
else {
lua_assert(!ttisnil(gkey(n)));
markvalue(g, gkey(n)); /* mark key */
- if (!hasclears && iscleared(gval(n))) /* is there a white value? */
+ if (!hasclears && iscleared(g, gval(n))) /* is there a white value? */
hasclears = 1; /* table will have to be cleared */
}
}
@@ -388,7 +402,7 @@ static int traverseephemeron (global_State *g, Table *h) {
checkdeadkey(n);
if (ttisnil(gval(n))) /* entry is empty? */
removeentry(n); /* remove it */
- else if (iscleared(gkey(n))) { /* key is not marked (yet)? */
+ else if (iscleared(g, gkey(n))) { /* key is not marked (yet)? */
hasclears = 1; /* table must be cleared */
if (valiswhite(gval(n))) /* value not marked yet? */
prop = 1; /* must propagate again */
@@ -426,30 +440,26 @@ static void traversestrongtable (global_State *g, Table *h) {
}
-static int traversetable (global_State *g, Table *h) {
+static lu_mem traversetable (global_State *g, Table *h) {
+ const char *weakkey, *weakvalue;
const TValue *mode = gfasttm(g, h->metatable, TM_MODE);
markobject(g, h->metatable);
- if (mode && ttisstring(mode)) { /* is there a weak mode? */
- int weakkey = (strchr(svalue(mode), 'k') != NULL);
- int weakvalue = (strchr(svalue(mode), 'v') != NULL);
- if (weakkey || weakvalue) { /* is really weak? */
- black2gray(obj2gco(h)); /* keep table gray */
- if (!weakkey) { /* strong keys? */
- traverseweakvalue(g, h);
- return TRAVCOST + sizenode(h);
- }
- else if (!weakvalue) { /* strong values? */
- traverseephemeron(g, h);
- return TRAVCOST + h->sizearray + sizenode(h);
- }
- else {
- linktable(h, &g->allweak); /* nothing to traverse now */
- return TRAVCOST;
- }
- } /* else go through */
+ if (mode && ttisstring(mode) && /* is there a weak mode? */
+ ((weakkey = strchr(svalue(mode), 'k')),
+ (weakvalue = strchr(svalue(mode), 'v')),
+ (weakkey || weakvalue))) { /* is really weak? */
+ black2gray(obj2gco(h)); /* keep table gray */
+ if (!weakkey) /* strong keys? */
+ traverseweakvalue(g, h);
+ else if (!weakvalue) /* strong values? */
+ traverseephemeron(g, h);
+ else /* all weak */
+ linktable(h, &g->allweak); /* nothing to traverse now */
}
- traversestrongtable(g, h);
- return TRAVCOST + h->sizearray + (2 * sizenode(h));
+ else /* not weak */
+ traversestrongtable(g, h);
+ return sizeof(Table) + sizeof(TValue) * h->sizearray +
+ sizeof(Node) * sizenode(h);
}
@@ -457,86 +467,101 @@ static int traverseproto (global_State *g, Proto *f) {
int i;
if (f->cache && iswhite(obj2gco(f->cache)))
f->cache = NULL; /* allow cache to be collected */
- stringmark(f->source);
+ markobject(g, f->source);
for (i = 0; i < f->sizek; i++) /* mark literals */
markvalue(g, &f->k[i]);
for (i = 0; i < f->sizeupvalues; i++) /* mark upvalue names */
- stringmark(f->upvalues[i].name);
+ markobject(g, f->upvalues[i].name);
for (i = 0; i < f->sizep; i++) /* mark nested protos */
markobject(g, f->p[i]);
for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */
- stringmark(f->locvars[i].varname);
- return TRAVCOST + f->sizek + f->sizeupvalues + f->sizep + f->sizelocvars;
+ markobject(g, f->locvars[i].varname);
+ return sizeof(Proto) + sizeof(Instruction) * f->sizecode +
+ sizeof(Proto *) * f->sizep +
+ sizeof(TValue) * f->sizek +
+ sizeof(int) * f->sizelineinfo +
+ sizeof(LocVar) * f->sizelocvars +
+ sizeof(Upvaldesc) * f->sizeupvalues;
}
-static int traverseclosure (global_State *g, Closure *cl) {
- if (cl->c.isC) {
- int i;
- for (i=0; ic.nupvalues; i++) /* mark its upvalues */
- markvalue(g, &cl->c.upvalue[i]);
- }
- else {
- int i;
- lua_assert(cl->l.nupvalues == cl->l.p->sizeupvalues);
- markobject(g, cl->l.p); /* mark its prototype */
- for (i=0; il.nupvalues; i++) /* mark its upvalues */
- markobject(g, cl->l.upvals[i]);
- }
- return TRAVCOST + cl->c.nupvalues;
+static lu_mem traverseCclosure (global_State *g, CClosure *cl) {
+ int i;
+ for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */
+ markvalue(g, &cl->upvalue[i]);
+ return sizeCclosure(cl->nupvalues);
+}
+
+static lu_mem traverseLclosure (global_State *g, LClosure *cl) {
+ int i;
+ markobject(g, cl->p); /* mark its prototype */
+ for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */
+ markobject(g, cl->upvals[i]);
+ return sizeLclosure(cl->nupvalues);
}
-static int traversestack (global_State *g, lua_State *L) {
- StkId o = L->stack;
+static lu_mem traversestack (global_State *g, lua_State *th) {
+ StkId o = th->stack;
if (o == NULL)
return 1; /* stack not completely built yet */
- for (; o < L->top; o++)
+ for (; o < th->top; o++)
markvalue(g, o);
if (g->gcstate == GCSatomic) { /* final traversal? */
- StkId lim = L->stack + L->stacksize; /* real end of stack */
+ StkId lim = th->stack + th->stacksize; /* real end of stack */
for (; o < lim; o++) /* clear not-marked stack slice */
setnilvalue(o);
}
- return TRAVCOST + cast_int(o - L->stack);
+ return sizeof(lua_State) + sizeof(TValue) * th->stacksize;
}
/*
** traverse one gray object, turning it to black (except for threads,
** which are always gray).
-** Returns number of values traversed.
*/
-static int propagatemark (global_State *g) {
+static void propagatemark (global_State *g) {
+ lu_mem size;
GCObject *o = g->gray;
lua_assert(isgray(o));
gray2black(o);
switch (gch(o)->tt) {
case LUA_TTABLE: {
Table *h = gco2t(o);
- g->gray = h->gclist;
- return traversetable(g, h);
+ g->gray = h->gclist; /* remove from 'gray' list */
+ size = traversetable(g, h);
+ break;
+ }
+ case LUA_TLCL: {
+ LClosure *cl = gco2lcl(o);
+ g->gray = cl->gclist; /* remove from 'gray' list */
+ size = traverseLclosure(g, cl);
+ break;
}
- case LUA_TFUNCTION: {
- Closure *cl = gco2cl(o);
- g->gray = cl->c.gclist;
- return traverseclosure(g, cl);
+ case LUA_TCCL: {
+ CClosure *cl = gco2ccl(o);
+ g->gray = cl->gclist; /* remove from 'gray' list */
+ size = traverseCclosure(g, cl);
+ break;
}
case LUA_TTHREAD: {
lua_State *th = gco2th(o);
- g->gray = th->gclist;
+ g->gray = th->gclist; /* remove from 'gray' list */
th->gclist = g->grayagain;
- g->grayagain = o;
+ g->grayagain = o; /* insert into 'grayagain' list */
black2gray(o);
- return traversestack(g, th);
+ size = traversestack(g, th);
+ break;
}
case LUA_TPROTO: {
Proto *p = gco2p(o);
- g->gray = p->gclist;
- return traverseproto(g, p);
+ g->gray = p->gclist; /* remove from 'gray' list */
+ size = traverseproto(g, p);
+ break;
}
- default: lua_assert(0); return 0;
+ default: lua_assert(0); return;
}
+ g->GCmemtrav += size;
}
@@ -599,12 +624,12 @@ static void convergeephemerons (global_State *g) {
** clear entries with unmarked keys from all weaktables in list 'l' up
** to element 'f'
*/
-static void clearkeys (GCObject *l, GCObject *f) {
+static void clearkeys (global_State *g, GCObject *l, GCObject *f) {
for (; l != f; l = gco2t(l)->gclist) {
Table *h = gco2t(l);
Node *n, *limit = gnodelast(h);
for (n = gnode(h, 0); n < limit; n++) {
- if (!ttisnil(gval(n)) && (iscleared(gkey(n)))) {
+ if (!ttisnil(gval(n)) && (iscleared(g, gkey(n)))) {
setnilvalue(gval(n)); /* remove value ... */
removeentry(n); /* and remove entry from table */
}
@@ -617,18 +642,18 @@ static void clearkeys (GCObject *l, GCObject *f) {
** clear entries with unmarked values from all weaktables in list 'l' up
** to element 'f'
*/
-static void clearvalues (GCObject *l, GCObject *f) {
+static void clearvalues (global_State *g, GCObject *l, GCObject *f) {
for (; l != f; l = gco2t(l)->gclist) {
Table *h = gco2t(l);
Node *n, *limit = gnodelast(h);
int i;
for (i = 0; i < h->sizearray; i++) {
TValue *o = &h->array[i];
- if (iscleared(o)) /* value was collected? */
+ if (iscleared(g, o)) /* value was collected? */
setnilvalue(o); /* remove value */
}
for (n = gnode(h, 0); n < limit; n++) {
- if (!ttisnil(gval(n)) && iscleared(gval(n))) {
+ if (!ttisnil(gval(n)) && iscleared(g, gval(n))) {
setnilvalue(gval(n)); /* remove value ... */
removeentry(n); /* and remove entry from table */
}
@@ -640,13 +665,22 @@ static void clearvalues (GCObject *l, GCObject *f) {
static void freeobj (lua_State *L, GCObject *o) {
switch (gch(o)->tt) {
case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break;
- case LUA_TFUNCTION: luaF_freeclosure(L, gco2cl(o)); break;
+ case LUA_TLCL: {
+ luaM_freemem(L, o, sizeLclosure(gco2lcl(o)->nupvalues));
+ break;
+ }
+ case LUA_TCCL: {
+ luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues));
+ break;
+ }
case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break;
case LUA_TTABLE: luaH_free(L, gco2t(o)); break;
case LUA_TTHREAD: luaE_freethread(L, gco2th(o)); break;
case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break;
- case LUA_TSTRING: {
+ case LUA_TSHRSTR:
G(L)->strt.nuse--;
+ /* go through */
+ case LUA_TLNGSTR: {
luaM_freemem(L, o, sizestring(gco2ts(o)));
break;
}
@@ -689,7 +723,6 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
int ow = otherwhite(g);
int toclear, toset; /* bits to clear and to set in all live objects */
int tostop; /* stop sweep when this is true */
- l_mem debt = g->GCdebt; /* current debt */
if (isgenerational(g)) { /* generational mode? */
toclear = ~0; /* clear nothing */
toset = bitmask(OLDBIT); /* set the old bit of all surviving objects */
@@ -708,19 +741,30 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
freeobj(L, curr); /* erase 'curr' */
}
else {
+ if (testbits(marked, tostop))
+ return NULL; /* stop sweeping this list */
if (gch(curr)->tt == LUA_TTHREAD)
sweepthread(L, gco2th(curr)); /* sweep thread's upvalues */
- if (testbits(marked, tostop)) {
- static GCObject *nullp = NULL;
- p = &nullp; /* stop sweeping this list */
- break;
- }
/* update marks */
gch(curr)->marked = cast_byte((marked & toclear) | toset);
p = &gch(curr)->next; /* go to next element */
}
}
- luaE_setdebt(g, debt); /* sweeping should not change debt */
+ return (*p == NULL) ? NULL : p;
+}
+
+
+/*
+** sweep a list until a live object (or end of list)
+*/
+static GCObject **sweeptolive (lua_State *L, GCObject **p, int *n) {
+ GCObject ** old = p;
+ int i = 0;
+ do {
+ i++;
+ p = sweeplist(L, p, 1);
+ } while (p == old);
+ if (n) *n += i;
return p;
}
@@ -783,12 +827,14 @@ static void GCTM (lua_State *L, int propagateerrors) {
L->allowhook = oldah; /* restore hooks */
g->gcrunning = running; /* restore state */
if (status != LUA_OK && propagateerrors) { /* error while running __gc? */
- if (status == LUA_ERRRUN) { /* is there an error msg.? */
- luaO_pushfstring(L, "error in __gc metamethod (%s)",
- lua_tostring(L, -1));
+ if (status == LUA_ERRRUN) { /* is there an error object? */
+ const char *msg = (ttisstring(L->top - 1))
+ ? svalue(L->top - 1)
+ : "no message";
+ luaO_pushfstring(L, "error in __gc metamethod (%s)", msg);
status = LUA_ERRGCMM; /* error in __gc metamethod */
}
- luaD_throw(L, status); /* re-send error */
+ luaD_throw(L, status); /* re-throw error */
}
}
}
@@ -834,12 +880,21 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
return; /* nothing to be done */
else { /* move 'o' to 'finobj' list */
GCObject **p;
- for (p = &g->allgc; *p != o; p = &gch(*p)->next) ;
- *p = gch(o)->next; /* remove 'o' from root list */
- gch(o)->next = g->finobj; /* link it in list 'finobj' */
+ GCheader *ho = gch(o);
+ if (g->sweepgc == &ho->next) { /* avoid removing current sweep object */
+ lua_assert(issweepphase(g));
+ g->sweepgc = sweeptolive(L, g->sweepgc, NULL);
+ }
+ /* search for pointer pointing to 'o' */
+ for (p = &g->allgc; *p != o; p = &gch(*p)->next) { /* empty */ }
+ *p = ho->next; /* remove 'o' from root list */
+ ho->next = g->finobj; /* link it in list 'finobj' */
g->finobj = o;
- l_setbit(gch(o)->marked, SEPARATED); /* mark it as such */
- resetoldbit(o); /* see MOVE OLD rule */
+ l_setbit(ho->marked, SEPARATED); /* mark it as such */
+ if (!keepinvariant(g)) /* not keeping invariant? */
+ makewhite(g, o); /* "sweep" object */
+ else
+ resetoldbit(o); /* see MOVE OLD rule */
}
}
@@ -856,6 +911,28 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
#define sweepphases \
(bitmask(GCSsweepstring) | bitmask(GCSsweepudata) | bitmask(GCSsweep))
+
+/*
+** enter first sweep phase (strings) and prepare pointers for other
+** sweep phases. The calls to 'sweeptolive' make pointers point to an
+** object inside the list (instead of to the header), so that the real
+** sweep do not need to skip objects created between "now" and the start
+** of the real sweep.
+** Returns how many objects it sweeped.
+*/
+static int entersweep (lua_State *L) {
+ global_State *g = G(L);
+ int n = 0;
+ g->gcstate = GCSsweepstring;
+ lua_assert(g->sweepgc == NULL && g->sweepfin == NULL);
+ /* prepare to sweep strings, finalizable objects, and regular objects */
+ g->sweepstrgc = 0;
+ g->sweepfin = sweeptolive(L, &g->finobj, &n);
+ g->sweepgc = sweeptolive(L, &g->allgc, &n);
+ return n;
+}
+
+
/*
** change GC mode
*/
@@ -865,15 +942,14 @@ void luaC_changemode (lua_State *L, int mode) {
if (mode == KGC_GEN) { /* change to generational mode */
/* make sure gray lists are consistent */
luaC_runtilstate(L, bitmask(GCSpropagate));
- g->lastmajormem = gettotalbytes(g);
+ g->GCestimate = gettotalbytes(g);
g->gckind = KGC_GEN;
}
else { /* change to incremental mode */
/* sweep all objects to turn them back to white
(as white has not changed, nothing extra will be collected) */
- g->sweepstrgc = 0;
- g->gcstate = GCSsweepstring;
g->gckind = KGC_NORMAL;
+ entersweep(L);
luaC_runtilstate(L, ~sweepphases);
}
}
@@ -907,8 +983,9 @@ void luaC_freeallobjects (lua_State *L) {
}
-static void atomic (lua_State *L) {
+static l_mem atomic (lua_State *L) {
global_State *g = G(L);
+ l_mem work = -g->GCmemtrav; /* start counting work */
GCObject *origweak, *origall;
lua_assert(!iswhite(obj2gco(g->mainthread)));
markobject(g, L); /* mark running thread */
@@ -917,77 +994,87 @@ static void atomic (lua_State *L) {
markmt(g); /* mark basic metatables */
/* remark occasional upvalues of (maybe) dead threads */
remarkupvals(g);
+ propagateall(g); /* propagate changes */
+ work += g->GCmemtrav; /* stop counting (do not (re)count grays) */
/* traverse objects caught by write barrier and by 'remarkupvals' */
retraversegrays(g);
+ work -= g->GCmemtrav; /* restart counting */
convergeephemerons(g);
/* at this point, all strongly accessible objects are marked. */
/* clear values from weak tables, before checking finalizers */
- clearvalues(g->weak, NULL);
- clearvalues(g->allweak, NULL);
+ clearvalues(g, g->weak, NULL);
+ clearvalues(g, g->allweak, NULL);
origweak = g->weak; origall = g->allweak;
+ work += g->GCmemtrav; /* stop counting (objects being finalized) */
separatetobefnz(L, 0); /* separate objects to be finalized */
- markbeingfnz(g); /* mark userdata that will be finalized */
+ markbeingfnz(g); /* mark objects that will be finalized */
propagateall(g); /* remark, to propagate `preserveness' */
+ work -= g->GCmemtrav; /* restart counting */
convergeephemerons(g);
/* at this point, all resurrected objects are marked. */
/* remove dead objects from weak tables */
- clearkeys(g->ephemeron, NULL); /* clear keys from all ephemeron tables */
- clearkeys(g->allweak, NULL); /* clear keys from all allweak tables */
+ clearkeys(g, g->ephemeron, NULL); /* clear keys from all ephemeron tables */
+ clearkeys(g, g->allweak, NULL); /* clear keys from all allweak tables */
/* clear values from resurrected weak tables */
- clearvalues(g->weak, origweak);
- clearvalues(g->allweak, origall);
- g->sweepstrgc = 0; /* prepare to sweep strings */
- g->gcstate = GCSsweepstring;
+ clearvalues(g, g->weak, origweak);
+ clearvalues(g, g->allweak, origall);
g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */
- /*lua_checkmemory(L);*/
+ work += g->GCmemtrav; /* complete counting */
+ return work; /* estimate of memory marked by 'atomic' */
}
-static l_mem singlestep (lua_State *L) {
+static lu_mem singlestep (lua_State *L) {
global_State *g = G(L);
switch (g->gcstate) {
case GCSpause: {
+ g->GCmemtrav = 0; /* start to count memory traversed */
if (!isgenerational(g))
markroot(g); /* start a new collection */
- /* in any case, root must be marked */
+ /* in any case, root must be marked at this point */
lua_assert(!iswhite(obj2gco(g->mainthread))
&& !iswhite(gcvalue(&g->l_registry)));
g->gcstate = GCSpropagate;
- return GCROOTCOST;
+ return g->GCmemtrav;
}
case GCSpropagate: {
- if (g->gray)
- return propagatemark(g);
+ if (g->gray) {
+ lu_mem oldtrav = g->GCmemtrav;
+ propagatemark(g);
+ return g->GCmemtrav - oldtrav; /* memory traversed in this step */
+ }
else { /* no more `gray' objects */
+ lu_mem work;
+ int sw;
g->gcstate = GCSatomic; /* finish mark phase */
- atomic(L);
- return GCATOMICCOST;
+ g->GCestimate = g->GCmemtrav; /* save what was counted */;
+ work = atomic(L); /* add what was traversed by 'atomic' */
+ g->GCestimate += work; /* estimate of total memory traversed */
+ sw = entersweep(L);
+ return work + sw * GCSWEEPCOST;
}
}
case GCSsweepstring: {
- if (g->sweepstrgc < g->strt.size) {
- sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]);
- return GCSWEEPCOST;
- }
- else { /* no more strings to sweep */
- g->sweepgc = &g->finobj; /* prepare to sweep finalizable objects */
+ int i;
+ for (i = 0; i < GCSWEEPMAX && g->sweepstrgc + i < g->strt.size; i++)
+ sweepwholelist(L, &g->strt.hash[g->sweepstrgc + i]);
+ g->sweepstrgc += i;
+ if (g->sweepstrgc >= g->strt.size) /* no more strings to sweep? */
g->gcstate = GCSsweepudata;
- return 0;
- }
+ return i * GCSWEEPCOST;
}
case GCSsweepudata: {
- if (*g->sweepgc) {
- g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX);
+ if (g->sweepfin) {
+ g->sweepfin = sweeplist(L, g->sweepfin, GCSWEEPMAX);
return GCSWEEPMAX*GCSWEEPCOST;
}
else {
- g->sweepgc = &g->allgc; /* go to next phase */
g->gcstate = GCSsweep;
- return GCSWEEPCOST;
+ return 0;
}
}
case GCSsweep: {
- if (*g->sweepgc) {
+ if (g->sweepgc) {
g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX);
return GCSWEEPMAX*GCSWEEPCOST;
}
@@ -1018,43 +1105,52 @@ void luaC_runtilstate (lua_State *L, int statesmask) {
static void generationalcollection (lua_State *L) {
global_State *g = G(L);
- if (g->lastmajormem == 0) { /* signal for another major collection? */
+ if (g->GCestimate == 0) { /* signal for another major collection? */
luaC_fullgc(L, 0); /* perform a full regular collection */
- g->lastmajormem = gettotalbytes(g); /* update control */
+ g->GCestimate = gettotalbytes(g); /* update control */
}
else {
+ lu_mem estimate = g->GCestimate;
luaC_runtilstate(L, ~bitmask(GCSpause)); /* run complete cycle */
luaC_runtilstate(L, bitmask(GCSpause));
- if (gettotalbytes(g) > g->lastmajormem/100 * g->gcmajorinc)
- g->lastmajormem = 0; /* signal for a major collection */
+ if (gettotalbytes(g) > (estimate / 100) * g->gcmajorinc)
+ g->GCestimate = 0; /* signal for a major collection */
}
luaE_setdebt(g, stddebt(g));
}
-static void step (lua_State *L) {
+static void incstep (lua_State *L) {
global_State *g = G(L);
- l_mem lim = g->gcstepmul; /* how much to work */
+ l_mem debt = g->GCdebt;
+ int stepmul = g->gcstepmul;
+ if (stepmul < 40) stepmul = 40; /* avoid ridiculous low values */
+ /* convert debt from Kb to 'work units' (avoid zero debt and overflows) */
+ debt = (debt / STEPMULADJ) + 1;
+ debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM;
do { /* always perform at least one single step */
- lim -= singlestep(L);
- } while (lim > 0 && g->gcstate != GCSpause);
- if (g->gcstate != GCSpause)
- luaE_setdebt(g, g->GCdebt - GCSTEPSIZE);
+ lu_mem work = singlestep(L); /* do some work */
+ debt -= work;
+ } while (debt > -GCSTEPSIZE && g->gcstate != GCSpause);
+ if (g->gcstate == GCSpause)
+ debt = stddebtest(g, g->GCestimate); /* pause until next cycle */
else
- luaE_setdebt(g, stddebt(g));
+ debt = (debt / stepmul) * STEPMULADJ; /* convert 'work units' to Kb */
+ luaE_setdebt(g, debt);
}
/*
-** performs a basic GC step even if the collector is stopped
+** performs a basic GC step
*/
void luaC_forcestep (lua_State *L) {
global_State *g = G(L);
int i;
if (isgenerational(g)) generationalcollection(L);
- else step(L);
- for (i = 0; i < GCFINALIZENUM && g->tobefnz; i++)
- GCTM(L, 1); /* Call a few pending finalizers */
+ else incstep(L);
+ /* run a few finalizers (or all of them at the end of a collect cycle) */
+ for (i = 0; g->tobefnz && (i < GCFINALIZENUM || g->gcstate == GCSpause); i++)
+ GCTM(L, 1); /* call one finalizer */
}
@@ -1062,10 +1158,13 @@ void luaC_forcestep (lua_State *L) {
** performs a basic GC step only if collector is running
*/
void luaC_step (lua_State *L) {
- if (G(L)->gcrunning) luaC_forcestep(L);
+ global_State *g = G(L);
+ if (g->gcrunning) luaC_forcestep(L);
+ else luaE_setdebt(g, -GCSTEPSIZE); /* avoid being called too often */
}
+
/*
** performs a full GC cycle; if "isemergency", does not call
** finalizers (which could change stack positions)
@@ -1073,16 +1172,19 @@ void luaC_step (lua_State *L) {
void luaC_fullgc (lua_State *L, int isemergency) {
global_State *g = G(L);
int origkind = g->gckind;
+ int someblack = keepinvariant(g);
lua_assert(origkind != KGC_EMERGENCY);
- if (!isemergency) /* do not run finalizers during emergency GC */
+ if (isemergency) /* do not run finalizers during emergency GC */
+ g->gckind = KGC_EMERGENCY;
+ else {
+ g->gckind = KGC_NORMAL;
callallpendingfinalizers(L, 1);
- if (keepinvariant(g)) { /* marking phase? */
+ }
+ if (someblack) { /* may there be some black objects? */
/* must sweep all objects to turn them back to white
(as white has not changed, nothing will be collected) */
- g->sweepstrgc = 0;
- g->gcstate = GCSsweepstring;
+ entersweep(L);
}
- g->gckind = isemergency ? KGC_EMERGENCY : KGC_NORMAL;
/* finish any pending sweep phase to start a new cycle */
luaC_runtilstate(L, bitmask(GCSpause));
/* run entire collector */
diff --git a/depends/lua/src/llex.c b/depends/lua/src/llex.c
index 74deebb93..c4d8c65b6 100644
--- a/depends/lua/src/llex.c
+++ b/depends/lua/src/llex.c
@@ -1,5 +1,5 @@
/*
-** $Id: llex.c,v 2.59 2011/11/30 12:43:51 roberto Exp $
+** $Id: llex.c,v 2.61 2012/01/23 23:05:51 roberto Exp $
** Lexical Analyzer
** See Copyright Notice in lua.h
*/
@@ -67,7 +67,7 @@ void luaX_init (lua_State *L) {
for (i=0; itsv.reserved = cast_byte(i+1); /* reserved word */
+ ts->tsv.extra = cast_byte(i+1); /* reserved word */
}
}
@@ -222,13 +222,24 @@ static void trydecpoint (LexState *ls, SemInfo *seminfo) {
/* LUA_NUMBER */
+/*
+** this function is quite liberal in what it accepts, as 'luaO_str2d'
+** will reject ill-formed numerals.
+*/
static void read_numeral (LexState *ls, SemInfo *seminfo) {
+ const char *expo = "Ee";
+ int first = ls->current;
lua_assert(lisdigit(ls->current));
- do {
- save_and_next(ls);
- if (check_next(ls, "EePp")) /* exponent part? */
+ save_and_next(ls);
+ if (first == '0' && check_next(ls, "Xx")) /* hexadecimal? */
+ expo = "Pp";
+ for (;;) {
+ if (check_next(ls, expo)) /* exponent part? */
check_next(ls, "+-"); /* optional exponent sign */
- } while (lislalnum(ls->current) || ls->current == '.');
+ if (lisxdigit(ls->current) || ls->current == '.')
+ save_and_next(ls);
+ else break;
+ }
save(ls, '\0');
buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */
if (!buff2d(ls->buff, &seminfo->r)) /* format error? */
@@ -480,8 +491,8 @@ static int llex (LexState *ls, SemInfo *seminfo) {
ts = luaX_newstring(ls, luaZ_buffer(ls->buff),
luaZ_bufflen(ls->buff));
seminfo->ts = ts;
- if (ts->tsv.reserved > 0) /* reserved word? */
- return ts->tsv.reserved - 1 + FIRST_RESERVED;
+ if (isreserved(ts)) /* reserved word? */
+ return ts->tsv.extra - 1 + FIRST_RESERVED;
else {
return TK_NAME;
}
diff --git a/depends/lua/src/lmathlib.c b/depends/lua/src/lmathlib.c
index b17237f0b..c3c605e86 100644
--- a/depends/lua/src/lmathlib.c
+++ b/depends/lua/src/lmathlib.c
@@ -1,5 +1,5 @@
/*
-** $Id: lmathlib.c,v 1.80 2011/07/05 12:49:35 roberto Exp $
+** $Id: lmathlib.c,v 1.81 2012/05/18 17:47:53 roberto Exp $
** Standard mathematical library
** See Copyright Notice in lua.h
*/
@@ -17,17 +17,17 @@
#include "lualib.h"
-#undef PI
-#define PI (3.14159265358979323846)
-#define RADIANS_PER_DEGREE (PI/180.0)
-
-
/* macro 'l_tg' allows the addition of an 'l' or 'f' to all math operations */
#if !defined(l_tg)
#define l_tg(x) (x)
#endif
+#undef PI
+#define PI (l_tg(3.1415926535897932384626433832795))
+#define RADIANS_PER_DEGREE (PI/180.0)
+
+
static int math_abs (lua_State *L) {
lua_pushnumber(L, l_tg(fabs)(luaL_checknumber(L, 1)));
diff --git a/depends/lua/src/lmem.c b/depends/lua/src/lmem.c
index 792deb3cf..3f88496e0 100644
--- a/depends/lua/src/lmem.c
+++ b/depends/lua/src/lmem.c
@@ -1,5 +1,5 @@
/*
-** $Id: lmem.c,v 1.83 2011/11/30 12:42:49 roberto Exp $
+** $Id: lmem.c,v 1.84 2012/05/23 15:41:53 roberto Exp $
** Interface to Memory Manager
** See Copyright Notice in lua.h
*/
@@ -94,22 +94,6 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
}
lua_assert((nsize == 0) == (newblock == NULL));
g->GCdebt = (g->GCdebt + nsize) - realosize;
-#if defined(TRACEMEM)
- { /* auxiliary patch to monitor garbage collection.
- ** To plot, gnuplot with following command:
- ** plot TRACEMEM using 1:2 with lines, TRACEMEM using 1:3 with lines
- */
- static unsigned long total = 0; /* our "time" */
- static FILE *f = NULL; /* output file */
- total++; /* "time" always grows */
- if ((total % 200) == 0) {
- if (f == NULL) f = fopen(TRACEMEM, "w");
- fprintf(f, "%lu %u %d %d\n", total,
- gettotalbytes(g), g->GCdebt, g->gcstate * 10000);
- }
- }
-#endif
-
return newblock;
}
diff --git a/depends/lua/src/loadlib.c b/depends/lua/src/loadlib.c
index 783bc12be..a9959277b 100644
--- a/depends/lua/src/loadlib.c
+++ b/depends/lua/src/loadlib.c
@@ -1,5 +1,5 @@
/*
-** $Id: loadlib.c,v 1.108 2011/12/12 16:34:03 roberto Exp $
+** $Id: loadlib.c,v 1.111 2012/05/30 12:33:44 roberto Exp $
** Dynamic library loader for Lua
** See Copyright Notice in lua.h
**
@@ -92,9 +92,9 @@
#define LUA_OFSEP "_"
-#define LIBPREFIX "LOADLIB: "
+/* table (in the registry) that keeps handles for all loaded C libraries */
+#define CLIBS "_CLIBS"
-#define POF LUA_POF
#define LIB_FAIL "open"
@@ -248,48 +248,54 @@ static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) {
#endif
-
-static void **ll_register (lua_State *L, const char *path) {
- void **plib;
- lua_pushfstring(L, "%s%s", LIBPREFIX, path);
- lua_gettable(L, LUA_REGISTRYINDEX); /* check library in registry? */
- if (!lua_isnil(L, -1)) /* is there an entry? */
- plib = (void **)lua_touserdata(L, -1);
- else { /* no entry yet; create one */
- lua_pop(L, 1); /* remove result from gettable */
- plib = (void **)lua_newuserdata(L, sizeof(const void *));
- *plib = NULL;
- luaL_setmetatable(L, "_LOADLIB");
- lua_pushfstring(L, "%s%s", LIBPREFIX, path);
- lua_pushvalue(L, -2);
- lua_settable(L, LUA_REGISTRYINDEX);
- }
+static void *ll_checkclib (lua_State *L, const char *path) {
+ void *plib;
+ lua_getfield(L, LUA_REGISTRYINDEX, CLIBS);
+ lua_getfield(L, -1, path);
+ plib = lua_touserdata(L, -1); /* plib = CLIBS[path] */
+ lua_pop(L, 2); /* pop CLIBS table and 'plib' */
return plib;
}
+static void ll_addtoclib (lua_State *L, const char *path, void *plib) {
+ lua_getfield(L, LUA_REGISTRYINDEX, CLIBS);
+ lua_pushlightuserdata(L, plib);
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -3, path); /* CLIBS[path] = plib */
+ lua_rawseti(L, -2, luaL_len(L, -2) + 1); /* CLIBS[#CLIBS + 1] = plib */
+ lua_pop(L, 1); /* pop CLIBS table */
+}
+
+
/*
-** __gc tag method: calls library's `ll_unloadlib' function with the lib
-** handle
+** __gc tag method for CLIBS table: calls 'll_unloadlib' for all lib
+** handles in list CLIBS
*/
static int gctm (lua_State *L) {
- void **lib = (void **)luaL_checkudata(L, 1, "_LOADLIB");
- if (*lib) ll_unloadlib(*lib);
- *lib = NULL; /* mark library as closed */
+ int n = luaL_len(L, 1);
+ for (; n >= 1; n--) { /* for each handle, in reverse order */
+ lua_rawgeti(L, 1, n); /* get handle CLIBS[n] */
+ ll_unloadlib(lua_touserdata(L, -1));
+ lua_pop(L, 1); /* pop handle */
+ }
return 0;
}
static int ll_loadfunc (lua_State *L, const char *path, const char *sym) {
- void **reg = ll_register(L, path);
- if (*reg == NULL) *reg = ll_load(L, path, *sym == '*');
- if (*reg == NULL) return ERRLIB; /* unable to load library */
+ void *reg = ll_checkclib(L, path); /* check loaded C libraries */
+ if (reg == NULL) { /* must load library? */
+ reg = ll_load(L, path, *sym == '*');
+ if (reg == NULL) return ERRLIB; /* unable to load library */
+ ll_addtoclib(L, path, reg);
+ }
if (*sym == '*') { /* loading only library (no function)? */
lua_pushboolean(L, 1); /* return 'true' */
return 0; /* no errors */
}
else {
- lua_CFunction f = ll_sym(L, *reg, sym);
+ lua_CFunction f = ll_sym(L, reg, sym);
if (f == NULL)
return ERRFUNC; /* unable to find function */
lua_pushcfunction(L, f); /* else create new function */
@@ -418,12 +424,12 @@ static int loadfunc (lua_State *L, const char *filename, const char *modname) {
if (mark) {
int stat;
funcname = lua_pushlstring(L, modname, mark - modname);
- funcname = lua_pushfstring(L, POF"%s", funcname);
+ funcname = lua_pushfstring(L, LUA_POF"%s", funcname);
stat = ll_loadfunc(L, filename, funcname);
if (stat != ERRFUNC) return stat;
modname = mark + 1; /* else go ahead and try old-style name */
}
- funcname = lua_pushfstring(L, POF"%s", modname);
+ funcname = lua_pushfstring(L, LUA_POF"%s", modname);
return ll_loadfunc(L, filename, funcname);
}
@@ -476,9 +482,9 @@ static void findloader (lua_State *L, const char *name) {
lua_getfield(L, lua_upvalueindex(1), "searchers"); /* will be at index 3 */
if (!lua_istable(L, 3))
luaL_error(L, LUA_QL("package.searchers") " must be a table");
- /* iterate over available seachers to find a loader */
+ /* iterate over available searchers to find a loader */
for (i = 1; ; i++) {
- lua_rawgeti(L, 3, i); /* get a seacher */
+ lua_rawgeti(L, 3, i); /* get a searcher */
if (lua_isnil(L, -1)) { /* no more searchers? */
lua_pop(L, 1); /* remove nil */
luaL_pushresult(&msg); /* create error message */
@@ -666,18 +672,10 @@ static const luaL_Reg ll_funcs[] = {
};
-static const lua_CFunction searchers[] =
- {searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL};
-
-
-LUAMOD_API int luaopen_package (lua_State *L) {
+static void createsearcherstable (lua_State *L) {
+ static const lua_CFunction searchers[] =
+ {searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL};
int i;
- /* create new type _LOADLIB */
- luaL_newmetatable(L, "_LOADLIB");
- lua_pushcfunction(L, gctm);
- lua_setfield(L, -2, "__gc");
- /* create `package' table */
- luaL_newlib(L, pk_funcs);
/* create 'searchers' table */
lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0);
/* fill it with pre-defined searchers */
@@ -686,6 +684,19 @@ LUAMOD_API int luaopen_package (lua_State *L) {
lua_pushcclosure(L, searchers[i], 1);
lua_rawseti(L, -2, i+1);
}
+}
+
+
+LUAMOD_API int luaopen_package (lua_State *L) {
+ /* create table CLIBS to keep track of loaded C libraries */
+ luaL_getsubtable(L, LUA_REGISTRYINDEX, CLIBS);
+ lua_createtable(L, 0, 1); /* metatable for CLIBS */
+ lua_pushcfunction(L, gctm);
+ lua_setfield(L, -2, "__gc"); /* set finalizer for CLIBS table */
+ lua_setmetatable(L, -2);
+ /* create `package' table */
+ luaL_newlib(L, pk_funcs);
+ createsearcherstable(L);
#if defined(LUA_COMPAT_LOADERS)
lua_pushvalue(L, -1); /* make a copy of 'searchers' table */
lua_setfield(L, -3, "loaders"); /* put it in field `loaders' */
diff --git a/depends/lua/src/lopcodes.c b/depends/lua/src/lopcodes.c
index 2e3467668..ef7369275 100644
--- a/depends/lua/src/lopcodes.c
+++ b/depends/lua/src/lopcodes.c
@@ -1,5 +1,6 @@
/*
-** $Id: lopcodes.c,v 1.48 2011/04/19 16:22:13 roberto Exp $
+** $Id: lopcodes.c,v 1.49 2012/05/14 13:34:18 roberto Exp $
+** Opcodes for Lua virtual machine
** See Copyright Notice in lua.h
*/
diff --git a/depends/lua/src/loslib.c b/depends/lua/src/loslib.c
index 881667dac..489755b6f 100644
--- a/depends/lua/src/loslib.c
+++ b/depends/lua/src/loslib.c
@@ -1,5 +1,5 @@
/*
-** $Id: loslib.c,v 1.38 2011/11/30 12:35:05 roberto Exp $
+** $Id: loslib.c,v 1.39 2012/05/23 15:37:09 roberto Exp $
** Standard Operating System library
** See Copyright Notice in lua.h
*/
@@ -26,11 +26,12 @@
#if !defined(LUA_STRFTIMEOPTIONS)
#if !defined(LUA_USE_POSIX)
-#define LUA_STRFTIMEOPTIONS { "aAbBcdHIjmMpSUwWxXyYz%", "" }
+#define LUA_STRFTIMEOPTIONS { "aAbBcdHIjmMpSUwWxXyYz%", "" }
#else
-#define LUA_STRFTIMEOPTIONS { "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%", "", \
- "E", "cCxXyY", \
- "O", "deHImMSuUVwWy" }
+#define LUA_STRFTIMEOPTIONS \
+ { "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%", "" \
+ "", "E", "cCxXyY", \
+ "O", "deHImMSuUVwWy" }
#endif
#endif
@@ -43,7 +44,7 @@
*/
#if defined(LUA_USE_MKSTEMP)
#include
-#define LUA_TMPNAMBUFSIZE 32
+#define LUA_TMPNAMBUFSIZE 32
#define lua_tmpnam(b,e) { \
strcpy(b, "/tmp/lua_XXXXXX"); \
e = mkstemp(b); \
@@ -52,8 +53,8 @@
#elif !defined(lua_tmpnam)
-#define LUA_TMPNAMBUFSIZE L_tmpnam
-#define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); }
+#define LUA_TMPNAMBUFSIZE L_tmpnam
+#define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); }
#endif
diff --git a/depends/lua/src/lparser.c b/depends/lua/src/lparser.c
index 4d689365a..b3eb3ca92 100644
--- a/depends/lua/src/lparser.c
+++ b/depends/lua/src/lparser.c
@@ -1,5 +1,5 @@
/*
-** $Id: lparser.c,v 2.124 2011/12/02 13:23:56 roberto Exp $
+** $Id: lparser.c,v 2.128 2012/05/20 14:51:23 roberto Exp $
** Lua Parser
** See Copyright Notice in lua.h
*/
@@ -222,7 +222,7 @@ static int searchupvalue (FuncState *fs, TString *name) {
int i;
Upvaldesc *up = fs->f->upvalues;
for (i = 0; i < fs->nups; i++) {
- if (eqstr(up[i].name, name)) return i;
+ if (luaS_eqstr(up[i].name, name)) return i;
}
return -1; /* not found */
}
@@ -246,7 +246,7 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
static int searchvar (FuncState *fs, TString *n) {
int i;
for (i=fs->nactvar-1; i >= 0; i--) {
- if (eqstr(n, getlocvar(fs, i)->varname))
+ if (luaS_eqstr(n, getlocvar(fs, i)->varname))
return i;
}
return -1; /* not found */
@@ -342,7 +342,7 @@ static void closegoto (LexState *ls, int g, Labeldesc *label) {
FuncState *fs = ls->fs;
Labellist *gl = &ls->dyd->gt;
Labeldesc *gt = &gl->arr[g];
- lua_assert(eqstr(gt->name, label->name));
+ lua_assert(luaS_eqstr(gt->name, label->name));
if (gt->nactvar < label->nactvar) {
TString *vname = getlocvar(fs, gt->nactvar)->varname;
const char *msg = luaO_pushfstring(ls->L,
@@ -369,7 +369,7 @@ static int findlabel (LexState *ls, int g) {
/* check labels in current block for a match */
for (i = bl->firstlabel; i < dyd->label.n; i++) {
Labeldesc *lb = &dyd->label.arr[i];
- if (eqstr(lb->name, gt->name)) { /* correct label? */
+ if (luaS_eqstr(lb->name, gt->name)) { /* correct label? */
if (gt->nactvar > lb->nactvar &&
(bl->upval || dyd->label.n > bl->firstlabel))
luaK_patchclose(ls->fs, gt->pc, lb->nactvar);
@@ -403,7 +403,7 @@ static void findgotos (LexState *ls, Labeldesc *lb) {
Labellist *gl = &ls->dyd->gt;
int i = ls->fs->bl->firstgoto;
while (i < gl->n) {
- if (eqstr(gl->arr[i].name, lb->name))
+ if (luaS_eqstr(gl->arr[i].name, lb->name))
closegoto(ls, i, lb);
else
i++;
@@ -461,7 +461,7 @@ static void breaklabel (LexState *ls) {
** message when label name is a reserved word (which can only be 'break')
*/
static l_noret undefgoto (LexState *ls, Labeldesc *gt) {
- const char *msg = (gt->name->tsv.reserved > 0)
+ const char *msg = isreserved(gt->name)
? "<%s> at line %d not inside a loop"
: "no visible label " LUA_QS " for at line %d";
msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line);
@@ -493,21 +493,30 @@ static void leaveblock (FuncState *fs) {
/*
-** adds prototype being created into its parent list of prototypes
-** and codes instruction to create new closure
+** adds a new prototype into list of prototypes
*/
-static void codeclosure (LexState *ls, Proto *clp, expdesc *v) {
- FuncState *fs = ls->fs->prev;
- Proto *f = fs->f; /* prototype of function creating new closure */
+static Proto *addprototype (LexState *ls) {
+ Proto *clp;
+ lua_State *L = ls->L;
+ FuncState *fs = ls->fs;
+ Proto *f = fs->f; /* prototype of current function */
if (fs->np >= f->sizep) {
int oldsize = f->sizep;
- luaM_growvector(ls->L, f->p, fs->np, f->sizep, Proto *,
- MAXARG_Bx, "functions");
+ luaM_growvector(L, f->p, fs->np, f->sizep, Proto *, MAXARG_Bx, "functions");
while (oldsize < f->sizep) f->p[oldsize++] = NULL;
}
- f->p[fs->np++] = clp;
- luaC_objbarrier(ls->L, f, clp);
- init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np-1));
+ f->p[fs->np++] = clp = luaF_newproto(L);
+ luaC_objbarrier(L, f, clp);
+ return clp;
+}
+
+
+/*
+** codes instruction to create new closure in parent function
+*/
+static void codeclosure (LexState *ls, expdesc *v) {
+ FuncState *fs = ls->fs->prev;
+ init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np - 1));
luaK_exp2nextreg(fs, v); /* fix it at stack top (for GC) */
}
@@ -529,13 +538,9 @@ static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) {
fs->nactvar = 0;
fs->firstlocal = ls->dyd->actvar.n;
fs->bl = NULL;
- f = luaF_newproto(L);
- fs->f = f;
+ f = fs->f;
f->source = ls->source;
f->maxstacksize = 2; /* registers 0/1 are always valid */
- /* anchor prototype (to avoid being collected) */
- setptvalue2s(L, L->top, f);
- incr_top(L);
fs->h = luaH_new(L);
/* anchor table of constants (to avoid being collected) */
sethvalue2s(L, L->top, fs->h);
@@ -568,20 +573,6 @@ static void close_func (LexState *ls) {
anchor_token(ls);
L->top--; /* pop table of constants */
luaC_checkGC(L);
- L->top--; /* pop prototype (after possible collection) */
-}
-
-
-/*
-** opens the main function, which is a regular vararg function with an
-** upvalue named LUA_ENV
-*/
-static void open_mainfunc (LexState *ls, FuncState *fs, BlockCnt *bl) {
- expdesc v;
- open_func(ls, fs, bl);
- fs->f->is_vararg = 1; /* main function is always vararg */
- init_exp(&v, VLOCAL, 0);
- newupvalue(fs, ls->envn, &v); /* create environment upvalue */
}
@@ -795,8 +786,9 @@ static void body (LexState *ls, expdesc *e, int ismethod, int line) {
/* body -> `(' parlist `)' block END */
FuncState new_fs;
BlockCnt bl;
- open_func(ls, &new_fs, &bl);
+ new_fs.f = addprototype(ls);
new_fs.f->linedefined = line;
+ open_func(ls, &new_fs, &bl);
checknext(ls, '(');
if (ismethod) {
new_localvarliteral(ls, "self"); /* create 'self' parameter */
@@ -807,7 +799,7 @@ static void body (LexState *ls, expdesc *e, int ismethod, int line) {
statlist(ls);
new_fs.f->lastlinedefined = ls->linenumber;
check_match(ls, TK_END, TK_FUNCTION, line);
- codeclosure(ls, new_fs.f, e);
+ codeclosure(ls, e);
close_func(ls);
}
@@ -879,8 +871,8 @@ static void funcargs (LexState *ls, expdesc *f, int line) {
*/
-static void prefixexp (LexState *ls, expdesc *v) {
- /* prefixexp -> NAME | '(' expr ')' */
+static void primaryexp (LexState *ls, expdesc *v) {
+ /* primaryexp -> NAME | '(' expr ')' */
switch (ls->t.token) {
case '(': {
int line = ls->linenumber;
@@ -901,12 +893,12 @@ static void prefixexp (LexState *ls, expdesc *v) {
}
-static void primaryexp (LexState *ls, expdesc *v) {
- /* primaryexp ->
- prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs } */
+static void suffixedexp (LexState *ls, expdesc *v) {
+ /* suffixedexp ->
+ primaryexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } */
FuncState *fs = ls->fs;
int line = ls->linenumber;
- prefixexp(ls, v);
+ primaryexp(ls, v);
for (;;) {
switch (ls->t.token) {
case '.': { /* fieldsel */
@@ -941,7 +933,7 @@ static void primaryexp (LexState *ls, expdesc *v) {
static void simpleexp (LexState *ls, expdesc *v) {
/* simpleexp -> NUMBER | STRING | NIL | TRUE | FALSE | ... |
- constructor | FUNCTION body | primaryexp */
+ constructor | FUNCTION body | suffixedexp */
switch (ls->t.token) {
case TK_NUMBER: {
init_exp(v, VKNUM, 0);
@@ -981,7 +973,7 @@ static void simpleexp (LexState *ls, expdesc *v) {
return;
}
default: {
- primaryexp(ls, v);
+ suffixedexp(ls, v);
return;
}
}
@@ -1141,10 +1133,10 @@ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) {
static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) {
expdesc e;
check_condition(ls, vkisvar(lh->v.k), "syntax error");
- if (testnext(ls, ',')) { /* assignment -> `,' primaryexp assignment */
+ if (testnext(ls, ',')) { /* assignment -> ',' suffixedexp assignment */
struct LHS_assign nv;
nv.prev = lh;
- primaryexp(ls, &nv.v);
+ suffixedexp(ls, &nv.v);
if (nv.v.k != VINDEXED)
check_conflict(ls, lh, &nv.v);
checklimit(ls->fs, nvars + ls->L->nCcalls, LUAI_MAXCCALLS,
@@ -1200,7 +1192,7 @@ static void gotostat (LexState *ls, int pc) {
static void checkrepeated (FuncState *fs, Labellist *ll, TString *label) {
int i;
for (i = fs->bl->firstlabel; i < ll->n; i++) {
- if (eqstr(label, ll->arr[i].name)) {
+ if (luaS_eqstr(label, ll->arr[i].name)) {
const char *msg = luaO_pushfstring(fs->ls->L,
"label " LUA_QS " already defined on line %d",
getstr(label), ll->arr[i].line);
@@ -1210,6 +1202,13 @@ static void checkrepeated (FuncState *fs, Labellist *ll, TString *label) {
}
+/* skip no-op statements */
+static void skipnoopstat (LexState *ls) {
+ while (ls->t.token == ';' || ls->t.token == TK_DBCOLON)
+ statement(ls);
+}
+
+
static void labelstat (LexState *ls, TString *label, int line) {
/* label -> '::' NAME '::' */
FuncState *fs = ls->fs;
@@ -1219,9 +1218,7 @@ static void labelstat (LexState *ls, TString *label, int line) {
checknext(ls, TK_DBCOLON); /* skip double colon */
/* create new entry for this label */
l = newlabelentry(ls, ll, label, line, fs->pc);
- /* skip other no-op statements */
- while (ls->t.token == ';' || ls->t.token == TK_DBCOLON)
- statement(ls);
+ skipnoopstat(ls); /* skip other no-op statements */
if (block_follow(ls, 0)) { /* label is last no-op statement in the block? */
/* assume that locals are already out of scope */
ll->arr[l].nactvar = fs->bl->nactvar;
@@ -1384,6 +1381,7 @@ static void test_then_block (LexState *ls, int *escapelist) {
luaK_goiffalse(ls->fs, &v); /* will jump to label if condition is true */
enterblock(fs, &bl, 0); /* must enter block before 'goto' */
gotostat(ls, v.t); /* handle goto/break */
+ skipnoopstat(ls); /* skip other no-op statements */
if (block_follow(ls, 0)) { /* 'goto' is the entire block? */
leaveblock(fs);
return; /* and that is it */
@@ -1480,13 +1478,15 @@ static void exprstat (LexState *ls) {
/* stat -> func | assignment */
FuncState *fs = ls->fs;
struct LHS_assign v;
- primaryexp(ls, &v.v);
- if (v.v.k == VCALL) /* stat -> func */
- SETARG_C(getcode(fs, &v.v), 1); /* call statement uses no results */
- else { /* stat -> assignment */
+ suffixedexp(ls, &v.v);
+ if (ls->t.token == '=' || ls->t.token == ',') { /* stat -> assignment ? */
v.prev = NULL;
assignment(ls, &v, 1);
}
+ else { /* stat -> func */
+ check_condition(ls, v.v.k == VCALL, "syntax error");
+ SETARG_C(getcode(fs, &v.v), 1); /* call statement uses no results */
+ }
}
@@ -1594,27 +1594,42 @@ static void statement (LexState *ls) {
/* }====================================================================== */
-Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
- Dyndata *dyd, const char *name, int firstchar) {
+/*
+** compiles the main function, which is a regular vararg function with an
+** upvalue named LUA_ENV
+*/
+static void mainfunc (LexState *ls, FuncState *fs) {
+ BlockCnt bl;
+ expdesc v;
+ open_func(ls, fs, &bl);
+ fs->f->is_vararg = 1; /* main function is always vararg */
+ init_exp(&v, VLOCAL, 0); /* create and... */
+ newupvalue(fs, ls->envn, &v); /* ...set environment upvalue */
+ luaX_next(ls); /* read first token */
+ statlist(ls); /* parse main body */
+ check(ls, TK_EOS);
+ close_func(ls);
+}
+
+
+Closure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
+ Dyndata *dyd, const char *name, int firstchar) {
LexState lexstate;
FuncState funcstate;
- BlockCnt bl;
- TString *tname = luaS_new(L, name);
- setsvalue2s(L, L->top, tname); /* push name to protect it */
+ Closure *cl = luaF_newLclosure(L, 1); /* create main closure */
+ /* anchor closure (to avoid being collected) */
+ setclLvalue(L, L->top, cl);
incr_top(L);
+ funcstate.f = cl->l.p = luaF_newproto(L);
+ funcstate.f->source = luaS_new(L, name); /* create and anchor TString */
lexstate.buff = buff;
lexstate.dyd = dyd;
dyd->actvar.n = dyd->gt.n = dyd->label.n = 0;
- luaX_setinput(L, &lexstate, z, tname, firstchar);
- open_mainfunc(&lexstate, &funcstate, &bl);
- luaX_next(&lexstate); /* read first token */
- statlist(&lexstate); /* main body */
- check(&lexstate, TK_EOS);
- close_func(&lexstate);
- L->top--; /* pop name */
+ luaX_setinput(L, &lexstate, z, funcstate.f->source, firstchar);
+ mainfunc(&lexstate, &funcstate);
lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs);
/* all scopes should be correctly finished */
lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0);
- return funcstate.f;
+ return cl; /* it's on the stack too */
}
diff --git a/depends/lua/src/lstate.c b/depends/lua/src/lstate.c
index 6e2801c49..3c00c2855 100644
--- a/depends/lua/src/lstate.c
+++ b/depends/lua/src/lstate.c
@@ -1,11 +1,12 @@
/*
-** $Id: lstate.c,v 2.92 2011/10/03 17:54:25 roberto Exp $
+** $Id: lstate.c,v 2.98 2012/05/30 12:33:44 roberto Exp $
** Global State
** See Copyright Notice in lua.h
*/
#include
+#include
#define lstate_c
#define LUA_CORE
@@ -38,7 +39,18 @@
#endif
-#define MEMERRMSG "not enough memory"
+#define MEMERRMSG "not enough memory"
+
+
+/*
+** a macro to help the creation of a unique random seed when a state is
+** created; the seed is used to randomize hashes.
+*/
+#if !defined(luai_makeseed)
+#include
+#define luai_makeseed() cast(size_t, time(NULL))
+#endif
+
/*
@@ -65,6 +77,28 @@ typedef struct LG {
#define fromstate(L) (cast(LX *, cast(lu_byte *, (L)) - offsetof(LX, l)))
+/*
+** Compute an initial seed as random as possible. In ANSI, rely on
+** Address Space Layout Randomization (if present) to increase
+** randomness..
+*/
+#define addbuff(b,p,e) \
+ { size_t t = cast(size_t, e); \
+ memcpy(buff + p, &t, sizeof(t)); p += sizeof(t); }
+
+static unsigned int makeseed (lua_State *L) {
+ char buff[4 * sizeof(size_t)];
+ unsigned int h = luai_makeseed();
+ int p = 0;
+ addbuff(buff, p, L); /* heap variable */
+ addbuff(buff, p, &h); /* local variable */
+ addbuff(buff, p, luaO_nilobject); /* global variable */
+ addbuff(buff, p, &lua_newstate); /* public function */
+ lua_assert(p == sizeof(buff));
+ return luaS_hash(buff, p, h);
+}
+
+
/*
** set GCdebt to a new value keeping the value (totalbytes + GCdebt)
** invariant
@@ -242,10 +276,11 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
g->frealloc = f;
g->ud = ud;
g->mainthread = L;
+ g->seed = makeseed(L);
g->uvhead.u.l.prev = &g->uvhead;
g->uvhead.u.l.next = &g->uvhead;
g->gcrunning = 0; /* no GC while building state */
- g->lastmajormem = 0;
+ g->GCestimate = 0;
g->strt.size = 0;
g->strt.nuse = 0;
g->strt.hash = NULL;
@@ -257,6 +292,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
g->allgc = NULL;
g->finobj = NULL;
g->tobefnz = NULL;
+ g->sweepgc = g->sweepfin = NULL;
g->gray = g->grayagain = NULL;
g->weak = g->ephemeron = g->allweak = NULL;
g->totalbytes = sizeof(LG);
diff --git a/depends/lua/src/lstring.c b/depends/lua/src/lstring.c
index adec415e7..8b959f19d 100644
--- a/depends/lua/src/lstring.c
+++ b/depends/lua/src/lstring.c
@@ -1,5 +1,5 @@
/*
-** $Id: lstring.c,v 2.19 2011/05/03 16:01:57 roberto Exp $
+** $Id: lstring.c,v 2.24 2012/05/11 14:14:42 roberto Exp $
** String table (keeps all strings handled by Lua)
** See Copyright Notice in lua.h
*/
@@ -18,7 +18,49 @@
#include "lstring.h"
+/*
+** Lua will use at most ~(2^LUAI_HASHLIMIT) bytes from a string to
+** compute its hash
+*/
+#if !defined(LUAI_HASHLIMIT)
+#define LUAI_HASHLIMIT 5
+#endif
+
+
+/*
+** equality for long strings
+*/
+int luaS_eqlngstr (TString *a, TString *b) {
+ size_t len = a->tsv.len;
+ lua_assert(a->tsv.tt == LUA_TLNGSTR && b->tsv.tt == LUA_TLNGSTR);
+ return (a == b) || /* same instance or... */
+ ((len == b->tsv.len) && /* equal length and ... */
+ (memcmp(getstr(a), getstr(b), len) == 0)); /* equal contents */
+}
+
+
+/*
+** equality for strings
+*/
+int luaS_eqstr (TString *a, TString *b) {
+ return (a->tsv.tt == b->tsv.tt) &&
+ (a->tsv.tt == LUA_TSHRSTR ? eqshrstr(a, b) : luaS_eqlngstr(a, b));
+}
+
+
+unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) {
+ unsigned int h = seed ^ l;
+ size_t l1;
+ size_t step = (l >> LUAI_HASHLIMIT) + 1;
+ for (l1 = l; l1 >= step; l1 -= step)
+ h = h ^ ((h<<5) + (h>>2) + cast_byte(str[l1 - 1]));
+ return h;
+}
+
+/*
+** resizes the string table
+*/
void luaS_resize (lua_State *L, int newsize) {
int i;
stringtable *tb = &G(L)->strt;
@@ -50,37 +92,49 @@ void luaS_resize (lua_State *L, int newsize) {
}
-static TString *newlstr (lua_State *L, const char *str, size_t l,
- unsigned int h) {
- size_t totalsize; /* total size of TString object */
- GCObject **list; /* (pointer to) list where it will be inserted */
+/*
+** creates a new string object
+*/
+static TString *createstrobj (lua_State *L, const char *str, size_t l,
+ int tag, unsigned int h, GCObject **list) {
TString *ts;
- stringtable *tb = &G(L)->strt;
- if (l+1 > (MAX_SIZET - sizeof(TString))/sizeof(char))
- luaM_toobig(L);
- if (tb->nuse >= cast(lu_int32, tb->size) && tb->size <= MAX_INT/2)
- luaS_resize(L, tb->size*2); /* too crowded */
+ size_t totalsize; /* total size of TString object */
totalsize = sizeof(TString) + ((l + 1) * sizeof(char));
- list = &tb->hash[lmod(h, tb->size)];
- ts = &luaC_newobj(L, LUA_TSTRING, totalsize, list, 0)->ts;
+ ts = &luaC_newobj(L, tag, totalsize, list, 0)->ts;
ts->tsv.len = l;
ts->tsv.hash = h;
- ts->tsv.reserved = 0;
+ ts->tsv.extra = 0;
memcpy(ts+1, str, l*sizeof(char));
((char *)(ts+1))[l] = '\0'; /* ending 0 */
- tb->nuse++;
return ts;
}
-TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {
+/*
+** creates a new short string, inserting it into string table
+*/
+static TString *newshrstr (lua_State *L, const char *str, size_t l,
+ unsigned int h) {
+ GCObject **list; /* (pointer to) list where it will be inserted */
+ stringtable *tb = &G(L)->strt;
+ TString *s;
+ if (tb->nuse >= cast(lu_int32, tb->size) && tb->size <= MAX_INT/2)
+ luaS_resize(L, tb->size*2); /* too crowded */
+ list = &tb->hash[lmod(h, tb->size)];
+ s = createstrobj(L, str, l, LUA_TSHRSTR, h, list);
+ tb->nuse++;
+ return s;
+}
+
+
+/*
+** checks whether short string exists and reuses it or creates a new one
+*/
+static TString *internshrstr (lua_State *L, const char *str, size_t l) {
GCObject *o;
- unsigned int h = cast(unsigned int, l); /* seed */
- size_t step = (l>>5)+1; /* if string is too long, don't hash all its chars */
- size_t l1;
- for (l1=l; l1>=step; l1-=step) /* compute hash */
- h = h ^ ((h<<5)+(h>>2)+cast(unsigned char, str[l1-1]));
- for (o = G(L)->strt.hash[lmod(h, G(L)->strt.size)];
+ global_State *g = G(L);
+ unsigned int h = luaS_hash(str, l, g->seed);
+ for (o = g->strt.hash[lmod(h, g->strt.size)];
o != NULL;
o = gch(o)->next) {
TString *ts = rawgco2ts(o);
@@ -92,10 +146,27 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {
return ts;
}
}
- return newlstr(L, str, l, h); /* not found; create a new string */
+ return newshrstr(L, str, l, h); /* not found; create a new string */
+}
+
+
+/*
+** new string (with explicit length)
+*/
+TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {
+ if (l <= LUAI_MAXSHORTLEN) /* short string? */
+ return internshrstr(L, str, l);
+ else {
+ if (l + 1 > (MAX_SIZET - sizeof(TString))/sizeof(char))
+ luaM_toobig(L);
+ return createstrobj(L, str, l, LUA_TLNGSTR, G(L)->seed, NULL);
+ }
}
+/*
+** new zero-terminated string
+*/
TString *luaS_new (lua_State *L, const char *str) {
return luaS_newlstr(L, str, strlen(str));
}
diff --git a/depends/lua/src/lstrlib.c b/depends/lua/src/lstrlib.c
index f5d61fd85..e13098bb6 100644
--- a/depends/lua/src/lstrlib.c
+++ b/depends/lua/src/lstrlib.c
@@ -1,5 +1,5 @@
/*
-** $Id: lstrlib.c,v 1.173 2011/11/30 18:24:56 roberto Exp $
+** $Id: lstrlib.c,v 1.176 2012/05/23 15:37:09 roberto Exp $
** Standard library for string operations and pattern-matching
** See Copyright Notice in lua.h
*/
@@ -30,7 +30,7 @@
/* macro to `unsign' a character */
-#define uchar(c) ((unsigned char)(c))
+#define uchar(c) ((unsigned char)(c))
@@ -119,7 +119,9 @@ static int str_rep (lua_State *L) {
char *p = luaL_buffinitsize(L, &b, totallen);
while (n-- > 1) { /* first n-1 copies (followed by separator) */
memcpy(p, s, l * sizeof(char)); p += l;
- memcpy(p, sep, lsep * sizeof(char)); p += lsep;
+ if (lsep > 0) { /* avoid empty 'memcpy' (may be expensive) */
+ memcpy(p, sep, lsep * sizeof(char)); p += lsep;
+ }
}
memcpy(p, s, l * sizeof(char)); /* last copy (not followed by separator) */
luaL_pushresultsize(&b, totallen);
@@ -745,20 +747,17 @@ static int str_gsub (lua_State *L) {
#if !defined(LUA_INTFRMLEN) /* { */
#if defined(LUA_USE_LONGLONG)
-#define LUA_INTFRMLEN "ll"
-#define LUA_INTFRM_T long long
+#define LUA_INTFRMLEN "ll"
+#define LUA_INTFRM_T long long
#else
-#define LUA_INTFRMLEN "l"
-#define LUA_INTFRM_T long
+#define LUA_INTFRMLEN "l"
+#define LUA_INTFRM_T long
#endif
#endif /* } */
-#define MAX_UINTFRM ((lua_Number)(~(unsigned LUA_INTFRM_T)0))
-#define MAX_INTFRM ((lua_Number)((~(unsigned LUA_INTFRM_T)0)/2))
-#define MIN_INTFRM (-(lua_Number)((~(unsigned LUA_INTFRM_T)0)/2) - 1)
/*
** LUA_FLTFRMLEN is the length modifier for float conversions in
@@ -767,8 +766,8 @@ static int str_gsub (lua_State *L) {
*/
#if !defined(LUA_FLTFRMLEN)
-#define LUA_FLTFRMLEN ""
-#define LUA_FLTFRM_T double
+#define LUA_FLTFRMLEN ""
+#define LUA_FLTFRM_T double
#endif
@@ -870,18 +869,22 @@ static int str_format (lua_State *L) {
}
case 'd': case 'i': {
lua_Number n = luaL_checknumber(L, arg);
- luaL_argcheck(L, (MIN_INTFRM - 1) < n && n < (MAX_INTFRM + 1), arg,
+ LUA_INTFRM_T ni = (LUA_INTFRM_T)n;
+ lua_Number diff = n - (lua_Number)ni;
+ luaL_argcheck(L, -1 < diff && diff < 1, arg,
"not a number in proper range");
addlenmod(form, LUA_INTFRMLEN);
- nb = sprintf(buff, form, (LUA_INTFRM_T)n);
+ nb = sprintf(buff, form, ni);
break;
}
case 'o': case 'u': case 'x': case 'X': {
lua_Number n = luaL_checknumber(L, arg);
- luaL_argcheck(L, 0 <= n && n < (MAX_UINTFRM + 1), arg,
+ unsigned LUA_INTFRM_T ni = (unsigned LUA_INTFRM_T)n;
+ lua_Number diff = n - (lua_Number)ni;
+ luaL_argcheck(L, -1 < diff && diff < 1, arg,
"not a non-negative number in proper range");
addlenmod(form, LUA_INTFRMLEN);
- nb = sprintf(buff, form, (unsigned LUA_INTFRM_T)n);
+ nb = sprintf(buff, form, ni);
break;
}
case 'e': case 'E': case 'f':
diff --git a/depends/lua/src/ltable.c b/depends/lua/src/ltable.c
index 9581add91..ffa5ecb36 100644
--- a/depends/lua/src/ltable.c
+++ b/depends/lua/src/ltable.c
@@ -1,5 +1,5 @@
/*
-** $Id: ltable.c,v 2.67 2011/11/30 12:41:45 roberto Exp $
+** $Id: ltable.c,v 2.71 2012/05/23 15:37:09 roberto Exp $
** Lua tables (hash)
** See Copyright Notice in lua.h
*/
@@ -48,10 +48,10 @@
#define MAXASIZE (1 << MAXBITS)
-#define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t))))
+#define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t))))
-#define hashstr(t,str) hashpow2(t, (str)->tsv.hash)
-#define hashboolean(t,p) hashpow2(t, p)
+#define hashstr(t,str) hashpow2(t, (str)->tsv.hash)
+#define hashboolean(t,p) hashpow2(t, p)
/*
@@ -98,7 +98,15 @@ static Node *mainposition (const Table *t, const TValue *key) {
switch (ttype(key)) {
case LUA_TNUMBER:
return hashnum(t, nvalue(key));
- case LUA_TSTRING:
+ case LUA_TLNGSTR: {
+ TString *s = rawtsvalue(key);
+ if (s->tsv.extra == 0) { /* no hash? */
+ s->tsv.hash = luaS_hash(getstr(s), s->tsv.len, s->tsv.hash);
+ s->tsv.extra = 1; /* now it has its hash */
+ }
+ return hashstr(t, rawtsvalue(key));
+ }
+ case LUA_TSHRSTR:
return hashstr(t, rawtsvalue(key));
case LUA_TBOOLEAN:
return hashboolean(t, bvalue(key));
@@ -453,12 +461,13 @@ const TValue *luaH_getint (Table *t, int key) {
/*
-** search function for strings
+** search function for short strings
*/
const TValue *luaH_getstr (Table *t, TString *key) {
Node *n = hashstr(t, key);
+ lua_assert(key->tsv.tt == LUA_TSHRSTR);
do { /* check whether `key' is somewhere in the chain */
- if (ttisstring(gkey(n)) && eqstr(rawtsvalue(gkey(n)), key))
+ if (ttisshrstring(gkey(n)) && eqshrstr(rawtsvalue(gkey(n)), key))
return gval(n); /* that's it */
else n = gnext(n);
} while (n);
@@ -470,9 +479,9 @@ const TValue *luaH_getstr (Table *t, TString *key) {
** main search function
*/
const TValue *luaH_get (Table *t, const TValue *key) {
- switch (ttypenv(key)) {
+ switch (ttype(key)) {
case LUA_TNIL: return luaO_nilobject;
- case LUA_TSTRING: return luaH_getstr(t, rawtsvalue(key));
+ case LUA_TSHRSTR: return luaH_getstr(t, rawtsvalue(key));
case LUA_TNUMBER: {
int k;
lua_Number n = nvalue(key);
diff --git a/depends/lua/src/lua.c b/depends/lua/src/lua.c
index e20ab86d2..7614c7030 100644
--- a/depends/lua/src/lua.c
+++ b/depends/lua/src/lua.c
@@ -1,5 +1,5 @@
/*
-** $Id: lua.c,v 1.203 2011/12/12 16:34:03 roberto Exp $
+** $Id: lua.c,v 1.205 2012/05/23 15:37:09 roberto Exp $
** Lua stand-alone interpreter
** See Copyright Notice in lua.h
*/
@@ -45,13 +45,13 @@
*/
#if defined(LUA_USE_ISATTY)
#include
-#define lua_stdin_is_tty() isatty(0)
+#define lua_stdin_is_tty() isatty(0)
#elif defined(LUA_WIN)
#include
#include
-#define lua_stdin_is_tty() _isatty(_fileno(stdin))
+#define lua_stdin_is_tty() _isatty(_fileno(stdin))
#else
-#define lua_stdin_is_tty() 1 /* assume stdin is a tty */
+#define lua_stdin_is_tty() 1 /* assume stdin is a tty */
#endif
@@ -66,19 +66,19 @@
#include
#include
#include
-#define lua_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL)
+#define lua_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL)
#define lua_saveline(L,idx) \
if (lua_rawlen(L,idx) > 0) /* non-empty line? */ \
add_history(lua_tostring(L, idx)); /* add it to history */
-#define lua_freeline(L,b) ((void)L, free(b))
+#define lua_freeline(L,b) ((void)L, free(b))
#elif !defined(lua_readline)
-#define lua_readline(L,b,p) \
+#define lua_readline(L,b,p) \
((void)L, fputs(p, stdout), fflush(stdout), /* show prompt */ \
fgets(b, LUA_MAXINPUT, stdin) != NULL) /* get line */
-#define lua_saveline(L,idx) { (void)L; (void)idx; }
-#define lua_freeline(L,b) { (void)L; (void)b; }
+#define lua_saveline(L,idx) { (void)L; (void)idx; }
+#define lua_freeline(L,b) { (void)L; (void)b; }
#endif
@@ -223,16 +223,11 @@ static int dostring (lua_State *L, const char *s, const char *name) {
static int dolibrary (lua_State *L, const char *name) {
int status;
- lua_pushglobaltable(L);
- lua_getfield(L, -1, "require");
+ lua_getglobal(L, "require");
lua_pushstring(L, name);
- status = docall(L, 1, 1);
- if (status == LUA_OK) {
- lua_setfield(L, -2, name); /* global[name] = require return */
- lua_pop(L, 1); /* remove global table */
- }
- else
- lua_remove(L, -2); /* remove global table (below error msg.) */
+ status = docall(L, 1, 1); /* call 'require(name)' */
+ if (status == LUA_OK)
+ lua_setglobal(L, name); /* global[name] = require return */
return report(L, status);
}
diff --git a/depends/lua/src/lundump.c b/depends/lua/src/lundump.c
index 80c7aa39b..54de011a4 100644
--- a/depends/lua/src/lundump.c
+++ b/depends/lua/src/lundump.c
@@ -1,5 +1,5 @@
/*
-** $Id: lundump.c,v 1.71 2011/12/07 10:39:12 lhf Exp $
+** $Id: lundump.c,v 2.22 2012/05/08 13:53:33 roberto Exp $
** load precompiled Lua chunks
** See Copyright Notice in lua.h
*/
@@ -27,7 +27,7 @@ typedef struct {
const char* name;
} LoadState;
-static void error(LoadState* S, const char* why)
+static l_noret error(LoadState* S, const char* why)
{
luaO_pushfstring(S->L,"%s: %s precompiled chunk",S->name,why);
luaD_throw(S->L,LUA_ERRSYNTAX);
@@ -39,7 +39,7 @@ static void error(LoadState* S, const char* why)
#define LoadVector(S,b,n,size) LoadMem(S,b,n,size)
#if !defined(luai_verifycode)
-#define luai_verifycode(L,b,f) (f)
+#define luai_verifycode(L,b,f) /* empty */
#endif
static void LoadBlock(LoadState* S, void* b, size_t size)
@@ -91,7 +91,7 @@ static void LoadCode(LoadState* S, Proto* f)
LoadVector(S,f->code,n,sizeof(Instruction));
}
-static Proto* LoadFunction(LoadState* S);
+static void LoadFunction(LoadState* S, Proto* f);
static void LoadConstants(LoadState* S, Proto* f)
{
@@ -118,13 +118,18 @@ static void LoadConstants(LoadState* S, Proto* f)
case LUA_TSTRING:
setsvalue2n(S->L,o,LoadString(S));
break;
+ default: lua_assert(0);
}
}
n=LoadInt(S);
f->p=luaM_newvector(S->L,n,Proto*);
f->sizep=n;
for (i=0; ip[i]=NULL;
- for (i=0; ip[i]=LoadFunction(S);
+ for (i=0; ip[i]=luaF_newproto(S->L);
+ LoadFunction(S,f->p[i]);
+ }
}
static void LoadUpvalues(LoadState* S, Proto* f)
@@ -163,10 +168,8 @@ static void LoadDebug(LoadState* S, Proto* f)
for (i=0; iupvalues[i].name=LoadString(S);
}
-static Proto* LoadFunction(LoadState* S)
+static void LoadFunction(LoadState* S, Proto* f)
{
- Proto* f=luaF_newproto(S->L);
- setptvalue2s(S->L,S->L->top,f); incr_top(S->L);
f->linedefined=LoadInt(S);
f->lastlinedefined=LoadInt(S);
f->numparams=LoadByte(S);
@@ -176,8 +179,6 @@ static Proto* LoadFunction(LoadState* S)
LoadConstants(S,f);
LoadUpvalues(S,f);
LoadDebug(S,f);
- S->L->top--;
- return f;
}
/* the code below must be consistent with the code in luaU_header */
@@ -202,9 +203,10 @@ static void LoadHeader(LoadState* S)
/*
** load precompiled chunk
*/
-Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name)
+Closure* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name)
{
LoadState S;
+ Closure* cl;
if (*name=='@' || *name=='=')
S.name=name+1;
else if (*name==LUA_SIGNATURE[0])
@@ -215,7 +217,19 @@ Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name)
S.Z=Z;
S.b=buff;
LoadHeader(&S);
- return luai_verifycode(L,buff,LoadFunction(&S));
+ cl=luaF_newLclosure(L,1);
+ setclLvalue(L,L->top,cl); incr_top(L);
+ cl->l.p=luaF_newproto(L);
+ LoadFunction(&S,cl->l.p);
+ if (cl->l.p->sizeupvalues != 1)
+ {
+ Proto* p=cl->l.p;
+ cl=luaF_newLclosure(L,cl->l.p->sizeupvalues);
+ cl->l.p=p;
+ setclLvalue(L,L->top-1,cl);
+ }
+ luai_verifycode(L,buff,cl->l.p);
+ return cl;
}
#define MYINT(s) (s[0]-'0')
diff --git a/depends/lua/src/lvm.c b/depends/lua/src/lvm.c
index 694971b11..b77eac26d 100644
--- a/depends/lua/src/lvm.c
+++ b/depends/lua/src/lvm.c
@@ -1,5 +1,5 @@
/*
-** $Id: lvm.c,v 2.147 2011/12/07 14:43:55 roberto Exp $
+** $Id: lvm.c,v 2.152 2012/06/08 15:14:04 roberto Exp $
** Lua virtual machine
** See Copyright Notice in lua.h
*/
@@ -60,10 +60,15 @@ int luaV_tostring (lua_State *L, StkId obj) {
static void traceexec (lua_State *L) {
CallInfo *ci = L->ci;
lu_byte mask = L->hookmask;
- if ((mask & LUA_MASKCOUNT) && L->hookcount == 0) {
- resethookcount(L);
- luaD_hook(L, LUA_HOOKCOUNT, -1);
+ int counthook = ((mask & LUA_MASKCOUNT) && L->hookcount == 0);
+ if (counthook)
+ resethookcount(L); /* reset count */
+ if (ci->callstatus & CIST_HOOKYIELD) { /* called hook last time? */
+ ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */
+ return; /* do not call hook again (VM yielded, so it did not move) */
}
+ if (counthook)
+ luaD_hook(L, LUA_HOOKCOUNT, -1); /* call count hook */
if (mask & LUA_MASKLINE) {
Proto *p = ci_func(ci)->p;
int npc = pcRel(ci->u.l.savedpc, p);
@@ -71,11 +76,15 @@ static void traceexec (lua_State *L) {
if (npc == 0 || /* call linehook when enter a new function, */
ci->u.l.savedpc <= L->oldpc || /* when jump back (loop), or when */
newline != getfuncline(p, pcRel(L->oldpc, p))) /* enter a new line */
- luaD_hook(L, LUA_HOOKLINE, newline);
+ luaD_hook(L, LUA_HOOKLINE, newline); /* call line hook */
}
L->oldpc = ci->u.l.savedpc;
if (L->status == LUA_YIELD) { /* did hook yield? */
+ if (counthook)
+ L->hookcount = 1; /* undo decrement to zero */
ci->u.l.savedpc--; /* undo increment (resume will increment it again) */
+ ci->callstatus |= CIST_HOOKYIELD; /* mark that it yieled */
+ ci->func = L->top - 1; /* protect stack below results */
luaD_throw(L, LUA_YIELD);
}
}
@@ -258,7 +267,8 @@ int luaV_equalobj_ (lua_State *L, const TValue *t1, const TValue *t2) {
case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */
case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2);
case LUA_TLCF: return fvalue(t1) == fvalue(t2);
- case LUA_TSTRING: return eqstr(rawtsvalue(t1), rawtsvalue(t2));
+ case LUA_TSHRSTR: return eqshrstr(rawtsvalue(t1), rawtsvalue(t2));
+ case LUA_TLNGSTR: return luaS_eqlngstr(rawtsvalue(t1), rawtsvalue(t2));
case LUA_TUSERDATA: {
if (uvalue(t1) == uvalue(t2)) return 1;
else if (L == NULL) return 0;
@@ -293,7 +303,7 @@ void luaV_concat (lua_State *L, int total) {
else if (tsvalue(top-1)->len == 0) /* second operand is empty? */
(void)tostring(L, top - 2); /* result is first operand */
else if (ttisstring(top-2) && tsvalue(top-2)->len == 0) {
- setsvalue2s(L, top-2, rawtsvalue(top-1)); /* result is second op. */
+ setobjs2s(L, top - 2, top - 1); /* result is second op. */
}
else {
/* at least two non-empty string values; get as many as possible */
@@ -394,7 +404,8 @@ static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base,
int nup = p->sizeupvalues;
Upvaldesc *uv = p->upvalues;
int i;
- Closure *ncl = luaF_newLclosure(L, p);
+ Closure *ncl = luaF_newLclosure(L, nup);
+ ncl->l.p = p;
setclLvalue(L, ra, ncl); /* anchor new closure in stack */
for (i = 0; i < nup; i++) { /* fill in its upvalues */
if (uv[i].instack) /* upvalue refers to local variable? */
@@ -500,7 +511,11 @@ void luaV_finishOp (lua_State *L) {
#define Protect(x) { {x;}; base = ci->u.l.base; }
-#define checkGC(L,c) Protect(luaC_condGC(L, c); luai_threadyield(L);)
+#define checkGC(L,c) \
+ Protect( luaC_condGC(L,{L->top = (c); /* limit of live values */ \
+ luaC_step(L); \
+ L->top = ci->top;}) /* restore top */ \
+ luai_threadyield(L); )
#define arith_op(op,tm) { \
@@ -593,11 +608,7 @@ void luaV_execute (lua_State *L) {
sethvalue(L, ra, t);
if (b != 0 || c != 0)
luaH_resize(L, t, luaO_fb2int(b), luaO_fb2int(c));
- checkGC(L,
- L->top = ra + 1; /* limit of live values */
- luaC_step(L);
- L->top = ci->top; /* restore top */
- )
+ checkGC(L, ra + 1);
)
vmcase(OP_SELF,
StkId rb = RB(i);
@@ -649,10 +660,7 @@ void luaV_execute (lua_State *L) {
ra = RA(i); /* 'luav_concat' may invoke TMs and move the stack */
rb = b + base;
setobjs2s(L, ra, rb);
- checkGC(L,
- L->top = (ra >= rb ? ra + 1 : rb); /* limit of live values */
- luaC_step(L);
- )
+ checkGC(L, (ra >= rb ? ra + 1 : rb));
L->top = ci->top; /* restore top */
)
vmcase(OP_JMP,
@@ -830,11 +838,7 @@ void luaV_execute (lua_State *L) {
pushclosure(L, p, cl->upvals, base, ra); /* create a new one */
else
setclLvalue(L, ra, ncl); /* push cashed closure */
- checkGC(L,
- L->top = ra + 1; /* limit of live values */
- luaC_step(L);
- L->top = ci->top; /* restore top */
- )
+ checkGC(L, ra + 1);
)
vmcase(OP_VARARG,
int b = GETARG_B(i) - 1;
diff --git a/depends/lua/src/lzio.c b/depends/lua/src/lzio.c
index 354f94e7c..8b77054e0 100644
--- a/depends/lua/src/lzio.c
+++ b/depends/lua/src/lzio.c
@@ -1,6 +1,6 @@
/*
-** $Id: lzio.c,v 1.34 2011/07/15 12:35:32 roberto Exp $
-** a generic input stream interface
+** $Id: lzio.c,v 1.35 2012/05/14 13:34:18 roberto Exp $
+** Buffered streams
** See Copyright Notice in lua.h
*/
From eeaae916edc28baa065e277acde69b0674fd3fd2 Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Sun, 17 Jun 2012 16:01:08 +0400
Subject: [PATCH 11/14] Reapply dfhack-specific lua build configuration.
---
depends/lua/include/luaconf.h | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/depends/lua/include/luaconf.h b/depends/lua/include/luaconf.h
index e4335df90..766752ff8 100644
--- a/depends/lua/include/luaconf.h
+++ b/depends/lua/include/luaconf.h
@@ -89,25 +89,21 @@
** In Windows, any exclamation mark ('!') in the path is replaced by the
** path of the directory of the executable file of the current process.
*/
-#define LUA_LDIR "!\\lua\\"
+#define LUA_LDIR "!\\hack\\lua\\"
#define LUA_CDIR "!\\"
#define LUA_PATH_DEFAULT \
- LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \
- LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua;" ".\\?.lua"
+ LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" ".\\?.lua"
#define LUA_CPATH_DEFAULT \
- LUA_CDIR"?.dll;" LUA_CDIR"loadall.dll;" ".\\?.dll"
+ LUA_CDIR"?.dll;" ".\\?.dll"
#else /* }{ */
-#define LUA_VDIR LUA_VERSION_MAJOR "." LUA_VERSION_MINOR "/"
-#define LUA_ROOT "/usr/local/"
-#define LUA_LDIR LUA_ROOT "share/lua/" LUA_VDIR
-#define LUA_CDIR LUA_ROOT "lib/lua/" LUA_VDIR
+#define LUA_LDIR "./hack/lua/"
+#define LUA_CDIR "./hack/"
#define LUA_PATH_DEFAULT \
- LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \
- LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua;" "./?.lua"
+ LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" "./?.lua"
#define LUA_CPATH_DEFAULT \
- LUA_CDIR"?.so;" LUA_CDIR"loadall.so;" "./?.so"
+ LUA_CDIR"?.so;" "./?.so"
#endif /* } */
@@ -142,11 +138,15 @@
*/
#if defined(LUA_BUILD_AS_DLL) /* { */
+#if defined(_MSC_VER)
#if defined(LUA_CORE) || defined(LUA_LIB) /* { */
#define LUA_API __declspec(dllexport)
#else /* }{ */
#define LUA_API __declspec(dllimport)
#endif /* } */
+#else
+#define LUA_API __attribute__ ((visibility("default")))
+#endif
#else /* }{ */
From 16ae6cb1fb06217e5b32f74ec72ce9fce1923b56 Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Sun, 17 Jun 2012 15:48:32 +0400
Subject: [PATCH 12/14] Fix lua bug: 'peaceful' unwind of yielded pcall doesn't
restore errfunc.
I.e. if the pcall results in no error, but a yield happens inside it,
the active errfunc is not restored to its previous value.
---
depends/lua/src/ldo.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/depends/lua/src/ldo.c b/depends/lua/src/ldo.c
index d18e33cd4..35d95ae4e 100644
--- a/depends/lua/src/ldo.c
+++ b/depends/lua/src/ldo.c
@@ -402,6 +402,9 @@ static void finishCcall (lua_State *L) {
int n;
lua_assert(ci->u.c.k != NULL); /* must have a continuation */
lua_assert(L->nny == 0);
+ /* finish 'lua_pcallk' */
+ if (ci->callstatus & CIST_YPCALL)
+ L->errfunc = ci->u.c.old_errfunc;
/* finish 'lua_callk' */
adjustresults(L, ci->nresults);
/* call continuation function */
From dc6cb61979458d00aa5c9a8d1f635d35891ca6ee Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Sun, 17 Jun 2012 18:44:59 +0400
Subject: [PATCH 13/14] Add more offset finders to the script.
---
library/lua/memscan.lua | 98 +++++++----
library/lua/utils.lua | 6 +-
scripts/devel/find-offsets.lua | 288 +++++++++++++++++++++++++++------
3 files changed, 311 insertions(+), 81 deletions(-)
diff --git a/library/lua/memscan.lua b/library/lua/memscan.lua
index e5a0c6f72..95b9197b1 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 4fac56ece..93ee840c4 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
diff --git a/scripts/devel/find-offsets.lua b/scripts/devel/find-offsets.lua
index ef16026e3..c9293b7b5 100644
--- a/scripts/devel/find-offsets.lua
+++ b/scripts/devel/find-offsets.lua
@@ -3,9 +3,19 @@
local utils = require 'utils'
local ms = require 'memscan'
-local scan_all = false
local is_known = dfhack.internal.getAddress
+local scan_all = false
+local force_scan = {}
+
+for _,v in ipairs({...}) do
+ if v == 'all' then
+ scan_all = true
+ else
+ force_scan[v] = true
+ end
+end
+
collectgarbage()
print[[
@@ -48,6 +58,52 @@ local function validate_offset(name,validator,addr,tname,...)
ms.found_offset(name,obj)
end
+local function exec_finder(finder, names)
+ local search = scan_all
+ if type(names) ~= 'table' then
+ names = { names }
+ end
+ for _,v in ipairs(names) do
+ if force_scan[v] or not is_known(v) then
+ search = true
+ end
+ end
+ if search then
+ if not dfhack.safecall(finder) then
+ if not utils.prompt_yes_no('Proceed with the rest of the script?') then
+ searcher:reset()
+ error('Quit')
+ end
+ end
+ else
+ print('Already known: '..table.concat(names,', '))
+ end
+end
+
+local ordinal_names = {
+ [0] = '1st entry',
+ [1] = '2nd entry'
+}
+setmetatable(ordinal_names, {
+ __index = function(self,idx) return (idx+1)..'th entry' end
+})
+
+local function list_index_choices(length_func)
+ return function(id)
+ if id > 0 then
+ local ok, len = pcall(length_func)
+ if not ok then
+ len = 5
+ elseif len > 10 then
+ len = 10
+ end
+ return id % len
+ else
+ return 0
+ end
+ end
+end
+
--
-- Cursor group
--
@@ -90,19 +146,14 @@ local function find_cursor()
return false
end
-if scan_all or not (
- is_known 'cursor' and is_known 'selection_rect' and
- is_known 'gamemode' and is_known 'gametype'
-) then
- find_cursor()
-end
+exec_finder(find_cursor, { 'cursor', 'selection_rect', 'gamemode', 'gametype' })
--
-- Announcements
--
local function find_announcements()
- idx, addr = data.int32_t:find_one{
+ local idx, addr = data.int32_t:find_one{
25, 25, 31, 31, 24, 24, 40, 40, 40, 40, 40, 40, 40
}
if idx then
@@ -113,9 +164,7 @@ local function find_announcements()
dfhack.printerr('Could not find announcements.')
end
-if scan_all or not is_known 'announcements' then
- find_announcements()
-end
+exec_finder(find_announcements, 'announcements')
--
-- d_init
@@ -142,7 +191,7 @@ local function is_valid_d_init(di)
end
local function find_d_init()
- idx, addr = data.int16_t:find_one{
+ local idx, addr = data.int16_t:find_one{
1,0, 2,0, 5,0, 25,0, -- path_cost
4,4, -- embark_rect
20,1000,1000,1000,1000 -- store_dist
@@ -155,10 +204,30 @@ local function find_d_init()
dfhack.printerr('Could not find d_init')
end
-if scan_all or not is_known 'd_init' then
- find_d_init()
+exec_finder(find_d_init, 'd_init')
+
+--
+-- gview
+--
+
+local function find_gview()
+ local vs_vtable = dfhack.internal.getVTable('viewscreenst')
+ if not vs_vtable then
+ dfhack.printerr('Cannot search for gview - no viewscreenst vtable.')
+ return
+ end
+
+ local idx, addr = data.uint32_t:find_one{0, vs_vtable}
+ if idx then
+ ms.found_offset('gview', addr)
+ return
+ end
+
+ dfhack.printerr('Could not find gview')
end
+exec_finder(find_gview, 'gview')
+
--
-- World
--
@@ -184,10 +253,9 @@ local function is_valid_world(world)
end
local function find_world()
- local addr = ms.find_menu_cursor(
- searcher, [[
+ local addr = searcher:find_menu_cursor([[
Searching for world. Please open the stockpile creation
-menu, and follow instructions below:]],
+menu, and select different types as instructed below:]],
'int32_t',
{ 'Corpses', 'Refuse', 'Stone', 'Wood', 'Gems', 'Bars', 'Cloth', 'Leather', 'Ammo', 'Coins' },
df.stockpile_category
@@ -195,9 +263,7 @@ menu, and follow instructions below:]],
validate_offset('world', is_valid_world, addr, df.world, 'selected_stockpile_type')
end
-if scan_all or not is_known 'world' then
- find_world()
-end
+exec_finder(find_world, 'world')
--
-- UI
@@ -220,10 +286,9 @@ local function is_valid_ui(ui)
end
local function find_ui()
- local addr = ms.find_menu_cursor(
- searcher, [[
+ local addr = searcher:find_menu_cursor([[
Searching for ui. Please open the designation
-menu, and follow instructions below:]],
+menu, and switch modes as instructed below:]],
'int16_t',
{ 'DesignateMine', 'DesignateChannel', 'DesignateRemoveRamps', 'DesignateUpStair',
'DesignateDownStair', 'DesignateUpDownStair', 'DesignateUpRamp', 'DesignateChopTrees' },
@@ -232,9 +297,7 @@ menu, and follow instructions below:]],
validate_offset('ui', is_valid_ui, addr, df.ui, 'main', 'mode')
end
-if scan_all or not is_known 'ui' then
- find_ui()
-end
+exec_finder(find_ui, 'ui')
--
-- ui_sidebar_menus
@@ -261,21 +324,19 @@ local function is_valid_ui_sidebar_menus(usm)
end
local function find_ui_sidebar_menus()
- local addr = ms.find_menu_cursor(
- searcher, [[
+ local addr = searcher:find_menu_cursor([[
Searching for ui_sidebar_menus. Please open the add job
ui of Mason, Craftsdwarfs, or Carpenters workshop, and
select entries in the list:]],
'int32_t',
- { 0, 1, 2, 3, 4, 5, 6 }
+ { 0, 1, 2, 3, 4, 5, 6 },
+ ordinal_names
)
validate_offset('ui_sidebar_menus', is_valid_ui_sidebar_menus,
addr, df.ui_sidebar_menus, 'workshop_job', 'cursor')
end
-if scan_all or not is_known 'ui_sidebar_menus' then
- find_ui_sidebar_menus()
-end
+exec_finder(find_ui_sidebar_menus, 'ui_sidebar_menus')
--
-- ui_build_selector
@@ -299,8 +360,7 @@ local function is_valid_ui_build_selector(ubs)
end
local function find_ui_build_selector()
- local addr = ms.find_menu_cursor(
- searcher, [[
+ local addr = searcher:find_menu_cursor([[
Searching for ui_build_selector. Please start constructing
a pressure plate, and enable creatures. Then change the min
weight as requested, remembering that the ui truncates the
@@ -312,9 +372,7 @@ number, so when it shows "Min (5000df", it means 50000:]],
addr, df.ui_build_selector, 'plate_info', 'unit_min')
end
-if scan_all or not is_known 'ui_build_selector' then
- find_ui_build_selector()
-end
+exec_finder(find_ui_build_selector, 'ui_build_selector')
--
-- ui_selected_unit
@@ -322,7 +380,7 @@ end
local function find_ui_selected_unit()
if not is_known 'world' then
- dfhack.printerr('Cannot find ui_selected_unit: no world')
+ dfhack.printerr('Cannot search for ui_selected_unit: no world')
return
end
@@ -330,30 +388,27 @@ local function find_ui_selected_unit()
dfhack.units.setNickname(unit, i)
end
- local addr = ms.find_menu_cursor(
- searcher, [[
+ local addr = searcher:find_menu_cursor([[
Searching for ui_selected_unit. Please activate the 'v'
mode, point it at units, and enter their numeric nickname
into the prompts below:]],
'int32_t',
function()
return utils.prompt_input(' Enter index: ', utils.check_number)
- end
+ end,
+ 'noprompt'
)
ms.found_offset('ui_selected_unit', addr)
end
-if scan_all or not is_known 'ui_selected_unit' then
- find_ui_selected_unit()
-end
+exec_finder(find_ui_selected_unit, 'ui_selected_unit')
--
-- ui_unit_view_mode
--
local function find_ui_unit_view_mode()
- local addr = ms.find_menu_cursor(
- searcher, [[
+ local addr = searcher:find_menu_cursor([[
Searching for ui_unit_view_mode. Having selected a unit
with 'v', switch the pages as requested:]],
'int32_t',
@@ -363,6 +418,143 @@ with 'v', switch the pages as requested:]],
ms.found_offset('ui_unit_view_mode', addr)
end
-if scan_all or not is_known 'ui_unit_view_mode' then
- find_ui_unit_view_mode()
+exec_finder(find_ui_unit_view_mode, 'ui_unit_view_mode')
+
+--
+-- ui_look_cursor
+--
+
+local function look_item_list_count()
+ return #df.global.ui_look_list.items
+end
+
+local function find_ui_look_cursor()
+ local addr = searcher:find_menu_cursor([[
+Searching for ui_look_cursor. Please activate the 'k'
+mode, find a tile with many items or units on the ground,
+and select list entries as instructed:]],
+ 'int32_t',
+ list_index_choices(look_item_list_count),
+ ordinal_names
+ )
+ ms.found_offset('ui_look_cursor', addr)
+end
+
+exec_finder(find_ui_look_cursor, 'ui_look_cursor')
+
+--
+-- ui_building_item_cursor
+--
+
+local function building_item_list_count()
+ return #df.global.world.selected_building.contained_items
+end
+
+local function find_ui_building_item_cursor()
+ local addr = searcher:find_menu_cursor([[
+Searching for ui_building_item_cursor. Please activate the 't'
+mode, find a cluttered workshop, trade depot, or other building
+with many contained items, and select as instructed:]],
+ 'int32_t',
+ list_index_choices(building_item_list_count),
+ ordinal_names
+ )
+ ms.found_offset('ui_building_item_cursor', addr)
+end
+
+exec_finder(find_ui_building_item_cursor, 'ui_building_item_cursor')
+
+--
+-- ui_workshop_in_add
+--
+
+local function find_ui_workshop_in_add()
+ local addr = searcher:find_menu_cursor([[
+Searching for ui_workshop_in_add. Please activate the 'q'
+mode, find a workshop without jobs (or delete jobs),
+and do as instructed:]],
+ 'int8_t',
+ { 1, 0 },
+ { [1] = 'enter the add job menu',
+ [0] = 'add job, thus exiting the menu' }
+ )
+ ms.found_offset('ui_workshop_in_add', addr)
+end
+
+--exec_finder(find_ui_workshop_in_add, 'ui_workshop_in_add')
+
+--
+-- ui_workshop_job_cursor
+--
+
+local function workshop_job_list_count()
+ return #df.global.world.selected_building.jobs
+end
+
+local function find_ui_workshop_job_cursor()
+ local addr = searcher:find_menu_cursor([[
+Searching for ui_workshop_job_cursor. Please activate the 'q'
+mode, find a workshop with many jobs, and select as instructed:]],
+ 'int32_t',
+ list_index_choices(workshop_job_list_count),
+ ordinal_names
+ )
+ ms.found_offset('ui_workshop_job_cursor', addr)
+end
+
+exec_finder(find_ui_workshop_job_cursor, 'ui_workshop_job_cursor')
+
+--
+-- window_x
+--
+
+local function find_window_x()
+ local addr = searcher:find_counter([[
+Searching for window_x. Please exit to main dwarfmode menu,
+scroll to the LEFT edge, then do as instructed:]],
+ 'int32_t', 10,
+ 'Please press Right to scroll right one step.'
+ )
+ ms.found_offset('window_x', addr)
+end
+
+exec_finder(find_window_x, 'window_x')
+
+--
+-- window_y
+--
+
+local function find_window_y()
+ local addr = searcher:find_counter([[
+Searching for window_y. Please exit to main dwarfmode menu,
+scroll to the TOP edge, then do as instructed:]],
+ 'int32_t', 10,
+ 'Please press Down to scroll down one step.'
+ )
+ ms.found_offset('window_y', addr)
end
+
+exec_finder(find_window_y, 'window_y')
+
+--
+-- window_z
+--
+
+local function find_window_z()
+ local addr = searcher:find_counter([[
+Searching for window_z. Please exit to main dwarfmode menu,
+scroll to ground level, then do as instructed:]],
+ 'int32_t', -1,
+ "Please press '>' to scroll 1 Z level down."
+ )
+ ms.found_offset('window_z', addr)
+end
+
+--exec_finder(find_window_z, 'window_z')
+
+--
+-- THE END
+--
+
+print('Done.')
+searcher:reset()
From a6bfc670389698b5d3e61e7322a5231450c420f6 Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Sun, 17 Jun 2012 21:40:08 +0400
Subject: [PATCH 14/14] Find a tweak to make two search recipes work, and add
two more.
---
scripts/devel/find-offsets.lua | 69 +++++++++++++++++++++++++++-------
1 file changed, 55 insertions(+), 14 deletions(-)
diff --git a/scripts/devel/find-offsets.lua b/scripts/devel/find-offsets.lua
index c9293b7b5..6b3c31576 100644
--- a/scripts/devel/find-offsets.lua
+++ b/scripts/devel/find-offsets.lua
@@ -5,15 +5,9 @@ local ms = require 'memscan'
local is_known = dfhack.internal.getAddress
-local scan_all = false
local force_scan = {}
-
for _,v in ipairs({...}) do
- if v == 'all' then
- scan_all = true
- else
- force_scan[v] = true
- end
+ force_scan[v] = true
end
collectgarbage()
@@ -43,7 +37,7 @@ if not data then
error('Could not find data segment')
end
-print('Data section: '..tostring(data))
+print('\nData section: '..tostring(data))
if data.size < 5000000 then
error('Data segment too short.')
end
@@ -59,10 +53,10 @@ local function validate_offset(name,validator,addr,tname,...)
end
local function exec_finder(finder, names)
- local search = scan_all
if type(names) ~= 'table' then
names = { names }
end
+ local search = force_scan['all']
for _,v in ipairs(names) do
if force_scan[v] or not is_known(v) then
search = true
@@ -472,7 +466,9 @@ local function find_ui_workshop_in_add()
local addr = searcher:find_menu_cursor([[
Searching for ui_workshop_in_add. Please activate the 'q'
mode, find a workshop without jobs (or delete jobs),
-and do as instructed:]],
+and do as instructed below.
+
+NOTE: After first 3 steps resize the game window.]],
'int8_t',
{ 1, 0 },
{ [1] = 'enter the add job menu',
@@ -481,7 +477,7 @@ and do as instructed:]],
ms.found_offset('ui_workshop_in_add', addr)
end
---exec_finder(find_ui_workshop_in_add, 'ui_workshop_in_add')
+exec_finder(find_ui_workshop_in_add, 'ui_workshop_in_add')
--
-- ui_workshop_job_cursor
@@ -504,6 +500,49 @@ end
exec_finder(find_ui_workshop_job_cursor, 'ui_workshop_job_cursor')
+--
+-- ui_building_in_assign
+--
+
+local function find_ui_building_in_assign()
+ local addr = searcher:find_menu_cursor([[
+Searching for ui_building_in_assign. Please activate
+the 'q' mode, select a room building (e.g. a bedroom)
+and do as instructed below.
+
+NOTE: After first 3 steps resize the game window.]],
+ 'int8_t',
+ { 1, 0 },
+ { [1] = 'enter the Assign owner menu',
+ [0] = 'press Esc to exit assign' }
+ )
+ ms.found_offset('ui_building_in_assign', addr)
+end
+
+exec_finder(find_ui_building_in_assign, 'ui_building_in_assign')
+
+--
+-- ui_building_in_resize
+--
+
+local function find_ui_building_in_resize()
+ local addr = searcher:find_menu_cursor([[
+Searching for ui_building_in_resize. Please activate
+the 'q' mode, select a room building (e.g. a bedroom)
+and do as instructed below.
+
+NOTE: After first 3 steps resize the game window.]],
+ 'int8_t',
+ { 1, 0 },
+ { [1] = 'enter the Resize room mode',
+ [0] = 'press Esc to exit resize' }
+ )
+ ms.found_offset('ui_building_in_resize', addr)
+end
+
+exec_finder(find_ui_building_in_resize, 'ui_building_in_resize')
+
+
--
-- window_x
--
@@ -543,14 +582,16 @@ exec_finder(find_window_y, 'window_y')
local function find_window_z()
local addr = searcher:find_counter([[
Searching for window_z. Please exit to main dwarfmode menu,
-scroll to ground level, then do as instructed:]],
+scroll to ground level, then do as instructed below.
+
+NOTE: After first 3 steps resize the game window.]],
'int32_t', -1,
- "Please press '>' to scroll 1 Z level down."
+ "Please press '>' to scroll one Z level down."
)
ms.found_offset('window_z', addr)
end
---exec_finder(find_window_z, 'window_z')
+exec_finder(find_window_z, 'window_z')
--
-- THE END