|
Warning: this is an htmlized version!
The original is here, and the conversion rules are here. |
/*
* luatclbridge.c - a Lua<->Tcl bridge.
* By Eduardo Ochs <eduardoochs@gmail.com>
* Version: 2007aug14
* http://angg.twu.net/LUA/luatclbridge.c
* http://angg.twu.net/LUA/luatclbridge.c.html
* (find-es "lua5" "luatclbridge")
* (find-es "lua5" "tlbridge.c")
* (find-angg "LUA/lua50init.lua" "loadtcl")
*
* Note: some inter-language bridges - for example, lunatic-python -
* can be loaded from both interpreters; this one cannot, you need to
* load it from the Lua side.
*
* This is a very minimalistic two-way bridge between Lua and Tcl. It
* adds one global function to Lua ("tcl", to call Tcl), and one to
* Tcl ("lua", to call Lua); none of them check for errors, and if you
* are running code in the other language that may fail in nasty ways
* then you should implement your own wrappers - called, say, "plua"
* and "ptcl", that execute functions in the other language with some
* kind of protection. I believe that these wrappers should be easy
* enough to write in Lua and Tcl, without the need for more C code;
* and the simpler we can keep the part in C the better - many more
* people can understand the parts in Tcl and Lua than the part in C.
*
* NOTE: There were two natural choices for how to call Tcl from Lua:
* tcl("expr", "12+34") -- <-- I have NOT chosen this
* tcl("expr 12+34") -- <-- I have chosen this one.
*/
#include <stdio.h>
#include <tcl.h>
#include <lua.h>
#include <lauxlib.h>
/* interpreters */
lua_State *LuaTclBridge_L;
Tcl_Interp *LuaTclBridge_T;
/* Tcl -> Lua
* Example of use:
* lua print 22 {foo bar}
* this calls the global Lua function called "print"
* with arguments "22" and "foo bar".
* The value returned to Tcl is always the frist value returned by the
* Lua function, converted to a string with lua_tostring; so this
* returns "nil" (yes, as a string!...).
*/
int LuaTclBridge_call_lua(ClientData clientData, Tcl_Interp *interp,
int argc, const char *argv[]) {
lua_State *L = LuaTclBridge_L;
int i;
//
// (find-luamanualw3m "#lua_call")
lua_getfield(L, LUA_GLOBALSINDEX, argv[1]); // push first arg as a function
for (i=2; i<argc; ++i) // for each one of the other args
lua_pushstring(L, argv[i]); // push it as a string
lua_call(L, argc - 2, 1); // call - expect one result
//
// Now return a string result to Tcl...
// (find-man "3tcl Tcl_SetResult" "THE TCL_FREEPROC ARGUMENT" "TCL_VOLATILE")
Tcl_SetResult(interp, lua_tostring(L, 1), TCL_VOLATILE);
//
// We're always returning TCL_OK at this moment...
// What should we do when the call to Lua triggers an error?
// Right now we just expect the user to be super-careful...
// (find-man "3tcl Tcl_Eval" "TCL_OK")
return TCL_OK;
}
/* Lua -> Tcl
* Example of use:
* tcl("expr 22+33")
* returns "55".
*
* Note that this function receives a single argument, a string to
* execute as a Tcl program - not a series of strings, each one being
* a word of a Tcl command.
*/
int LuaTclBridge_call_tcl(lua_State *L) {
if (!LuaTclBridge_L)
LuaTclBridge_L = L;
if (!LuaTclBridge_T) {
// Tcl_FindExecutable(argv[0]); <-- a bit of black magic, see my tcl.e
// Tcl_FindExecutable("");
LuaTclBridge_T = Tcl_CreateInterp();
Tcl_CreateCommand(LuaTclBridge_T, "lua", LuaTclBridge_call_lua,
(ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
}
Tcl_Eval(LuaTclBridge_T, luaL_checklstring(L, 1, NULL));
lua_pushstring(L, Tcl_GetStringResult(LuaTclBridge_T));
return 1;
}
/* Experimental, 2007aug14
*/
static int LuaTclBridge_tclfindexecutable(lua_State *L) {
Tcl_FindExecutable(luaL_checklstring(L, 1, NULL));
return 0;
}
/* initalization.
* Usage:
* tcl = require "tlbridge"
* print(tcl("expr 22+33")) -> "55"
*/
LUALIB_API int luaopen_luatclbridge (lua_State *L) {
lua_pushcfunction(L, LuaTclBridge_call_tcl);
lua_pushcfunction(L, LuaTclBridge_tclfindexecutable);
return 2;
}