Files
glest-source/source/shared_lib/sources/lua/lua_script.cpp
2018-05-06 00:01:36 +02:00

1135 lines
37 KiB
C++

// ==============================================================
// This file is part of Glest Shared Library (www.glest.org)
//
// Copyright (C) 2001-2008 Martiño Figueroa
//
// You can redistribute this code 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
// ==============================================================
#include "lua_script.h"
#include <stdexcept>
#include "conversion.h"
#include "util.h"
#include "platform_util.h"
#include "leak_dumper.h"
using namespace std;
using namespace Shared::Util;
namespace Shared {
namespace Lua {
//
// This class wraps streflop for LuaScript. We need to toggle the data type
// for streflop to use when calling into LUA as streflop may corrupt some
// numeric values passed from Lua otherwise
//
class Lua_STREFLOP_Wrapper {
public:
Lua_STREFLOP_Wrapper() {
#ifdef USE_STREFLOP
streflop_init<streflop::Double>();
#endif
}
~Lua_STREFLOP_Wrapper() {
#ifdef USE_STREFLOP
streflop_init<streflop::Simple>();
#endif
}
};
// =====================================================
// class LuaScript
// =====================================================
bool LuaScript::disableSandbox = false;
bool LuaScript::debugModeEnabled = false;
LuaScript::LuaScript() {
Lua_STREFLOP_Wrapper streflopWrapper;
currentLuaFunction = "";
currentLuaFunctionIsValid = false;
sandboxWrapperFunctionName = "";
sandboxCode = "";
luaState = luaL_newstate();
luaL_openlibs(luaState);
if (luaState == NULL) {
throw megaglest_runtime_error("Can not allocate lua state");
}
argumentCount = -1;
if (disableSandbox == false) {
lua_getglobal(luaState, "os");
lua_pushnil(luaState);
lua_setfield(luaState, -2, "execute");
lua_pushnil(luaState);
lua_setfield(luaState, -2, "rename");
lua_pushnil(luaState);
lua_setfield(luaState, -2, "remove");
lua_pushnil(luaState);
lua_setfield(luaState, -2, "exit");
lua_getglobal(luaState, "io");
lua_pushnil(luaState);
lua_setfield(luaState, -2, "open");
lua_pushnil(luaState);
lua_setfield(luaState, -2, "close");
lua_pushnil(luaState);
lua_setfield(luaState, -2, "write");
lua_pushnil(luaState);
lua_setfield(luaState, -2, "read");
lua_pushnil(luaState);
lua_setfield(luaState, -2, "flush");
lua_pushnil(luaState);
lua_setglobal(luaState, "loadfile");
lua_pushnil(luaState);
lua_setglobal(luaState, "dofile");
lua_pushnil(luaState);
lua_setglobal(luaState, "getfenv");
lua_pushnil(luaState);
lua_setglobal(luaState, "getmetatable");
lua_pushnil(luaState);
lua_setglobal(luaState, "load");
lua_pushnil(luaState);
lua_setglobal(luaState, "loadfile");
lua_pushnil(luaState);
lua_setglobal(luaState, "loadstring");
lua_pushnil(luaState);
lua_setglobal(luaState, "rawequal");
lua_pushnil(luaState);
lua_setglobal(luaState, "rawget");
lua_pushnil(luaState);
lua_setglobal(luaState, "rawset");
lua_pushnil(luaState);
lua_setglobal(luaState, "setfenv");
lua_pushnil(luaState);
lua_setglobal(luaState, "setmetatable");
lua_pop(luaState, 1);
}
}
void LuaScript::DumpGlobals() {
LuaHandle *L = luaState;
// push the first key (nil = beginning of table)
#if LUA_VERSION_NUM <= 501
lua_pushnil(L);
#endif
// lua_next will:
// 1 - pop the key
// 2 - push the next key
// 3 - push the value at that key
// ... so the key will be at index -2 and the value at index -1
#if LUA_VERSION_NUM > 501
lua_pushglobaltable(L);
lua_pushnil(L);
while (lua_next(L, -2) != 0) {
#else
while (lua_next(L, LUA_GLOBALSINDEX) != 0) {
#endif
// get type of key and value
int key_type = lua_type(L, -2);
int value_type = lua_type(L, -1);
// support only string keys
// globals aren't likely to have a non-string key, but just to be certain ...
if (key_type != LUA_TSTRING) {
lua_pop(L, 1); // pop the value so that the top contains the key for the next iteration
continue;
}
// support only number, boolean and string values
if (value_type != LUA_TNUMBER &&
value_type != LUA_TBOOLEAN &&
value_type != LUA_TSTRING) {
lua_pop(L, 1); // again, pop the value before going to the next loop iteration
continue;
}
// get the key as a string
string key_string = lua_tostring(L, -2); // no copy required - we already know this is a string
// do not support variables that start with '_'
// lua has some predefined values like _VERSION. They all start with underscore
if (!key_string.size()) { // this again is highly unlikely, but still ...
lua_pop(L, 1);
continue;
}
if (key_string[0] == '_') {
lua_pop(L, 1);
continue;
}
string value_string;
// convert the value to a string. This depends on its type
switch (value_type) {
case LUA_TSTRING:
case LUA_TNUMBER:
// numbers can be converted to strings
// get the value as a string (this requires a copy because traversing tables
// uses the top of the stack as an index. If conversion from a number to string
// happens, the top of the stack will be altered and the table index will become invalid)
lua_pushvalue(L, -1);
value_string = lua_tostring(L, -1);
lua_pop(L, 1);
break;
case LUA_TBOOLEAN:
value_string = lua_toboolean(L, -1) == 0 ? "false" : "true";
break;
}
// enclose the value in "" if it is a string
if (value_type == LUA_TSTRING) {
value_string = "\"" + value_string + "\"";
}
// resulting line. Somehow save this and when you need to restore it, just
// call luaL_dostring with that line.
//SaveLine(key_string + " = " + value_string); // Pop the value so the index remains on top of the stack for the next iteration
printf("Found global LUA var: %s = %s\n", key_string.c_str(), value_string.c_str());
lua_pop(L, 1);
}
#if LUA_VERSION_NUM > 501
lua_pop(L, 1);
#endif
}
void LuaScript::saveGame(XmlNode *rootNode) {
std::map<string, string> mapTagReplacements;
//try{
LuaHandle *L = luaState;
// push the first key (nil = beginning of table)
#if LUA_VERSION_NUM <= 501
lua_pushnil(L);
#endif
// lua_next will:
// 1 - pop the key
// 2 - push the next key
// 3 - push the value at that key
// ... so the key will be at index -2 and the value at index -1
#if LUA_VERSION_NUM > 501
lua_pushglobaltable(L);
lua_pushnil(L);
while (lua_next(L, -2) != 0) {
#else
while (lua_next(L, LUA_GLOBALSINDEX) != 0) {
#endif
// get type of key and value
int key_type = lua_type(L, -2);
int value_type = lua_type(L, -1);
if (LuaScript::debugModeEnabled == true) printf("LUA save key_type = %d, value_type = %d for var [%s]\n", key_type, value_type, lua_tostring(L, -2));
// support only string keys
// globals aren't likely to have a non-string key, but just to be certain ...
if (key_type != LUA_TSTRING) {
lua_pop(L, 1); // pop the value so that the top contains the key for the next iteration
continue;
}
// support only number, boolean and string values
if (value_type != LUA_TNUMBER &&
value_type != LUA_TBOOLEAN &&
value_type != LUA_TSTRING &&
value_type != LUA_TTABLE) {
lua_pop(L, 1); // again, pop the value before going to the next loop iteration
continue;
}
// get the key as a string
string key_string = lua_tostring(L, -2); // no copy required - we already know this is a string
if (LuaScript::debugModeEnabled == true) printf("key_string [%s]\n", key_string.c_str());
// do not support variables that start with '_'
// lua has some predefined values like _VERSION. They all start with underscore
if (!key_string.size()) { // this again is highly unlikely, but still ...
lua_pop(L, 1);
continue;
}
if (key_string[0] == '_') {
lua_pop(L, 1);
continue;
}
bool skipTable = false;
// The first pair is the tables key type,value
// The second pair is the tables value type,value
vector<pair<pair<int, string>, pair<int, string> > > tableList;
string value_string;
// convert the value to a string. This depends on its type
switch (value_type) {
case LUA_TSTRING:
case LUA_TNUMBER:
// numbers can be converted to strings
// get the value as a string (this requires a copy because traversing tables
// uses the top of the stack as an index. If conversion from a number to string
// happens, the top of the stack will be altered and the table index will become invalid)
lua_pushvalue(L, -1);
value_string = lua_tostring(L, -1);
lua_pop(L, 1);
break;
case LUA_TBOOLEAN:
value_string = lua_toboolean(L, -1) == 0 ? "false" : "true";
break;
case LUA_TTABLE:
{
int tableItemCount = 0;
if (LuaScript::debugModeEnabled == true) printf("================ LUA TABLE DETECTED - START =================\n");
for (lua_pushnil(L); lua_next(L, -2);) {
tableItemCount++;
if (LuaScript::debugModeEnabled == true) printf("LUA TABLE loop A\n");
int tableKeyType = lua_type(L, -2);
int tableValueType = lua_type(L, -1);
if (LuaScript::debugModeEnabled == true) printf("LUA TABLE loop item type [%s] key: %d value type: %d\n", lua_typename(L, tableValueType), tableKeyType, tableValueType);
switch (tableValueType) {
case LUA_TSTRING:
case LUA_TNUMBER:
case LUA_TBOOLEAN:
break;
default:
skipTable = true;
break;
}
if (skipTable == false) {
// Stack: value, key, table
std::string value = "";
if (!lua_isnil(L, -1)) {
if (LuaScript::debugModeEnabled == true) printf("LUA TABLE loop B\n");
lua_pushvalue(L, -1);
if (LuaScript::debugModeEnabled == true) printf("LUA TABLE loop C\n");
if (tableValueType == LUA_TBOOLEAN) {
value = lua_toboolean(L, -1) == 0 ? "false" : "true";
} else {
value = lua_tostring(L, -1);
}
if (LuaScript::debugModeEnabled == true) printf("LUA TABLE loop D\n");
lua_pop(L, 1);
}
lua_pop(L, 1);
if (LuaScript::debugModeEnabled == true) printf("LUA TABLE value [%s]\n", value.c_str());
// Stack: key, table
lua_pushvalue(L, -1);
// Stack: key, key, table
std::string key = lua_tostring(L, -1);
lua_pop(L, 1);
// Stack: key, table
//std :: cout << key << "" << value << "\ n";
if (LuaScript::debugModeEnabled == true) printf("[%s] [%s]\n", key.c_str(), value.c_str());
if (value_string != "") {
value_string += "|||";
}
char szBuf[8096] = "";
snprintf(szBuf, 8096, "[%s] [%s]", key.c_str(), value.c_str());
//value_string += szBuf;
//vector<pair<pair<int,string>, pair<int,string>> > tableList;
tableList.push_back(make_pair(make_pair(tableKeyType, key), make_pair(tableValueType, value)));
} else {
if (LuaScript::debugModeEnabled == true) printf("***WARNING*** SKIPPING LUA TABLE because it has an unsupported embedded type: %d [%s]\n", tableValueType, lua_typename(L, tableValueType));
lua_pop(L, 1);
}
}
if (tableItemCount < 1) {
if (LuaScript::debugModeEnabled == true) printf("Skipping lua table tableItemCount = %d\n", tableItemCount);
skipTable = true;
}
if (LuaScript::debugModeEnabled == true) printf("---------------------------- LUA TABLE DETECTED - END ----------------------------\n");
}
break;
}
// enclose the value in "" if it is a string
//if (value_type == LUA_TSTRING) {
//value_string = "\"" + value_string + "\"";
//}
if (skipTable == true) {
if (LuaScript::debugModeEnabled == true) printf("#2 SKIPPING TABLE\n");
} else {
//vector<pair<pair<int,string>, pair<int,string>> > tableList;
if (tableList.empty() == false) {
XmlNode *luaScriptNode = rootNode->addChild("LuaScript");
luaScriptNode->addAttribute("variable", key_string, mapTagReplacements);
luaScriptNode->addAttribute("value_type", intToStr(value_type), mapTagReplacements);
for (unsigned int i = 0; i < tableList.size(); ++i) {
pair<pair<int, string>, pair<int, string> > &item = tableList[i];
XmlNode *luaScriptTableNode = luaScriptNode->addChild("Table");
luaScriptTableNode->addAttribute("key_type", intToStr(item.first.first), mapTagReplacements);
luaScriptTableNode->addAttribute("key", item.first.second, mapTagReplacements);
luaScriptTableNode->addAttribute("value", item.second.second, mapTagReplacements);
luaScriptTableNode->addAttribute("value_type", intToStr(item.second.first), mapTagReplacements);
}
} else {
// resulting line. Somehow save this and when you need to restore it, just
// call luaL_dostring with that line.
//SaveLine(key_string + " = " + value_string); // Pop the value so the index remains on top of the stack for the next iteration
//printf("Found global LUA var: %s = %s\n",key_string.c_str(),value_string.c_str());
XmlNode *luaScriptNode = rootNode->addChild("LuaScript");
luaScriptNode->addAttribute("variable", key_string, mapTagReplacements);
luaScriptNode->addAttribute("value", value_string, mapTagReplacements);
luaScriptNode->addAttribute("value_type", intToStr(value_type), mapTagReplacements);
}
}
lua_pop(L, 1);
}
#if LUA_VERSION_NUM > 501
lua_pop(L, 1);
#endif
//}
//catch(const exception &ex) {
// abort();
//}
}
void LuaScript::loadGame(const XmlNode *rootNode) {
if (LuaScript::debugModeEnabled) printf("START [%s::%s] Line: %d\n", extractFileFromDirectoryPath(__FILE__).c_str(), __FUNCTION__, __LINE__);
vector<XmlNode *> luaScriptNodeList = rootNode->getChildList("LuaScript");
if (LuaScript::debugModeEnabled) printf("luaScriptNodeList.size(): %d\n", (int) luaScriptNodeList.size());
for (unsigned int i = 0; i < luaScriptNodeList.size(); ++i) {
XmlNode *node = luaScriptNodeList[i];
string variable = node->getAttribute("variable")->getValue();
int value_type = node->getAttribute("value_type")->getIntValue();
if (LuaScript::debugModeEnabled) printf(" index #: %u [%s] [%d]\n", i, variable.c_str(), value_type);
switch (value_type) {
case LUA_TSTRING:
if (LuaScript::debugModeEnabled) printf(" value [%s]\n", node->getAttribute("value")->getValue().c_str());
lua_pushstring(luaState, node->getAttribute("value")->getValue().c_str());
break;
case LUA_TNUMBER:
if (LuaScript::debugModeEnabled) printf(" value [%s]\n", node->getAttribute("value")->getValue().c_str());
lua_pushnumber(luaState, node->getAttribute("value")->getFloatValue());
break;
case LUA_TBOOLEAN:
if (LuaScript::debugModeEnabled) printf(" value [%s]\n", node->getAttribute("value")->getValue().c_str());
lua_pushboolean(luaState, node->getAttribute("value")->getBoolValue());
break;
case LUA_TTABLE:
{
if (LuaScript::debugModeEnabled == true) printf("================ LUA TABLE DETECTED - START =================\n");
lua_newtable(luaState); /* We will pass a table */
vector<XmlNode *> luaScriptTableNode = node->getChildList("Table");
if (LuaScript::debugModeEnabled) printf("luaScriptTableNode.size(): %d\n", (int) luaScriptTableNode.size());
for (unsigned int j = 0; j < luaScriptTableNode.size(); ++j) {
XmlNode *nodeTable = luaScriptTableNode[j];
int key_type = nodeTable->getAttribute("key_type")->getIntValue();
if (LuaScript::debugModeEnabled == true) printf("Table item key_type: %d [%s]\n", key_type, lua_typename(luaState, key_type));
switch (key_type) {
case LUA_TSTRING:
if (LuaScript::debugModeEnabled) printf(" table item key [%s]\n", nodeTable->getAttribute("key")->getValue().c_str());
lua_pushstring(luaState, nodeTable->getAttribute("key")->getValue().c_str());
break;
case LUA_TNUMBER:
if (LuaScript::debugModeEnabled) printf(" table item key [%s]\n", nodeTable->getAttribute("key")->getValue().c_str());
lua_pushnumber(luaState, nodeTable->getAttribute("key")->getFloatValue());
break;
case LUA_TBOOLEAN:
if (LuaScript::debugModeEnabled) printf(" table item key [%s]\n", nodeTable->getAttribute("key")->getValue().c_str());
lua_pushboolean(luaState, nodeTable->getAttribute("key")->getBoolValue());
break;
}
int value_type = nodeTable->getAttribute("value_type")->getIntValue();
if (LuaScript::debugModeEnabled == true) printf("Table item value_type: %d [%s]\n", value_type, lua_typename(luaState, value_type));
switch (value_type) {
case LUA_TSTRING:
if (LuaScript::debugModeEnabled) printf(" table item value [%s]\n", nodeTable->getAttribute("value")->getValue().c_str());
lua_pushstring(luaState, nodeTable->getAttribute("value")->getValue().c_str());
break;
case LUA_TNUMBER:
if (LuaScript::debugModeEnabled) printf(" table item value [%s]\n", nodeTable->getAttribute("value")->getValue().c_str());
lua_pushnumber(luaState, nodeTable->getAttribute("value")->getFloatValue());
break;
case LUA_TBOOLEAN:
if (LuaScript::debugModeEnabled) printf(" table item value [%s]\n", nodeTable->getAttribute("value")->getValue().c_str());
lua_pushboolean(luaState, nodeTable->getAttribute("value")->getBoolValue());
break;
}
lua_rawset(luaState, -3); /* Stores the pair in the table */
}
if (LuaScript::debugModeEnabled == true) printf("----------------- LUA TABLE DETECTED - END -----------------\n");
}
break;
}
lua_setglobal(luaState, variable.c_str());
}
}
LuaScript::~LuaScript() {
Lua_STREFLOP_Wrapper streflopWrapper;
// LuaInterface.LuaTable luatab;
//
// luatab = lua.GetTable("_G");
//
//
// foreach (DictionaryEntry d in luatab)
//
// {
//
// Console.WriteLine("{0} -> {1}", d.Key, d.Value);
//
// }
//DumpGlobals();
lua_close(luaState);
}
void LuaScript::loadCode(string code, string name) {
Lua_STREFLOP_Wrapper streflopWrapper;
//printf("Code [%s]\nName [%s]\n",code.c_str(),name.c_str());
int errorCode = luaL_loadbuffer(luaState, code.c_str(), code.length(), name.c_str());
if (errorCode != 0) {
printf("=========================================================\n");
printf("Error loading lua code: %s\n", errorToString(errorCode).c_str());
printf("Function name [%s]\ncode:\n%s\n", name.c_str(), code.c_str());
printf("=========================================================\n");
throw megaglest_runtime_error("Error loading lua code: " + errorToString(errorCode), true);
}
if (SystemFlags::getSystemSettingType(SystemFlags::debugLUA).enabled) SystemFlags::OutputDebug(SystemFlags::debugLUA, "In [%s::%s Line: %d] name [%s], errorCode = %d\n", __FILE__, __FUNCTION__, __LINE__, name.c_str(), errorCode);
//run code
errorCode = lua_pcall(luaState, 0, 0, 0);
if (errorCode != 0) {
printf("=========================================================\n");
printf("Error calling lua pcall: %s\n", errorToString(errorCode).c_str());
printf("=========================================================\n");
throw megaglest_runtime_error("Error initializing lua: " + errorToString(errorCode), true);
}
//const char *errMsg = lua_tostring(luaState, -1);
//printf("END of call to Name [%s]\n",name.c_str());
if (SystemFlags::getSystemSettingType(SystemFlags::debugLUA).enabled) SystemFlags::OutputDebug(SystemFlags::debugLUA, "In [%s::%s Line: %d] name [%s], errorCode = %d\n", __FILE__, __FUNCTION__, __LINE__, name.c_str(), errorCode);
}
void LuaScript::setSandboxWrapperFunctionName(string name) {
sandboxWrapperFunctionName = name;
}
void LuaScript::setSandboxCode(string code) {
sandboxCode = code;
}
int LuaScript::runCode(string code) {
Lua_STREFLOP_Wrapper streflopWrapper;
int errorCode = luaL_dostring(luaState, code.c_str());
return errorCode;
}
void LuaScript::beginCall(string functionName) {
Lua_STREFLOP_Wrapper streflopWrapper;
currentLuaFunction = functionName;
if (SystemFlags::getSystemSettingType(SystemFlags::debugLUA).enabled) SystemFlags::OutputDebug(SystemFlags::debugLUA, "In [%s::%s Line: %d] functionName [%s]\n", __FILE__, __FUNCTION__, __LINE__, functionName.c_str());
if (SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) SystemFlags::OutputDebug(SystemFlags::debugPerformance, "In [%s::%s Line: %d] functionName [%s]\n", __FILE__, __FUNCTION__, __LINE__, functionName.c_str());
//string funcLuaFunction = functionName;
// if(sandboxWrapperFunctionName != "" && sandboxCode != "") {
// int errorCode= runCode(sandboxCode);
// if(errorCode !=0 ) {
// throw megaglest_runtime_error("Error calling lua function [" + currentLuaFunction + "] error: " + errorToString(errorCode));
// }
// //functionName = sandboxWrapperFunctionName;
// }
lua_getglobal(luaState, functionName.c_str());
currentLuaFunctionIsValid = lua_isfunction(luaState, lua_gettop(luaState));
//printf("currentLuaFunctionIsValid = %d functionName [%s]\n",currentLuaFunctionIsValid,functionName.c_str());
argumentCount = 0;
}
void LuaScript::endCall() {
Lua_STREFLOP_Wrapper streflopWrapper;
if (SystemFlags::getSystemSettingType(SystemFlags::debugLUA).enabled) SystemFlags::OutputDebug(SystemFlags::debugLUA, "In [%s::%s Line: %d] currentLuaFunction [%s], currentLuaFunctionIsValid = %d\n", __FILE__, __FUNCTION__, __LINE__, currentLuaFunction.c_str(), currentLuaFunctionIsValid);
if (currentLuaFunctionIsValid == true) {
if (sandboxWrapperFunctionName != "" && sandboxCode != "") {
//lua_pushstring(luaState, currentLuaFunction.c_str()); // push 1st argument, the real lua function
//argumentCount = 1;
string safeWrapper = sandboxWrapperFunctionName + " [[" + currentLuaFunction + "()]]";
printf("Trying to execute [%s]\n", safeWrapper.c_str());
int errorCode = runCode(safeWrapper);
if (errorCode != 0) {
throw megaglest_runtime_error("Error calling lua function [" + currentLuaFunction + "] error: " + errorToString(errorCode), true);
}
//printf("Trying to execute [%s]\n",currentLuaFunction.c_str());
//lua_getglobal(luaState, sandboxWrapperFunctionName.c_str());
//argumentCount = 1;
//lua_pushstring( luaState, currentLuaFunction.c_str() );
// int errorCode= lua_pcall(luaState, argumentCount, 0, 0);
// if(errorCode !=0 ) {
// throw megaglest_runtime_error("Error calling lua function [" + currentLuaFunction + "] error: " + errorToString(errorCode));
// }
} else {
int errorCode = lua_pcall(luaState, argumentCount, 0, 0);
if (errorCode != 0) {
throw megaglest_runtime_error("Error calling lua function [" + currentLuaFunction + "] error: " + errorToString(errorCode), true);
}
}
} else {
lua_pcall(luaState, argumentCount, 0, 0);
}
}
void LuaScript::registerFunction(LuaFunction luaFunction, string functionName) {
Lua_STREFLOP_Wrapper streflopWrapper;
if (SystemFlags::getSystemSettingType(SystemFlags::debugLUA).enabled) SystemFlags::OutputDebug(SystemFlags::debugLUA, "In [%s::%s Line: %d] functionName [%s]\n", __FILE__, __FUNCTION__, __LINE__, functionName.c_str());
lua_pushcfunction(luaState, luaFunction);
lua_setglobal(luaState, functionName.c_str());
}
string LuaScript::errorToString(int errorCode) {
Lua_STREFLOP_Wrapper streflopWrapper;
string error;
switch (errorCode) {
case LUA_ERRSYNTAX:
error += "Syntax error";
break;
case LUA_ERRRUN:
error += "Runtime error";
break;
case LUA_ERRMEM:
error += "Memory allocation error";
break;
case LUA_ERRERR:
error += "Error while running the error handler";
break;
default:
error += "Unknown LUA error" + intToStr(errorCode);
break;
}
error += string(": ") + luaL_checkstring(luaState, -1);
return error;
}
// =====================================================
// class LuaArguments
// =====================================================
LuaArguments::LuaArguments(lua_State *luaState) {
Lua_STREFLOP_Wrapper streflopWrapper;
this->luaState = luaState;
returnCount = 0;
}
int LuaArguments::getInt(int argumentIndex) const {
Lua_STREFLOP_Wrapper streflopWrapper;
if (!lua_isnumber(luaState, argumentIndex)) {
throwLuaError("Can not get int from Lua state");
}
int result = (int) luaL_checkinteger(luaState, argumentIndex);
return result;
}
float LuaArguments::getFloat(int argumentIndex) const {
Lua_STREFLOP_Wrapper streflopWrapper;
if (!lua_isnumber(luaState, argumentIndex)) {
throwLuaError("Can not get int from Lua state");
}
float result = static_cast<float>(luaL_checknumber(luaState, argumentIndex));
return result;
}
Vec2f LuaArguments::getVec2f(int argumentIndex) const {
Lua_STREFLOP_Wrapper streflopWrapper;
Vec2f v;
if (!lua_istable(luaState, argumentIndex)) {
throwLuaError("Can not get vec2f from Lua state, value on the stack is not a table");
}
#if LUA_VERSION_NUM > 501
if (lua_rawlen(luaState, argumentIndex) != 2) {
#else
if (luaL_getn(luaState, argumentIndex) != 2) {
#endif
throwLuaError("Can not get vec2f from Lua state, array size not 2");
}
//string stackString = getStackText();
//printf("Lua Stack:\n%s\n",stackString.c_str());
lua_rawgeti(luaState, argumentIndex, 1);
//printf("xa = %s argumentIndex = %d\n",lua_tostring(luaState, argumentIndex),argumentIndex);
//v.x= (int)luaL_checkinteger(luaState, argumentIndex);
v.x = static_cast<float>(lua_tonumber(luaState, argumentIndex));
lua_pop(luaState, 1);
//printf("X = %d\n",v.x);
lua_rawgeti(luaState, argumentIndex, 2);
//printf("ya = %s\n",lua_tostring(luaState, argumentIndex));
//v.y= (int)luaL_checkinteger(luaState, argumentIndex);
v.y = static_cast<float>(lua_tonumber(luaState, argumentIndex));
lua_pop(luaState, 1);
//printf("Y = %d\n",v.y);
return v;
}
Vec3f LuaArguments::getVec3f(int argumentIndex) const {
Lua_STREFLOP_Wrapper streflopWrapper;
Vec3f v;
if (!lua_istable(luaState, argumentIndex)) {
throwLuaError("Can not get vec3f from Lua state, value on the stack is not a table");
}
#if LUA_VERSION_NUM > 501
if (lua_rawlen(luaState, argumentIndex) != 3) {
#else
if (luaL_getn(luaState, argumentIndex) != 3) {
#endif
throwLuaError("Can not get vec3f from Lua state, array size not 3");
}
//string stackString = getStackText();
//printf("Lua Stack:\n%s\n",stackString.c_str());
lua_rawgeti(luaState, argumentIndex, 1);
//printf("xa = %s argumentIndex = %d\n",lua_tostring(luaState, argumentIndex),argumentIndex);
//v.x= (int)luaL_checkinteger(luaState, argumentIndex);
v.x = static_cast<float>(lua_tonumber(luaState, argumentIndex));
lua_pop(luaState, 1);
//printf("X = %d\n",v.x);
lua_rawgeti(luaState, argumentIndex, 2);
//printf("ya = %s\n",lua_tostring(luaState, argumentIndex));
//v.y= (int)luaL_checkinteger(luaState, argumentIndex);
v.y = static_cast<float>(lua_tonumber(luaState, argumentIndex));
lua_pop(luaState, 1);
//printf("Y = %d\n",v.y);
lua_rawgeti(luaState, argumentIndex, 3);
//printf("ya = %s\n",lua_tostring(luaState, argumentIndex));
//v.y= (int)luaL_checkinteger(luaState, argumentIndex);
v.z = static_cast<float>(lua_tonumber(luaState, argumentIndex));
lua_pop(luaState, 1);
return v;
}
Vec4f LuaArguments::getVec4f(int argumentIndex) const {
Lua_STREFLOP_Wrapper streflopWrapper;
Vec4f v;
if (!lua_istable(luaState, argumentIndex)) {
throwLuaError("Can not get vec4f from Lua state, value on the stack is not a table");
}
#if LUA_VERSION_NUM > 501
if (lua_rawlen(luaState, argumentIndex) != 4) {
#else
if (luaL_getn(luaState, argumentIndex) != 4) {
#endif
throwLuaError("Can not get vec4f from Lua state, array size not 4");
}
//string stackString = getStackText();
//printf("Lua Stack:\n%s\n",stackString.c_str());
lua_rawgeti(luaState, argumentIndex, 1);
//printf("xa = %s argumentIndex = %d\n",lua_tostring(luaState, argumentIndex),argumentIndex);
//v.x= (int)luaL_checkinteger(luaState, argumentIndex);
v.x = static_cast<float>(lua_tonumber(luaState, argumentIndex));
lua_pop(luaState, 1);
//printf("X = %d\n",v.x);
lua_rawgeti(luaState, argumentIndex, 2);
//printf("ya = %s\n",lua_tostring(luaState, argumentIndex));
//v.y= (int)luaL_checkinteger(luaState, argumentIndex);
v.y = static_cast<float>(lua_tonumber(luaState, argumentIndex));
lua_pop(luaState, 1);
//printf("Y = %d\n",v.y);
lua_rawgeti(luaState, argumentIndex, 3);
//printf("ya = %s\n",lua_tostring(luaState, argumentIndex));
//v.y= (int)luaL_checkinteger(luaState, argumentIndex);
v.z = static_cast<float>(lua_tonumber(luaState, argumentIndex));
lua_pop(luaState, 1);
lua_rawgeti(luaState, argumentIndex, 4);
//printf("ya = %s\n",lua_tostring(luaState, argumentIndex));
//v.y= (int)luaL_checkinteger(luaState, argumentIndex);
v.w = static_cast<float>(lua_tonumber(luaState, argumentIndex));
lua_pop(luaState, 1);
return v;
}
string LuaArguments::getString(int argumentIndex) const {
Lua_STREFLOP_Wrapper streflopWrapper;
if (!lua_isstring(luaState, argumentIndex)) {
throwLuaError("Can not get string from Lua state");
}
return luaL_checkstring(luaState, argumentIndex);
}
void * LuaArguments::getGenericData(int argumentIndex) const {
Lua_STREFLOP_Wrapper streflopWrapper;
if (lua_isstring(luaState, argumentIndex)) {
const char *result = luaL_checkstring(luaState, argumentIndex);
//printf("\nGENERIC param %d is a string, %s!\n",argumentIndex,result);
return (void *) result;
}
//else if(lua_isnumber(luaState, argumentIndex)) {
// double result = luaL_checknumber(luaState, argumentIndex);
// printf("\nGENERIC param %d is a double, %f!\n",argumentIndex,result);
// return (void *)result;
//}
else if (lua_isnumber(luaState, argumentIndex)) {
lua_Integer result = luaL_checkinteger(luaState, argumentIndex);
//printf("\nGENERIC param %d is an int, %d!\n",argumentIndex,(int)result);
return (void *) result;
} else {
//printf("\nGENERIC param %d is a NULL!\n",argumentIndex);
return NULL;
}
}
Vec2i LuaArguments::getVec2i(int argumentIndex) const {
Lua_STREFLOP_Wrapper streflopWrapper;
Vec2i v;
if (!lua_istable(luaState, argumentIndex)) {
throwLuaError("Can not get vec2i from Lua state, value on the stack is not a table");
}
#if LUA_VERSION_NUM > 501
if (lua_rawlen(luaState, argumentIndex) != 2) {
#else
if (luaL_getn(luaState, argumentIndex) != 2) {
#endif
throwLuaError("Can not get vec2i from Lua state, array size not 2");
}
//string stackString = getStackText();
//printf("Lua Stack:\n%s\n",stackString.c_str());
lua_rawgeti(luaState, argumentIndex, 1);
//printf("xa = %s argumentIndex = %d\n",lua_tostring(luaState, argumentIndex),argumentIndex);
//v.x= (int)luaL_checkinteger(luaState, argumentIndex);
v.x = (int) lua_tointeger(luaState, argumentIndex);
lua_pop(luaState, 1);
//printf("X = %d\n",v.x);
lua_rawgeti(luaState, argumentIndex, 2);
//printf("ya = %s\n",lua_tostring(luaState, argumentIndex));
//v.y= (int)luaL_checkinteger(luaState, argumentIndex);
v.y = (int) lua_tointeger(luaState, argumentIndex);
lua_pop(luaState, 1);
//printf("Y = %d\n",v.y);
return v;
}
Vec4i LuaArguments::getVec4i(int argumentIndex) const {
Lua_STREFLOP_Wrapper streflopWrapper;
Vec4i v;
if (!lua_istable(luaState, argumentIndex)) {
throwLuaError("Can not get vec4i from Lua state, value on the stack is not a table");
}
#if LUA_VERSION_NUM > 501
if (lua_rawlen(luaState, argumentIndex) != 4) {
#else
if (luaL_getn(luaState, argumentIndex) != 4) {
#endif
throwLuaError("Can not get vec4i from Lua state, array size not 4");
}
lua_rawgeti(luaState, argumentIndex, 1);
v.x = (int) luaL_checkinteger(luaState, argumentIndex);
lua_pop(luaState, 1);
lua_rawgeti(luaState, argumentIndex, 2);
v.y = (int) luaL_checkinteger(luaState, argumentIndex);
lua_pop(luaState, 1);
lua_rawgeti(luaState, argumentIndex, 3);
v.z = (int) luaL_checkinteger(luaState, argumentIndex);
lua_pop(luaState, 1);
lua_rawgeti(luaState, argumentIndex, 4);
v.w = (int) luaL_checkinteger(luaState, argumentIndex);
lua_pop(luaState, 1);
return v;
}
void LuaArguments::returnInt(int value) {
Lua_STREFLOP_Wrapper streflopWrapper;
++returnCount;
lua_pushinteger(luaState, value);
}
void LuaArguments::returnFloat(float value) {
Lua_STREFLOP_Wrapper streflopWrapper;
++returnCount;
lua_pushnumber(luaState, value);
}
void LuaArguments::returnString(const string &value) {
Lua_STREFLOP_Wrapper streflopWrapper;
++returnCount;
lua_pushstring(luaState, value.c_str());
}
void LuaArguments::returnVec2i(const Vec2i &value) {
//Lua_STREFLOP_Wrapper streflopWrapper;
++returnCount;
lua_newtable(luaState);
lua_pushnumber(luaState, value.x);
lua_rawseti(luaState, -2, 1);
lua_pushnumber(luaState, value.y);
lua_rawseti(luaState, -2, 2);
}
void LuaArguments::returnVec4i(const Vec4i &value) {
//Lua_STREFLOP_Wrapper streflopWrapper;
++returnCount;
lua_newtable(luaState);
lua_pushnumber(luaState, value.x);
lua_rawseti(luaState, -2, 1);
lua_pushnumber(luaState, value.y);
lua_rawseti(luaState, -2, 2);
lua_pushnumber(luaState, value.z);
lua_rawseti(luaState, -2, 3);
lua_pushnumber(luaState, value.w);
lua_rawseti(luaState, -2, 4);
}
void LuaArguments::returnVectorInt(const vector<int> &value) {
//Lua_STREFLOP_Wrapper streflopWrapper;
++returnCount;
lua_newtable(luaState);
for (unsigned int i = 0; i < value.size(); ++i) {
lua_pushnumber(luaState, value[i]);
lua_rawseti(luaState, -2, i + 1);
}
}
string LuaArguments::getStackText() const {
Lua_STREFLOP_Wrapper streflopWrapper;
string stackString;
int stackSize = lua_gettop(luaState);
//build stack string
for (int i = 1; i <= stackSize; ++i) {
stackString += "-" + intToStr(i) + ": ";
if (lua_isnumber(luaState, -i)) {
stackString += "Number: " + doubleToStr(luaL_checknumber(luaState, -i));
} else if (lua_isstring(luaState, -i)) {
stackString += "String: " + string(luaL_checkstring(luaState, -i));
} else if (lua_istable(luaState, -i)) {
//int tableLen = 0;
#if LUA_VERSION_NUM > 501
int tableLen = lua_rawlen(luaState, -i);
#else
int tableLen = luaL_getn(luaState, -i);
#endif
stackString += "Table (" + intToStr(tableLen) + ")\n";
// for(unsigned int j = 1; j < tableLen; ++j) {
// stackString+= "entry# " + intToStr(j) + ", value = " + lua_tostring(luaState, -i) + "\n";
// }
// int j = 1;
// lua_pushnil(luaState); // The initial key for the traversal.
//
// printf("start loop\n");
//
// while (lua_next(luaState, -2)!=0) {
// printf("in loop j = %d\n",j);
//
// const char* Param=lua_tostring(luaState, -1);
//
// printf("passed in loop j = %d Param [%s]\n",j,(Param != NULL ? Param : "<nil>"));
//
// if (Param!=NULL) {
// stackString+= "entry# " + intToStr(j) + ", value = " + Param + "\n";
// }
//
// // Remove the value, keep the key for the next iteration.
// lua_pop(luaState, 1);
// j++;
// }
// const int len = lua_objlen( luaState, -i );
// printf("Table Len = %d\n",len);
//
// for ( int j = 1; j <= len; ++j ) {
// printf("A Table\n");
//
// lua_pushinteger( luaState, j );
//
// printf("B Table\n");
//
// lua_gettable( luaState, -2 );
//
// printf("C Table\n");
//
// //v.push_back( lua_tointeger( L, -1 ) );
// const char *value = lua_tostring( luaState, -1 );
// printf("D Table value = %s\n",(value != NULL ? value : "<nil>"));
//
// //v.push_back( lua_tointeger( L, -1 ) );
// const char *value2 = lua_tostring( luaState, -2 );
// printf("E Table value2 = %s\n",(value2 != NULL ? value2 : "<nil>"));
//
// value2 = lua_tostring( luaState, -3 );
// printf("F Table value2 = %s\n",(value2 != NULL ? value2 : "<nil>"));
//
// value2 = lua_tostring( luaState, 0 );
// printf("G Table value2 = %s\n",(value2 != NULL ? value2 : "<nil>"));
//
// value2 = lua_tostring( luaState, 1 );
// printf("H Table value2 = %s\n",(value2 != NULL ? value2 : "<nil>"));
//
// stackString+= "entry# " + intToStr(j) + ", value = " + (value != NULL ? value : "<nil>") + "\n";
//
// printf("E Table\n");
//
// lua_pop( luaState, 1 );
// }
} else {
stackString += "Unknown";
}
stackString += "\n";
}
return stackString;
}
void LuaArguments::throwLuaError(const string &message) const {
Lua_STREFLOP_Wrapper streflopWrapper;
string stackString = getStackText();
throw megaglest_runtime_error("Lua error: " + message + "\n\nLua Stack:\n" + stackString, true);
}
}
}//end namespace