Pull console output support and REPL out of dfusion into core lib.

develop
Alexander Gavrilov 2012-03-31 15:40:54 +04:00
parent 9384f0c842
commit 0f41608ed4
14 changed files with 501 additions and 225 deletions

@ -82,6 +82,8 @@ SET(DFHACK_DATA_DESTINATION hack)
SET(DFHACK_PLUGIN_DESTINATION hack/plugins)
# dfhack header files go here:
SET(DFHACK_INCLUDES_DESTINATION hack/include)
# dfhack lua files go here:
SET(DFHACK_LUA_DESTINATION hack/lua)
# the windows .lib file goes here:
SET(DFHACK_DEVLIB_DESTINATION hack)

@ -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 /* } */

@ -29,6 +29,7 @@ include/ColorText.h
include/DataDefs.h
include/DataIdentity.h
include/LuaWrapper.h
include/LuaTools.h
include/Error.h
include/Export.h
include/Hooks.h
@ -58,6 +59,7 @@ ColorText.cpp
DataDefs.cpp
LuaWrapper.cpp
LuaTypes.cpp
LuaTools.cpp
DataStatics.cpp
DataStaticsCtor.cpp
DataStaticsFields.cpp
@ -295,6 +297,10 @@ install(TARGETS dfhack-run dfhack-client
LIBRARY DESTINATION ${DFHACK_LIBRARY_DESTINATION}
RUNTIME DESTINATION ${DFHACK_LIBRARY_DESTINATION})
install(DIRECTORY lua/
DESTINATION ${DFHACK_LUA_DESTINATION}
FILES_MATCHING PATTERN "*.lua")
# Unused for so long that it's not even relevant now...
if(BUILD_DEVEL)
if(WIN32)

@ -757,6 +757,16 @@ std::string Core::getHotkeyCmd( void )
return returner;
}
void Core::print(const char *format, ...)
{
color_ostream_proxy proxy(getInstance().con);
va_list args;
va_start(args,format);
proxy.vprint(format,args);
va_end(args);
}
void Core::printerr(const char *format, ...)
{
color_ostream_proxy proxy(getInstance().con);

@ -0,0 +1,364 @@
/*
https://github.com/peterix/dfhack
Copyright (c) 2009-2011 Petr Mrázek (peterix@gmail.com)
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#include "Internal.h"
#include <string>
#include <vector>
#include <map>
#include "MemAccess.h"
#include "Core.h"
#include "VersionInfo.h"
#include "tinythread.h"
// must be last due to MS stupidity
#include "DataDefs.h"
#include "DataIdentity.h"
#include "LuaWrapper.h"
#include "LuaTools.h"
#include "MiscUtils.h"
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
using namespace DFHack;
using namespace DFHack::LuaWrapper;
void DFHack::Lua::PushDFObject(lua_State *state, type_identity *type, void *ptr)
{
push_object_internal(state, type, ptr, false);
}
void *DFHack::Lua::GetDFObject(lua_State *state, type_identity *type, int val_index, bool exact_type)
{
return get_object_internal(state, type, val_index, exact_type, false);
}
static int DFHACK_OSTREAM_TOKEN = 0;
color_ostream *DFHack::Lua::GetOutput(lua_State *L)
{
lua_rawgetp(L, LUA_REGISTRYINDEX, &DFHACK_OSTREAM_TOKEN);
auto rv = (color_ostream*)lua_touserdata(L, -1);
lua_pop(L, 1);
return rv;
}
static void set_dfhack_output(lua_State *L, color_ostream *p)
{
lua_pushlightuserdata(L, p);
lua_rawsetp(L, LUA_REGISTRYINDEX, &DFHACK_OSTREAM_TOKEN);
}
static std::string lua_print_fmt(lua_State *L)
{
/* Copied from lua source to fully replicate builtin print */
int n = lua_gettop(L); /* number of arguments */
lua_getglobal(L, "tostring");
std::stringstream ss;
for (int i=1; i<=n; i++) {
lua_pushvalue(L, -1); /* function to be called */
lua_pushvalue(L, i); /* value to print */
lua_call(L, 1, 1);
const char *s = lua_tostring(L, -1); /* get result */
if (s == NULL)
luaL_error(L, "tostring must return a string to print");
if (i>1)
ss << '\t';
ss << s;
lua_pop(L, 1); /* pop result */
}
return ss.str();
}
static int lua_dfhack_print(lua_State *S)
{
std::string str = lua_print_fmt(S);
if (color_ostream *out = Lua::GetOutput(S))
*out << str;
else
Core::print("%s", str.c_str());
return 0;
}
static int lua_dfhack_println(lua_State *S)
{
std::string str = lua_print_fmt(S);
if (color_ostream *out = Lua::GetOutput(S))
*out << str << std::endl;
else
Core::print("%s\n", str.c_str());
return 0;
}
static int lua_dfhack_printerr(lua_State *S)
{
std::string str = lua_print_fmt(S);
if (color_ostream *out = Lua::GetOutput(S))
out->printerr("%s\n", str.c_str());
else
Core::printerr("%s\n", str.c_str());
return 0;
}
static int traceback (lua_State *L) {
const char *msg = lua_tostring(L, 1);
if (msg)
luaL_traceback(L, L, msg, 1);
else if (!lua_isnoneornil(L, 1)) { /* is there an error object? */
if (!luaL_callmeta(L, 1, "__tostring")) /* try its 'tostring' metamethod */
lua_pushliteral(L, "(no error message)");
}
return 1;
}
static void report_error(color_ostream &out, lua_State *L)
{
const char *msg = lua_tostring(L, -1);
if (msg)
out.printerr("%s\n", msg);
else
out.printerr("In Lua::SafeCall: error message is not a string.\n", msg);
lua_pop(L, 1);
}
bool DFHack::Lua::SafeCall(color_ostream &out, lua_State *L, int nargs, int nres, bool perr)
{
int base = lua_gettop(L) - nargs;
color_ostream *cur_out = Lua::GetOutput(L);
set_dfhack_output(L, &out);
lua_pushcfunction(L, traceback);
lua_insert(L, base);
bool ok = lua_pcall(L, nargs, nres, base) == LUA_OK;
lua_remove(L, base);
set_dfhack_output(L, cur_out);
if (!ok && perr)
report_error(out, L);
return ok;
}
bool DFHack::Lua::Require(color_ostream &out, lua_State *state,
const std::string &module, bool setglobal)
{
lua_getglobal(state, "require");
lua_pushstring(state, module.c_str());
if (!Lua::SafeCall(out, state, 1, 1))
return false;
if (setglobal)
lua_setglobal(state, module.c_str());
else
lua_pop(state, 1);
return true;
}
static bool load_with_env(color_ostream &out, lua_State *state, const std::string &code, int eidx)
{
if (luaL_loadstring(state, code.c_str()) != LUA_OK)
{
report_error(out, state);
return false;
}
// Replace _ENV
lua_pushvalue(state, eidx);
if (!lua_setupvalue(state, -2, 1))
{
out.printerr("No _ENV upvalue.\n");
return false;
}
return true;
}
bool DFHack::Lua::InterpreterLoop(color_ostream &out, lua_State *state,
const char *prompt, int env, const char *hfile)
{
if (!out.is_console())
return false;
if (!lua_checkstack(state, 20))
return false;
if (!hfile)
hfile = "lua.history";
if (!prompt)
prompt = "lua";
DFHack::CommandHistory hist;
hist.load(hfile);
out.print("Type quit to exit interactive lua interpreter.\n"
"Shortcuts:\n"
" '= foo' => '_1,_2,... = foo'\n"
" '! foo' => 'print(foo)'\n"
"Both assign the first result to '_'\n");
Console &con = static_cast<Console&>(out);
// Make a proxy global environment.
lua_newtable(state);
lua_newtable(state);
if (env)
lua_pushvalue(state, env);
else
lua_rawgeti(state, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS);
lua_setfield(state, -2, "__index");
lua_setmetatable(state, -2);
// Main interactive loop
int base = lua_gettop(state);
int vcnt = 1;
string curline;
string prompt_str = "[" + string(prompt) + "]# ";
for (;;) {
lua_settop(state, base);
con.lineedit(prompt_str,curline,hist);
if (curline.empty())
continue;
if (curline == "quit")
break;
hist.add(curline);
char pfix = curline[0];
if (pfix == '=' || pfix == '!')
{
curline = "return " + curline.substr(1);
if (!load_with_env(out, state, curline, base))
continue;
if (!SafeCall(out, state, 0, LUA_MULTRET))
continue;
int numret = lua_gettop(state) - base;
if (numret >= 1)
{
lua_pushvalue(state, base+1);
lua_setfield(state, base, "_");
if (pfix == '!')
{
lua_pushcfunction(state, lua_dfhack_println);
lua_insert(state, base+1);
SafeCall(out, state, numret, 0);
continue;
}
}
for (int i = 1; i <= numret; i++)
{
std::string name = stl_sprintf("_%d", vcnt++);
lua_pushvalue(state, base + i);
lua_setfield(state, base, name.c_str());
out.print("%s = ", name.c_str());
lua_pushcfunction(state, lua_dfhack_println);
lua_pushvalue(state, base + i);
SafeCall(out, state, 1, 0);
}
}
else
{
if (!load_with_env(out, state, curline, base))
continue;
if (!SafeCall(out, state, 0, LUA_MULTRET))
continue;
}
}
lua_settop(state, base-1);
hist.save(hfile);
return true;
}
static int lua_dfhack_interpreter(lua_State *state)
{
color_ostream *pstream = Lua::GetOutput(state);
if (!pstream)
luaL_error(state, "Cannot use dfhack.interpreter() without output.");
int argc = lua_gettop(state);
const char *prompt = (argc >= 1 ? lua_tostring(state, 1) : NULL);
int env = (argc >= 2 && !lua_isnil(state,2) ? 2 : 0);
const char *hfile = (argc >= 3 ? lua_tostring(state, 3) : NULL);
lua_pushboolean(state, Lua::InterpreterLoop(*pstream, state, prompt, env, hfile));
return 1;
}
static const luaL_Reg dfhack_funcs[] = {
{ "print", lua_dfhack_print },
{ "println", lua_dfhack_println },
{ "printerr", lua_dfhack_printerr },
{ "traceback", traceback },
{ "interpreter", lua_dfhack_interpreter },
{ NULL, NULL }
};
lua_State *DFHack::Lua::Open(color_ostream &out, lua_State *state)
{
if (!state)
state = luaL_newstate();
luaL_openlibs(state);
AttachDFGlobals(state);
// Replace the print function of the standard library
lua_pushcfunction(state, lua_dfhack_println);
lua_setglobal(state, "print");
// Create and initialize the dfhack global
lua_newtable(state);
luaL_setfuncs(state, dfhack_funcs, 0);
lua_setglobal(state, "dfhack");
// load dfhack.lua
Require(out, state, "dfhack");
return state;
}

@ -59,16 +59,6 @@ void LuaWrapper::field_error(lua_State *state, int index, const char *err, const
mode, (cname ? cname : "?"), (fname ? fname : "?"), err);
}
void DFHack::PushDFObject(lua_State *state, type_identity *type, void *ptr)
{
push_object_internal(state, type, ptr, false);
}
void *DFHack::GetDFObject(lua_State *state, type_identity *type, int val_index, bool exact_type)
{
return get_object_internal(state, type, val_index, exact_type, false);
}
/* */
static int change_error(lua_State *state)
@ -1320,7 +1310,7 @@ static int DoAttach(lua_State *state)
* Initialize access to DF objects from the interpreter
* context, unless it has already been done.
*/
void DFHack::AttachDFGlobals(lua_State *state)
void LuaWrapper::AttachDFGlobals(lua_State *state)
{
if (luaL_newmetatable(state, DFHACK_TYPETABLE_NAME))
{

@ -135,6 +135,7 @@ namespace DFHack
DFHack::VersionInfo * vinfo;
DFHack::Windows::df_window * screen_window;
static void print(const char *format, ...);
static void printerr(const char *format, ...);
private:

@ -360,23 +360,6 @@ namespace DFHack
void InitDataDefGlobals(Core *core);
// LUA wrapper
/**
* Make DF objects available to the given interpreter.
*/
DFHACK_EXPORT void AttachDFGlobals(lua_State *state);
/**
* Push the pointer onto the stack as a wrapped DF object of the given type.
*/
DFHACK_EXPORT void PushDFObject(lua_State *state, type_identity *type, void *ptr);
/**
* Check that the value is a wrapped DF object of the given type, and if so return the pointer.
*/
DFHACK_EXPORT void *GetDFObject(lua_State *state, type_identity *type, int val_index, bool exact_type = false);
template<class T>
T *ifnull(T *a, T *b) { return a ? a : b; }
@ -683,24 +666,6 @@ namespace DFHack {
flagarray_to_string<T>(&tmp, val);
return join_strings(sep, tmp);
}
// LUA wrapper
/**
* Push the pointer onto the stack as a wrapped DF object of a specific type.
*/
template<class T>
void PushDFObject(lua_State *state, T *ptr) {
PushDFObject(state, df::identity_traits<T>::get(), ptr);
}
/**
* Check that the value is a wrapped DF object of the correct type, and if so return the pointer.
*/
template<class T>
T *GetDFObject(lua_State *state, int val_index, bool exact_type = false) {
return (T*)GetDFObject(state, df::identity_traits<T>::get(), val_index, exact_type);
}
}
#define ENUM_ATTR(enum,attr,val) (df::enum_traits<df::enum>::attrs(val).attr)

@ -0,0 +1,92 @@
/*
https://github.com/peterix/dfhack
Copyright (c) 2009-2011 Petr Mrázek (peterix@gmail.com)
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#pragma once
#include <string>
#include <sstream>
#include <vector>
#include <map>
#include "DataDefs.h"
#include <lua.h>
#include <lauxlib.h>
namespace DFHack { namespace Lua {
/**
* Create or initialize a lua interpreter with access to DFHack tools.
*/
DFHACK_EXPORT lua_State *Open(color_ostream &out, lua_State *state = NULL);
/**
* Load a module using require().
*/
DFHACK_EXPORT bool Require(color_ostream &out, lua_State *state,
const std::string &module, bool setglobal = false);
/**
* Push the pointer onto the stack as a wrapped DF object of the given type.
*/
DFHACK_EXPORT void PushDFObject(lua_State *state, type_identity *type, void *ptr);
/**
* Check that the value is a wrapped DF object of the given type, and if so return the pointer.
*/
DFHACK_EXPORT void *GetDFObject(lua_State *state, type_identity *type, int val_index, bool exact_type = false);
/**
* Push the pointer onto the stack as a wrapped DF object of a specific type.
*/
template<class T>
void PushDFObject(lua_State *state, T *ptr) {
PushDFObject(state, df::identity_traits<T>::get(), ptr);
}
/**
* Check that the value is a wrapped DF object of the correct type, and if so return the pointer.
*/
template<class T>
T *GetDFObject(lua_State *state, int val_index, bool exact_type = false) {
return (T*)GetDFObject(state, df::identity_traits<T>::get(), val_index, exact_type);
}
/**
* Invoke lua function via pcall. Returns true if success.
* If an error is signalled, and perr is true, it is printed and popped from the stack.
*/
DFHACK_EXPORT bool SafeCall(color_ostream &out, lua_State *state, int nargs, int nres, bool perr = true);
/**
* Returns the ostream passed to SafeCall.
*/
DFHACK_EXPORT color_ostream *GetOutput(lua_State *state);
/**
* Run an interactive interpreter loop if possible, or return false.
*/
DFHACK_EXPORT bool InterpreterLoop(color_ostream &out, lua_State *state,
const char *prompt = NULL, int env = 0, const char *hfile = NULL);
}}

@ -214,5 +214,7 @@ namespace DFHack { namespace LuaWrapper {
void AttachEnumKeys(lua_State *state, int meta_idx, int ftable_idx, type_identity *ienum);
void IndexStatics(lua_State *state, int meta_idx, int ftable_idx, struct_identity *pstruct);
void AttachDFGlobals(lua_State *state);
}}

@ -0,0 +1,5 @@
-- Common startup file for all dfhack plugins with lua support
-- The global dfhack table is already created by C++ init
-- code. Feed it back to the require() mechanism.
return dfhack

@ -21,6 +21,7 @@
#include "lua_FunctionCall.h"
#include "lua_Offsets.h"
#include "DataDefs.h"
#include "LuaTools.h"
using std::vector;
using std::string;
@ -42,11 +43,12 @@ DFhackCExport const char * plugin_name ( void )
return "dfusion";
}
DFhackCExport command_result plugin_init ( Core * c, std::vector <PluginCommand> &commands)
DFhackCExport command_result plugin_init (color_ostream &out, std::vector <PluginCommand> &commands)
{
lua::state st=lua::glua::Get();
//maybe remake it to run automaticaly
DFHack::AttachDFGlobals(st);
Lua::Open(out, st);
lua::RegisterConsole(st);
lua::RegisterProcess(st);
@ -64,11 +66,6 @@ DFhackCExport command_result plugin_init ( Core * c, std::vector <PluginCommand>
st.setglobal("WINDOWS");
#endif
st.getglobal("Console");
st.getfield("println");
st.setglobal("print");
st.pop();
commands.push_back(PluginCommand("dfusion","Run dfusion system (interactive i.e. can input further commands).",dfusion,true));
commands.push_back(PluginCommand("dfuse","Init dfusion system (not interactive).",dfuse,false));
commands.push_back(PluginCommand("lua", "Run interactive interpreter. Use 'lua <filename>' to run <filename> instead.",lua_run,true));
@ -113,87 +110,6 @@ DFhackCExport command_result plugin_onupdate_DISABLED ( Core * c )
mymutex->unlock();
return CR_OK;
}
void InterpreterLoop(color_ostream &out)
{
DFHack::CommandHistory hist;
lua::state s=lua::glua::Get();
string curline;
out.print("Type quit to exit interactive lua interpreter.\n"
"Shortcuts:\n"
" '= foo' => '_1,_2,... = foo'\n"
" '! foo' => 'print(foo)'\n"
"Both assign the first result to '_'\n");
assert(out.is_console());
Console &con = static_cast<Console&>(out);
int vcnt = 1;
s.settop(0);
for (;;) {
con.lineedit("[lua]# ",curline,hist);
if (curline.empty())
continue;
if (curline == "quit")
break;
hist.add(curline);
try
{
char pfix = curline[0];
if (pfix == '=' || pfix == '!')
{
curline = "return " + curline.substr(1);
s.loadstring(curline);
s.pcall(0, LUA_MULTRET);
int numret = s.gettop();
if (numret >= 1)
{
s.pushvalue(1);
s.setglobal("_");
if (pfix == '!')
{
s.getglobal("print");
s.insert(1);
s.pcall(numret,0);
numret = 0;
}
}
for (int i = 1; i <= numret; i++)
{
std::string name = stl_sprintf("_%d", vcnt++);
s.pushvalue(i);
s.setglobal(name);
con.print("%s = ", name.c_str());
s.getglobal("print");
s.pushvalue(i);
s.pcall(1,0);
}
}
else
{
s.loadstring(curline);
s.pcall();
}
}
catch(lua::exception &e)
{
con.printerr("Error:%s\n",e.what());
con.printerr("%s\n",lua::DebugDump(lua::glua::Get()).c_str());
}
s.settop(0);
}
}
command_result lua_run_file (color_ostream &out, std::vector <std::string> &parameters)
{
if(parameters.size()==0)
@ -207,14 +123,14 @@ command_result lua_run (color_ostream &out, std::vector <std::string> &parameter
{
mymutex->lock();
lua::state s=lua::glua::Get();
lua::SetConsole(s,out);
if(parameters.size()>0)
{
try{
s.loadfile(parameters[0]); //load file
for(size_t i=1;i<parameters.size();i++)
s.push(parameters[i]);
s.pcall(parameters.size()-1,0);// run it
Lua::SafeCall(out, s, parameters.size()-1,0);// run it
}
catch(lua::exception &e)
{
@ -224,7 +140,7 @@ command_result lua_run (color_ostream &out, std::vector <std::string> &parameter
}
else
{
InterpreterLoop(out);
Lua::InterpreterLoop(out, s);
}
s.settop(0);// clean up
mymutex->unlock();
@ -235,12 +151,10 @@ void RunDfusion(color_ostream &out, std::vector <std::string> &parameters)
mymutex->lock();
lua::state s=lua::glua::Get();
try{
s.getglobal("err");
int errpos=s.gettop();
s.loadfile("dfusion/init.lua"); //load script
for(size_t i=0;i<parameters.size();i++)
s.push(parameters[i]);
s.pcall(parameters.size(),0,errpos);// run it
Lua::SafeCall(out, s, parameters.size(),0);
}
catch(lua::exception &e)
{
@ -253,7 +167,6 @@ void RunDfusion(color_ostream &out, std::vector <std::string> &parameters)
command_result dfuse(color_ostream &out, std::vector <std::string> &parameters)
{
lua::state s=lua::glua::Get();
lua::SetConsole(s,out);
s.push(1);
s.setglobal("INIT");
RunDfusion(out,parameters);
@ -262,7 +175,6 @@ command_result dfuse(color_ostream &out, std::vector <std::string> &parameters)
command_result dfusion (color_ostream &out, std::vector <std::string> &parameters)
{
lua::state s=lua::glua::Get();
lua::SetConsole(s,out);
s.push();
s.setglobal("INIT");
RunDfusion(out,parameters);

@ -7,7 +7,7 @@ namespace lua
{
void RegisterConsole(lua::state &st);
void SetConsole(lua::state &st,DFHack::color_ostream& stream);
}
#endif

@ -1,64 +1,12 @@
#include "lua_Console.h"
#include "LuaTools.h"
#include <sstream>
//TODO error management. Using lua error? or something other?
static DFHack::color_ostream* GetConsolePtr(lua::state &st)
{
int t=st.gettop();
st.getglobal("Console");
st.getfield("__pointer");
DFHack::color_ostream* c=static_cast<DFHack::color_ostream*>(lua_touserdata(st,-1));
st.settop(t);
return c;
}
static std::string lua_print_fmt(lua_State *L)
{
/* Copied from lua source to fully replicate builtin print */
int n = lua_gettop(L); /* number of arguments */
lua_getglobal(L, "tostring");
std::stringstream ss;
for (int i=1; i<=n; i++) {
lua_pushvalue(L, -1); /* function to be called */
lua_pushvalue(L, i); /* value to print */
lua_call(L, 1, 1);
const char *s = lua_tostring(L, -1); /* get result */
if (s == NULL)
luaL_error(L, "tostring must return a string to print");
if (i>1)
ss << '\t';
ss << s;
lua_pop(L, 1); /* pop result */
}
return ss.str();
}
static int lua_Console_print(lua_State *S)
{
lua::state st(S);
DFHack::color_ostream* c=GetConsolePtr(st);
c->print("%s", lua_print_fmt(S).c_str());
return 0;
}
static int lua_Console_println(lua_State *S)
{
lua::state st(S);
DFHack::color_ostream* c=GetConsolePtr(st);
c->print("%s\n", lua_print_fmt(S).c_str());
return 0;
}
static int lua_Console_printerr(lua_State *S)
{
lua::state st(S);
DFHack::color_ostream* c=GetConsolePtr(st);
c->printerr("%s", lua_print_fmt(S).c_str());
return 0;
return DFHack::Lua::GetOutput(st);
}
static int lua_Console_clear(lua_State *S)
@ -156,9 +104,6 @@ static int lua_Console_lineedit(lua_State *S)
}
const luaL_Reg lua_console_func[]=
{
{"print",lua_Console_print},
{"println",lua_Console_println},
{"printerr",lua_Console_printerr},
{"clear",lua_Console_clear},
{"gotoxy",lua_Console_gotoxy},
{"color",lua_Console_color},
@ -183,17 +128,3 @@ void lua::RegisterConsole(lua::state &st)
//TODO add color consts
st.setglobal("Console");
}
void lua::SetConsole(lua::state &st,DFHack::color_ostream& stream)
{
int top=st.gettop();
st.getglobal("Console");
if(st.is<lua::nil>())
{
st.pop();
st.newtable();
}
st.pushlightuserdata(&stream);
st.setfield("__pointer");
st.settop(top);
}