aboutsummaryrefslogtreecommitdiff
path: root/engines/sword25/script/luabindhelper.cpp
diff options
context:
space:
mode:
authorEugene Sandulenko2010-07-29 19:53:02 +0000
committerEugene Sandulenko2010-10-12 21:38:20 +0000
commita683a420a9e43705c972b5e74d55e319729e1a81 (patch)
treebde6e4abd417bdfaec120aa951da9a19be36b654 /engines/sword25/script/luabindhelper.cpp
parent7723d91c957d07205c51be32498d45cd0a78568f (diff)
downloadscummvm-rg350-a683a420a9e43705c972b5e74d55e319729e1a81.tar.gz
scummvm-rg350-a683a420a9e43705c972b5e74d55e319729e1a81.tar.bz2
scummvm-rg350-a683a420a9e43705c972b5e74d55e319729e1a81.zip
SWORD25: Importing original sources
svn-id: r53171
Diffstat (limited to 'engines/sword25/script/luabindhelper.cpp')
-rwxr-xr-xengines/sword25/script/luabindhelper.cpp419
1 files changed, 419 insertions, 0 deletions
diff --git a/engines/sword25/script/luabindhelper.cpp b/engines/sword25/script/luabindhelper.cpp
new file mode 100755
index 0000000000..eccc568989
--- /dev/null
+++ b/engines/sword25/script/luabindhelper.cpp
@@ -0,0 +1,419 @@
+// -----------------------------------------------------------------------------
+// This file is part of Broken Sword 2.5
+// Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdörfer
+//
+// Broken Sword 2.5 is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// Broken Sword 2.5 is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Broken Sword 2.5; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+// -----------------------------------------------------------------------------
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "kernel/kernel.h"
+#include "luabindhelper.h"
+#include "luascript.h"
+#include <sstream>
+
+#define BS_LOG_PREFIX "LUABINDHELPER"
+
+// -----------------------------------------------------------------------------
+
+namespace
+{
+ const char * METATABLES_TABLE_NAME = "__METATABLES";
+ const char * PERMANENTS_TABLE_NAME = "Permanents";
+
+ bool RegisterPermanent(lua_State * L, const std::string & Name)
+ {
+ // Eine C-Funktion muss auf dem Stack liegen.
+ if (!lua_iscfunction(L, -1)) return false;
+
+ // Sicherstellen, dass die Permanents-Tabelle oben auf dem Stack liegt.
+ lua_getfield(L, LUA_REGISTRYINDEX, PERMANENTS_TABLE_NAME);
+ if (lua_isnil(L, -1))
+ {
+ // Permanents-Tabelle existiert noch nicht, sie muss erstellt werden.
+
+ // Nil vom Stack poppen.
+ lua_pop(L, 1);
+
+ // Permanents-Tabelle erstellen und eine zweite Referenz darauf auf den Stack legen.
+ lua_newtable(L);
+ lua_pushvalue(L, -1);
+
+ // Permanents-Tabelle in der Registry speichern. Die zweite Referenz verbleibt auf dem Stack um im Anschluss benutzt zu werden.
+ lua_setfield(L, LUA_REGISTRYINDEX, PERMANENTS_TABLE_NAME);
+ }
+
+ // C-Funktion mit dem Namen als Index in der Permanents-Tabelle ablegen.
+ lua_insert(L, -2);
+ lua_setfield(L, -2, Name.c_str());
+
+ // Permanents-Tabelle vom Stack nehmen.
+ lua_pop(L, 1);
+
+ return true;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_LuaBindhelper::AddFunctionsToLib(lua_State * L, const std::string & LibName, const luaL_reg * Functions)
+{
+#ifdef DEBUG
+ int __startStackDepth = lua_gettop(L);
+#endif
+
+ // Wenn der Tabellenname leer ist, werden die Funktionen zum globalen Namensraum hinzugefügt.
+ if (LibName.size() == 0)
+ {
+ for (; Functions->name; ++Functions)
+ {
+ lua_pushstring(L, Functions->name);
+ lua_pushcclosure(L, Functions->func, 0);
+ lua_settable(L, LUA_GLOBALSINDEX);
+
+ // Funktion als permanent registrieren, damit sie beim Persistieren ignoriert wird.
+ lua_pushstring(L, Functions->name);
+ lua_gettable(L, LUA_GLOBALSINDEX);
+ RegisterPermanent(L, Functions->name);
+ }
+ }
+ // Wenn der Tabellenname nicht leer ist, werden die Funktionen zu dieser Tabelle hinzugefügt.
+ else
+ {
+ // Sicherstellen, dass die Library-Table existiert.
+ if (!_CreateTable(L, LibName)) return false;
+
+ // Die einzelnen Funktionen in der Table registrieren.
+ for (; Functions->name; ++Functions)
+ {
+ // Funktion registrieren.
+ lua_pushstring(L, Functions->name);
+ lua_pushcclosure(L, Functions->func, 0);
+ lua_settable(L, -3);
+
+ // Funktion als permanent registrieren, damit sie beim Persistieren ignoriert wird.
+ lua_pushstring(L, Functions->name);
+ lua_gettable(L, -2);
+ RegisterPermanent(L, LibName + "." + Functions->name);
+ }
+
+ // Library-Table vom Lua-Stack nehmen.
+ lua_pop(L, 1);
+ }
+
+
+#ifdef DEBUG
+ BS_ASSERT(__startStackDepth == lua_gettop(L));
+#endif
+
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_LuaBindhelper::AddConstantsToLib(lua_State * L, const std::string & LibName, const lua_constant_reg * Constants)
+{
+#ifdef DEBUG
+ int __startStackDepth = lua_gettop(L);
+#endif
+
+ // Wenn der Tabellenname leer ist, werden die Konstanten zum globalen Namensraum hinzugefügt.
+ if (LibName.size() == 0)
+ {
+ for (; Constants->Name; ++Constants)
+ {
+ lua_pushstring(L, Constants->Name);
+ lua_pushnumber(L, Constants->Value);
+ lua_settable(L, LUA_GLOBALSINDEX);
+ }
+ }
+ // Wenn der Tabellenname nicht leer ist, werden die Konstanten zu dieser Tabelle hinzugefügt.
+ else
+ {
+ // Sicherstellen, dass die Library-Table existiert.
+ if (!_CreateTable(L, LibName)) return false;
+
+ // Die einzelnen Konstanten in der Table registrieren
+ for (; Constants->Name; ++Constants)
+ {
+ lua_pushstring(L, Constants->Name);
+ lua_pushnumber(L, Constants->Value);
+ lua_settable(L, -3);
+ }
+
+ // Library-Tabelle vom Lua-Stack nehmen
+ lua_pop(L, 1);
+ }
+
+#ifdef DEBUG
+ BS_ASSERT(__startStackDepth == lua_gettop(L));
+#endif
+
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_LuaBindhelper::AddMethodsToClass(lua_State * L, const std::string & ClassName, const luaL_reg * Methods)
+{
+#ifdef DEBUG
+ int __startStackDepth = lua_gettop(L);
+#endif
+
+ // Metatable auf den Lua-Stack laden
+ if (!GetMetatable(L, ClassName)) return false;
+
+ // Die einzelnen Methoden in der Metatable registrieren
+ for (; Methods->name; ++Methods)
+ {
+ lua_pushstring(L, Methods->name);
+ lua_pushcclosure(L, Methods->func, 0);
+ lua_settable(L, -3);
+
+ // Funktion als permanent registrieren, damit sie beim Persistieren ignoriert wird.
+ lua_pushstring(L, Methods->name);
+ lua_gettable(L, -2);
+ RegisterPermanent(L, ClassName + "." + Methods->name);
+ }
+
+ // Metatable vom Lua-Stack nehmen
+ lua_pop(L, 1);
+
+#ifdef DEBUG
+ BS_ASSERT(__startStackDepth == lua_gettop(L));
+#endif
+
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_LuaBindhelper::SetClassGCHandler(lua_State * L, const std::string & ClassName, lua_CFunction GCHandler)
+{
+#ifdef DEBUG
+ int __startStackDepth = lua_gettop(L);
+#endif
+
+ // Metatable auf den Lua-Stack laden
+ if (!GetMetatable(L, ClassName)) return false;
+
+ // Den GC-Handler in die Metatable schreiben
+ lua_pushstring(L, "__gc");
+ lua_pushcclosure(L, GCHandler, 0);
+ lua_settable(L, -3);
+
+ // Funktion als permanent registrieren, damit sie beim Persistieren ignoriert wird.
+ lua_pushstring(L, "__gc");
+ lua_gettable(L, -2);
+ RegisterPermanent(L, ClassName + ".__gc");
+
+ // Metatable vom Lua-Stack nehmen
+ lua_pop(L, 1);
+
+#ifdef DEBUG
+ BS_ASSERT(__startStackDepth == lua_gettop(L));
+#endif
+
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+
+namespace
+{
+ void PushMetatableTable(lua_State * L)
+ {
+ // Tabelle mit den Metatabellen auf den Stack legen.
+ lua_getglobal(L, METATABLES_TABLE_NAME);
+
+ // Wenn die Tabelle noch nicht existiert, muss sie erstellt werden.
+ if (lua_isnil(L, -1))
+ {
+ // nil vom Stack poppen.
+ lua_pop(L, 1);
+
+ // Neue Tabelle erstellen, in die globale Table eintragen und eine Referenz auf dem Stack lassen.
+ lua_newtable(L);
+ lua_pushvalue(L, -1);
+ lua_setglobal(L, METATABLES_TABLE_NAME);
+ }
+ }
+}
+
+
+bool BS_LuaBindhelper::GetMetatable(lua_State * L, const std::string & TableName)
+{
+ // Tabelle mit den Metatabellen auf den Stack legen.
+ PushMetatableTable(L);
+
+ // Versuchen, die gewünschte Metatabelle auf den Stack zu legen. Wenn sie noch nicht existiert, muss sie erstellt werden.
+ lua_getfield(L, -1, TableName.c_str());
+ if (lua_isnil(L, -1))
+ {
+ // nil vom Stack poppen.
+ lua_pop(L, 1);
+
+ // Neue Tabelle erstellen.
+ lua_newtable(L);
+
+ // Das __index Feld der Metatabele zeigt auf die Metatabelle selbst.
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -2, "__index");
+
+ // Persistfeld auf true setzen. Dies sorgt dafür, dass Objekte mit dieser Metatabelle direkt gespeichert werden.
+ lua_pushbooleancpp(L, true);
+ lua_setfield(L, -2, "__persist");
+
+ // Metatabelle in die Tabelle für Metatabellen eintragen und eine Referenz auf dem Stack lassen.
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -3, TableName.c_str());
+ }
+
+ // Tabelle mit den Metatabellen vom Stack nehmen.
+ lua_remove(L, -2);
+
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_LuaBindhelper::_CreateTable(lua_State * L, const std::string & TableName)
+{
+ // Der Tabellenname wird an den Punkten auseinandergetrennt und jeweils die Untertabellen erstellt.
+ // Auf diese Weise können auch Tabellen mit Untertabellen erstellt werden (z.B. Foo.Bar).
+ std::string::size_type PartBegin = 0;
+ while (PartBegin <= TableName.size())
+ {
+ std::string::size_type PartEnd;
+ PartEnd = TableName.find(".", PartBegin);
+ if (PartEnd == std::string::npos) PartEnd = TableName.size();
+ std::string SubTableName = TableName.substr(PartBegin, PartEnd - PartBegin);
+
+ // Tabellen mit einen leeren String als Namen sind nicht zulässig.
+ if (SubTableName.size() == 0) return false;
+
+ // Überprüfen, ob die Tabelle mit dem Namen bereits existiert.
+ // Beim ersten Durchgang wird im globalen Namensbereich gesucht, bei späteren Durchgängen in der entsprechenden Elterntabelle auf dem Stack.
+ if (PartBegin == 0)
+ {
+ lua_pushstring(L, SubTableName.c_str());
+ lua_gettable(L, LUA_GLOBALSINDEX);
+ }
+ else
+ {
+ lua_pushstring(L, SubTableName.c_str());
+ lua_gettable(L, -2);
+ if (!lua_isnil(L, -1)) lua_remove(L, -2);
+ }
+
+ // Wenn nicht, Table erstellen
+ if (lua_isnil(L, -1))
+ {
+ // nil-Wert vom Stack holen
+ lua_pop(L, 1);
+
+ // Neue Tabelle erstellen
+ lua_newtable(L);
+ lua_pushstring(L, SubTableName.c_str());
+ lua_pushvalue(L, -2);
+ if (PartBegin == 0)
+ lua_settable(L, LUA_GLOBALSINDEX);
+ else
+ {
+ lua_settable(L, -4);
+ lua_remove(L, -2);
+ }
+ }
+
+ PartBegin = PartEnd + 1;
+ }
+
+ return true;
+}
+
+namespace
+{
+ std::string GetLuaValueInfo(lua_State * L, int StackIndex)
+ {
+ switch (lua_type(L, StackIndex))
+ {
+ case LUA_TNUMBER:
+ lua_pushstring(L, lua_tostring(L, StackIndex));
+ break;
+
+ case LUA_TSTRING:
+ lua_pushfstring(L, "\"%s\"", lua_tostring(L, StackIndex));
+ break;
+
+ case LUA_TBOOLEAN:
+ lua_pushstring(L, (lua_toboolean(L, StackIndex) ? "true" : "false"));
+ break;
+
+ case LUA_TNIL:
+ lua_pushliteral(L, "nil");
+ break;
+
+ default:
+ lua_pushfstring(L, "%s: %p", luaL_typename(L, StackIndex), lua_topointer(L, StackIndex));
+ break;
+ }
+
+ std::string Result(lua_tostring(L, -1));
+ lua_pop(L, 1);
+
+ return Result;
+ }
+}
+
+std::string BS_LuaBindhelper::StackDump(lua_State *L)
+{
+ std::ostringstream oss;
+
+ int i = lua_gettop(L);
+ oss << "------------------- Stack Dump -------------------\n";
+
+ while(i)
+ {
+ oss << i << ": " << GetLuaValueInfo(L, i) << "\n";
+ i--;
+ }
+
+ oss << "-------------- Stack Dump Finished ---------------\n";
+
+ return oss.str();
+}
+
+std::string BS_LuaBindhelper::TableDump(lua_State * L)
+{
+ std::ostringstream oss;
+
+ oss << "------------------- Table Dump -------------------\n";
+
+ lua_pushnil(L);
+ while (lua_next(L, -2) != 0)
+ {
+ // Der Wert des aktuellen Elementes liegt oben auf dem Stack, darunter der Index.
+ oss << GetLuaValueInfo(L, -2) << " : " << GetLuaValueInfo(L, -1) << "\n";
+
+ // Wert vom Stack poppen. Der Index liegt dann oben für den nächsten Aufruf von lua_next().
+ lua_pop(L, 1);
+ }
+
+ oss << "-------------- Table Dump Finished ---------------\n";
+
+ return oss.str();
+}