Lua 5.2 redirecting the print function
From Lua 5.2 manual:
Lua keeps a distinguished environment called the global environment.
This value is kept at a special index in the C registry (see §4.5).
In Lua, the variable _G is initialized with this same value.
So this answer to the question you linked will work if you replace the calls to luaL_register
to calls to luaL_setfuncs
.
How to print Lua table using the redefined print function?
Just use luaL_tolstring
to get the string representation of anything. This also respects the __tostring
metamethod. The example below uses std::string_view
from C++17 for zero-copy read-only string arguments.
#include <iostream>
#include <string_view>
#include <lua.hpp>
void poststring(std::string_view sv) { std::cout << sv << '\n'; }
void endpost() { std::cout << "---\n"; }
int l_my_print(lua_State *L) {
int nargs = lua_gettop(L);
for (int i = 1; i <= nargs; ++i) {
poststring(luaL_tolstring(L, i, nullptr));
lua_pop(L, 1); // remove the string
}
endpost();
return 0;
}
int main() {
lua_State *L = luaL_newstate();
luaL_openlibs(L);
lua_pushcfunction(L, l_my_print);
lua_setglobal(L, "my_print");
int i = 0;
lua_pushlightuserdata(L, &i);
lua_setglobal(L, "udata");
luaL_dostring(L, "my_print(1, 3.14, \"Hello World\")\n"
"my_print(false, udata, {})\n");
lua_close(L);
}
Example invocation:
$ clang++ -Wall -Wextra -Wpedantic -std=c++17 -I/usr/include/lua5.3 test.cpp -llua5.3
$ ./a.out
1
3.14
Hello World
---
false
userdata: 0x7fff4685993c
table: 0x883300
---
send lua output to non stdout
This answer can get critics from some readers, but first please have a look at my blog post which I've prepared specially for this answer, and read the foreword why I choose this solution.
As promised, I've upstreamed my old Lua 5.1 output redirection patch to the latest version.
Patches are available here: 5.1.5 and 5.2.1.
Patch:
patch -p1 < ~/download/lua-5.2.1-output-redirect.patch
Build:
cd src
make a LUA_A="liblua-5.2.1-redirect.a" SYSCFLAGS="-DLUA_USE_LINUX -DLUA_REDIRECT" SYSLIBS="-Wl,-E -ldl -lreadline -lncurses"
Check:
nm liblua-5.x.y-redirect.a | grep printf
nm liblua-5.x.y-redirect.a | grep fputs
nm liblua-5.x.y-redirect.a | grep fwrite
Test:
Obtain test program here (C/C++ mixed, sorry). Build it via:
g++ -DLUA_REDIRECT -I/path/to/lua-5.2.1/src/ -L. lua-redirect-test.cpp -llua-5.2.1-redirect -ldl -o lua-redirect-test
Output:
===== Test 1 output =====
Lua stdout buffer:
---
hello world!
---
Lua stderr buffer:
---
---
Lua error message:
---
(null)
---
===== Test 2 output =====
Lua stdout buffer:
---
---
Lua stderr buffer:
---
---
Lua error message:
---
[string "bad_function()"]:1: attempt to call global 'bad_function' (a nil value)
---
trouble redefining print function in lua
First error: It's luaL_Reg
, not luaL_reg
.
Second error:
luaL_register is deprecated (in Lua 5.2), and is only available if LUA_COMPAT_MODULE is defined before you include the Lua headers. You should use luaL_setfuncs instead.
Rerouting Lua print in C++ with default print behavior
You can try on default this:
lua_pushfstring(L, "%s: %p", luaL_typename(L, i), lua_topointer(L, i));
or
luaout << luaL_typename(L, i) << ": " << lua_topointer(L, i);
This will add the name of the function and the pointer.
You can call lua function from C++ (don't guarantee to work as I have not tested it, but it should aside from grammatical errors)
lua_getglobal(L, "tostring");
lua_pushvalue (L, i);
if (lua_pcall(L, 1, 1, 0) != 0) {
printf("error running function `%s': %s\n", "tostring", lua_tostring(L, -1));
return -1;
}
// get result
char *result = luaL_checkstring (L, -1);
Embedded Lua print not working in debug mode from Visual Studio
Unfortunately, you are probably up against a known deficiency in the print()
function, which is really intended for quick and dirty debugging at a console prompt, and is missing some necessary flexibility.
The base library function print()
implemented by luaB_print()
in lbaselib.c explicitly uses the C runtime's stdout
stream as its destination. Since it refers to the global variable stdout
explicitly in its implementation, the only way to redirect it is to cause that file handle to be redirected. In a C program that can be done by calling freopen(stdout,...)
. Unfortunately, there isn't a stock library function in Lua that can do that.
The io
library is implemented in liolib.c. It uses the function environment to hold a table of open file descriptors, and during its initialization it creates file
objects named io.stdin
, io.stdout
and io.stderr
for the three standard descriptors. It also provides functions named io.output
and io.input
to allow those two descriptors to be modified to point to any open file
object (or a newly opened file if a file name is passed). However, those functions only change the function environment table and do not call freopen()
to modify the C runtime's table of FILE
values.
I have no idea how LuaInterface attempts to treat the standard C runtime's idea of stdout
. It may very well be that stdout
is not connected to anything useful in the VS debugger because it probably takes advantage of some .NET feature to capture output from the module being debugged that may not be all that compatible with C in any case.
That said, it is easy to replace the standard print
function. Just use existing features of LuaInterface to write a global function named print
that calls tostring()
on each argument and passes it to the whatever .NET things is the standard output device.
Lua vs Embedded Lisp and potential other candidates. for set based data processing
I strongly agree with @jpjacobs's points. Lua is an excellent choice for embedding, unless there's something very specific about lisp that you need (for instance, if your data maps particularly well to cons-cells).
I've used lisp for many many years, BTW, and I quite like lisp syntax, but these days I'd generally pick Lua. While I like the lisp language, I've yet to find a lisp implementation that captures the wonderful balance of features/smallness/usability for embedded use the way Lua does.
Lua:
Is very small, both source and binary, an order of magnitude or more smaller than many more popular languages (Python etc). Because the Lua source code is so small and simple, it's perfectly reasonable to just include the entire Lua implementation in your source tree, if you want to avoid adding an external dependency.
Is very fast. The Lua interpreter is much faster than most scripting languages (again, an order of magnitude is not uncommon), and LuaJIT2 is a very good JIT compiler for some popular CPU architectures (x86, arm, mips, ppc). Using LuaJIT can often speed things up by another order of magnitude, and in many cases, the result approaches the speed of C. LuaJIT is also a "drop-in" replacement for standard Lua 5.1: no application or user code changes are required to use it.
Has LPEG. LPEG is a "Parsing Expression Grammar" library for Lua, which allows very easy, powerful, and fast parsing, suitable for both large and small tasks; it's a great replacement for yacc/lex/hairy-regexps. [I wrote a parser using LPEG and LuaJIT, which is much faster than the yacc/lex parser I was trying emulate, and was very easy and straight-forward to create.] LPEG is an add-on package for Lua, but is well-worth getting (it's one source file).
Has a great C-interface, which makes it a pleasure to call Lua from C, or call C from Lua. For interfacing large/complex C++ libraries, one can use SWIG, or any one of a number of interface generators (one can also just use Lua's simple C interface with C++ of course).
Has liberal licensing ("BSD-like"), which means Lua can be embedded in proprietary projects if you wish, and is GPL-compatible for FOSS projects.
Is very, very elegant. It's not lisp, in that it's not based around cons-cells, but it shows clear influences from languages like scheme, with a straight-forward and attractive syntax. Like scheme (at least in it's earlier incarnations), it tends towards "minimal" but does a good job of balancing that with usability. For somebody with a lisp background (like me!), a lot about Lua will seem familiar, and "make sense", despite the differences.
Is very flexible, and such features as metatables allow easily integrating domain-specific types and operations.
Has a simple, attractive, and approachable syntax. This might not be such an advantage over lisp for existing lisp users, but might be relevant if you intend to have end-users write scripts.
Is designed for embedding, and besides its small size and fast speed, has various features such as an incremental GC that make using a scripting language more viable in such contexts.
Has a long history, and responsible and professional developers, who have shown good judgment in how they've evolved the language over the last 2 decades.
Has a vibrant and friendly user-community.
Related Topics
What Can Make C++ Rtti Undesirable to Use
Undefined Symbols for Architecture X86_64 - Mavericks (Yosemite, El Capitan...)
Large 2D Array Gives Segmentation Fault
Class Template for Numeric Types
Unresolved External Symbol "Public: Virtual Struct Qmetaobject Const * _Thiscall Parent
How to Assign Multiple Values into a Struct at Once
Performance Penalty for Working with Interfaces in C++
Why Does Int Main() {} Compile
Operator << Must Take Exactly One Argument
Reinterpret_Cast Between Char* and Std::Uint8_T* - Safe
Template Function Inside Template Class
Sqlite3_Exec() Callback Function Clarification
Qt/Qml:Send Qimage from C++ to Qml and Display the Qimage on Gui