/* embed2.c some more test for an embeded interpreter | |
This will go a bit further as it will pass values to and from the lua code. | |
It uses less of the SWIG code, and more of the raw lua API's | |
What it will do is load the wrappered lib, load runme.lua and then call some functions. | |
To make life easier, all the printf's have either [C] or [Lua] at the start | |
so you can see where they are coming from. | |
We will be using the luaL_dostring()/lua_dostring() function to call into lua | |
*/ | |
/* Deal with Microsoft's attempt at deprecating C standard runtime functions */ | |
#if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) | |
# define _CRT_SECURE_NO_DEPRECATE | |
#endif | |
/* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */ | |
#if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE) | |
# define _SCL_SECURE_NO_DEPRECATE | |
#endif | |
#include <stdlib.h> | |
#include <stdio.h> | |
#include <lua.h> | |
#include <lauxlib.h> | |
#include <lualib.h> | |
#include <stdarg.h> | |
#include <string.h> | |
/* the SWIG wrappered library */ | |
extern int luaopen_example(lua_State*L); | |
/* This is an example of how to call the Lua function | |
int add(int,int) | |
its very tedious, but gives you an idea of the issues involded. | |
(look below for a better idea) | |
*/ | |
int call_add(lua_State *L,int a,int b,int* res) { | |
int top; | |
/* ok, here we go: | |
push a, push b, call 'add' check & return res | |
*/ | |
top=lua_gettop(L); /* for later */ | |
lua_pushstring(L, "add"); /* function name */ | |
lua_gettable(L, LUA_GLOBALSINDEX); /* function to be called */ | |
if (!lua_isfunction(L,-1)) { | |
printf("[C] error: cannot find function 'add'\n"); | |
lua_settop(L,top); // reset | |
return 0; | |
} | |
lua_pushnumber(L,a); | |
lua_pushnumber(L,b); | |
if (lua_pcall(L, 2, 1, 0) != 0) /* call function with 2 arguments and 1 result */ | |
{ | |
printf("[C] error running function `add': %s\n",lua_tostring(L, -1)); | |
lua_settop(L,top); // reset | |
return 0; | |
} | |
// check results | |
if (!lua_isnumber(L,-1)) { | |
printf("[C] error: returned value is not a number\n"); | |
lua_settop(L,top); // reset | |
return 0; | |
} | |
*res=(int)lua_tonumber(L,-1); | |
lua_settop(L,top); /* reset stack */ | |
return 1; // ok | |
} | |
/* This is a variargs call function for calling from C into Lua. | |
Original Code from Programming in Lua (PIL) by Roberto Ierusalimschy | |
ISBN 85-903798-1-7 | |
http://www.lua.org/pil/25.3.html | |
This has been modified slightly to make it compile, and its still a bit rough. | |
But it gives the idea of how to make it work. | |
*/ | |
int call_va (lua_State *L,const char *func, const char *sig, ...) { | |
va_list vl; | |
int narg, nres; /* number of arguments and results */ | |
int top; | |
top=lua_gettop(L); /* for later */ | |
va_start(vl, sig); | |
lua_getglobal(L, func); /* get function */ | |
/* push arguments */ | |
narg = 0; | |
while (*sig) { /* push arguments */ | |
switch (*sig++) { | |
case 'd': /* double argument */ | |
lua_pushnumber(L, va_arg(vl, double)); | |
break; | |
case 'i': /* int argument */ | |
lua_pushnumber(L, va_arg(vl, int)); | |
break; | |
case 's': /* string argument */ | |
lua_pushstring(L, va_arg(vl, char *)); | |
break; | |
case '>': | |
goto endwhile; | |
default: | |
printf("invalid option (%c)\n", *(sig - 1)); | |
goto fail; | |
} | |
narg++; | |
/* do we need this?*/ | |
/* luaL_checkstack(L, 1, "too many arguments"); */ | |
} | |
endwhile: | |
/* do the call */ | |
nres = (int)strlen(sig); /* number of expected results */ | |
if (lua_pcall(L, narg, nres, 0) != 0) /* do the call */ | |
{ | |
printf("error running function `%s': %s\n",func, lua_tostring(L, -1)); | |
goto fail; | |
} | |
/* retrieve results */ | |
nres = -nres; /* stack index of first result */ | |
while (*sig) { /* get results */ | |
switch (*sig++) { | |
case 'd': /* double result */ | |
if (!lua_isnumber(L, nres)) { | |
printf("wrong result type\n"); | |
goto fail; | |
} | |
*va_arg(vl, double *) = lua_tonumber(L, nres); | |
break; | |
case 'i': /* int result */ | |
if (!lua_isnumber(L, nres)) { | |
printf("wrong result type\n"); | |
goto fail; | |
} | |
*va_arg(vl, int *) = (int)lua_tonumber(L, nres); | |
break; | |
case 's': /* string result */ | |
if (!lua_isstring(L, nres)) { | |
printf("wrong result type\n"); | |
goto fail; | |
} | |
strcpy(va_arg(vl, char *),lua_tostring(L, nres));/* WARNING possible buffer overflow */ | |
break; | |
default: { | |
printf("invalid option (%c)", *(sig - 1)); | |
goto fail; | |
} | |
} | |
nres++; | |
} | |
va_end(vl); | |
lua_settop(L,top); /* reset stack */ | |
return 1; /* ok */ | |
fail: | |
lua_settop(L,top); /* reset stack */ | |
return 0; /* error */ | |
} | |
int main(int argc,char* argv[]) { | |
lua_State *L; | |
int ok; | |
int res; | |
char str[80]; | |
printf("[C] Welcome to the simple embedded Lua example v2\n"); | |
printf("[C] We are in C\n"); | |
printf("[C] opening a Lua state & loading the libraries\n"); | |
L=lua_open(); | |
luaopen_base(L); | |
luaopen_string(L); | |
luaopen_math(L); | |
printf("[C] now loading the SWIG wrappered library\n"); | |
luaopen_example(L); | |
printf("[C] all looks ok\n"); | |
printf("\n"); | |
printf("[C] lets load the file 'runme.lua'\n"); | |
printf("[C] any lua code in this file will be executed\n"); | |
if (luaL_loadfile(L, "runme.lua") || lua_pcall(L, 0, 0, 0)) { | |
printf("[C] ERROR: cannot run lua file: %s",lua_tostring(L, -1)); | |
exit(3); | |
} | |
printf("[C] We are now back in C, all looks ok\n"); | |
printf("\n"); | |
printf("[C] lets call the Lua function 'add(1,1)'\n"); | |
printf("[C] using the C function 'call_add'\n"); | |
ok=call_add(L,1,1,&res); | |
printf("[C] the function returned %d with value %d\n",ok,res); | |
printf("\n"); | |
printf("[C] lets do this rather easier\n"); | |
printf("[C] we will call the same Lua function using a generic C function 'call_va'\n"); | |
ok=call_va(L,"add","ii>i",1,1,&res); | |
printf("[C] the function returned %d with value %d\n",ok,res); | |
printf("\n"); | |
printf("[C] we will now use the same generic C function to call 'append(\"cat\",\"dog\")'\n"); | |
ok=call_va(L,"append","ss>s","cat","dog",str); | |
printf("[C] the function returned %d with value %s\n",ok,str); | |
printf("\n"); | |
printf("[C] we can also make some bad calls to ensure the code doesn't fail\n"); | |
printf("[C] calling adds(1,2)\n"); | |
ok=call_va(L,"adds","ii>i",1,2,&res); | |
printf("[C] the function returned %d with value %d\n",ok,res); | |
printf("[C] calling add(1,'fred')\n"); | |
ok=call_va(L,"add","is>i",1,"fred",&res); | |
printf("[C] the function returned %d with value %d\n",ok,res); | |
printf("\n"); | |
printf("[C] Note: no protection if you mess up the va-args, this is C\n"); | |
printf("\n"); | |
printf("[C] Finally we will call the wrappered gcd function gdc(6,9):\n"); | |
printf("[C] This will pass the values to Lua, then call the wrappered function\n"); | |
printf(" Which will get the values from Lua, call the C code \n"); | |
printf(" and return the value to Lua and eventually back to C\n"); | |
printf("[C] Certainly not the best way to do it :-)\n"); | |
ok=call_va(L,"gcd","ii>i",6,9,&res); | |
printf("[C] the function returned %d with value %d\n",ok,res); | |
printf("\n"); | |
printf("[C] all finished, closing the lua state\n"); | |
lua_close(L); | |
return 0; | |
} |