328 lines
8.5 KiB
C
328 lines
8.5 KiB
C
/* The Lua runtime component of the EFL */
|
|
|
|
#include "main.h"
|
|
|
|
static Eina_List *modlist = NULL;
|
|
static int require_ref = LUA_REFNIL;
|
|
|
|
int el_log_domain = -1;
|
|
|
|
enum {
|
|
ARG_CODE = 0, ARG_MODULE, ARG_LIBRARY
|
|
};
|
|
|
|
typedef struct Arg_Data {
|
|
int type;
|
|
const char *value;
|
|
} Arg_Data;
|
|
|
|
static Eina_Bool append_cb(const Ecore_Getopt *parser EINA_UNUSED,
|
|
const Ecore_Getopt_Desc *desc EINA_UNUSED,
|
|
const char *str,
|
|
void *data,
|
|
Ecore_Getopt_Value *val)
|
|
{
|
|
Eina_List **l = val->listp;
|
|
Arg_Data *v = malloc(sizeof(Arg_Data));
|
|
v->type = (size_t)data;
|
|
v->value = str;
|
|
*l = eina_list_append(*l, v);
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
static Ecore_Getopt opt = {
|
|
"elua", "%prog [options] [script [args]]", "0.0.1", "See COPYING",
|
|
"See COPYING", "A main entry for all EFL/LuaJIT powered applications.",
|
|
0, {
|
|
ECORE_GETOPT_LICENSE('L', "license"),
|
|
ECORE_GETOPT_COPYRIGHT('c', "copyright"),
|
|
ECORE_GETOPT_VERSION('v', "version"),
|
|
ECORE_GETOPT_HELP('h', "help"),
|
|
|
|
ECORE_GETOPT_CALLBACK_ARGS('e', "execute", "Execute string "
|
|
"'code'.", "CODE", append_cb, (void*)ARG_CODE),
|
|
ECORE_GETOPT_CALLBACK_ARGS('m', "module", "Include module 'module'.",
|
|
"MODULE", append_cb, (void*)ARG_MODULE),
|
|
ECORE_GETOPT_CALLBACK_ARGS('l', "library", "Require library 'library'.",
|
|
"LIBRARY", append_cb, (void*)ARG_LIBRARY),
|
|
ECORE_GETOPT_STORE_TRUE('E', "noenv", "Ignore environment vars."),
|
|
|
|
ECORE_GETOPT_SENTINEL
|
|
}
|
|
};
|
|
|
|
static void errmsg(const char *pname, const char *msg) {
|
|
ERR("%s%s%s", pname ? pname : "", pname ? ": " : "", msg);
|
|
}
|
|
|
|
static int report(lua_State *L, int status) {
|
|
if (status && !lua_isnil(L, -1)) {
|
|
const char *msg = lua_tostring(L, -1);
|
|
errmsg(opt.prog, msg ? msg : "(non-string error)");
|
|
lua_pop(L, 1);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
static int traceback(lua_State *L) {
|
|
lua_getglobal(L, "debug");
|
|
if (!lua_istable(L, -1)) {
|
|
lua_pop(L, 1);
|
|
return 1;
|
|
}
|
|
lua_getfield(L, -1, "traceback");
|
|
if (!lua_isfunction(L, -1)) {
|
|
lua_pop(L, 2);
|
|
return 1;
|
|
}
|
|
lua_pushvalue(L, 1);
|
|
lua_pushinteger(L, 2);
|
|
lua_call(L, 2, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int docall(lua_State *L, int narg) {
|
|
int status;
|
|
int bs = lua_gettop(L) - narg;
|
|
lua_pushcfunction(L, traceback);
|
|
lua_insert(L, bs);
|
|
status = lua_pcall(L, narg, 0, bs);
|
|
lua_remove(L, bs);
|
|
if (status) lua_gc(L, LUA_GCCOLLECT, 0);
|
|
return status;
|
|
}
|
|
|
|
static int getargs(lua_State *L, int argc, char **argv, int n) {
|
|
int i;
|
|
int narg = argc - (n + 1);
|
|
luaL_checkstack(L, narg + 3, "too many arguments to script");
|
|
for (i = n + 1; i < argc; ++i) lua_pushstring(L, argv[i]);
|
|
lua_createtable(L, narg, n + 1);
|
|
for (i = 0; i < argc; ++i) {
|
|
lua_pushstring(L, argv[i]);
|
|
lua_rawseti(L, -2, i - n);
|
|
}
|
|
return narg;
|
|
}
|
|
|
|
static int init_module(lua_State *L) {
|
|
if (!lua_isnoneornil(L, 1)) {
|
|
lua_pushvalue(L, 1);
|
|
lua_call(L, 0, 0);
|
|
}
|
|
if (!lua_isnoneornil(L, 2)) {
|
|
lua_pushvalue(L, 2);
|
|
modlist = eina_list_append(modlist,
|
|
(void*)(size_t)luaL_ref(L, LUA_REGISTRYINDEX));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int register_require(lua_State *L) {
|
|
lua_pushvalue(L, 1);
|
|
require_ref = luaL_ref(L, LUA_REGISTRYINDEX);
|
|
lua_pushliteral(L, ELUA_DATA_DIR "/core/?.lua;");
|
|
lua_pushliteral(L, ELUA_DATA_DIR "/modules/?.lua;");
|
|
lua_pushvalue(L, 2);
|
|
lua_concat(L, 3);
|
|
return 1;
|
|
}
|
|
|
|
static int dolib(lua_State *L, const char *libname) {
|
|
lua_rawgeti(L, LUA_REGISTRYINDEX, require_ref);
|
|
lua_pushstring(L, libname);
|
|
return report(L, lua_pcall(L, 1, 0, 0));
|
|
}
|
|
|
|
static int dofile(lua_State *L, const char *fname) {
|
|
return report(L, elua_loadfile(L, fname) || docall(L, 0));
|
|
}
|
|
|
|
static int dostr(lua_State *L, const char *chunk, const char *chname) {
|
|
return report(L, luaL_loadbuffer(L, chunk, strlen(chunk), chname)
|
|
|| docall(L, 0));
|
|
}
|
|
|
|
static int doscript(lua_State *L, int argc, char **argv, int n) {
|
|
int status;
|
|
const char *fname = argv[n];
|
|
int narg = getargs(L, argc, argv, n);
|
|
lua_setglobal(L, "arg");
|
|
if (fname[0] == '-' && !fname[1]) {
|
|
fname = NULL;
|
|
}
|
|
status = elua_loadfile(L, fname);
|
|
lua_insert(L, -(narg + 1));
|
|
if (!status) {
|
|
status = docall(L, narg);
|
|
} else {
|
|
lua_pop(L, narg);
|
|
}
|
|
return report(L, status);
|
|
}
|
|
|
|
void shutdown(lua_State *L, int c) {
|
|
void *data;
|
|
INF("elua shutdown");
|
|
|
|
EINA_LIST_FREE(modlist, data) {
|
|
lua_rawgeti(L, LUA_REGISTRYINDEX, (size_t)data);
|
|
lua_call(L, 0, 0);
|
|
}
|
|
|
|
if (L) lua_close(L);
|
|
eina_shutdown();
|
|
exit(c);
|
|
}
|
|
|
|
static int cb_ref = LUA_REFNIL;
|
|
static lua_State *LL = NULL;
|
|
|
|
static void smart_cb_wrapper(void *data, void *obj EINA_UNUSED,
|
|
void *einfo EINA_UNUSED) {
|
|
int idx = (size_t)data;
|
|
lua_rawgeti(LL, LUA_REGISTRYINDEX, cb_ref);
|
|
lua_rawgeti(LL, -1, idx);
|
|
lua_call(LL, 0, 0);
|
|
lua_pop(LL, 1);
|
|
}
|
|
|
|
static int register_callbacks(lua_State *L) {
|
|
union { void (*fptr)(void*, void*, void*); void *ptr; } u;
|
|
lua_pushvalue(L, 1);
|
|
cb_ref = luaL_ref(L, LUA_REGISTRYINDEX);
|
|
u.fptr = smart_cb_wrapper;
|
|
lua_pushlightuserdata(L, u.ptr);
|
|
return 1;
|
|
}
|
|
|
|
struct Main_Data {
|
|
int argc;
|
|
char **argv;
|
|
int status;
|
|
};
|
|
|
|
const luaL_reg utillib[] = {
|
|
{ "init_module", init_module },
|
|
{ "register_callbacks", register_callbacks },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* protected main */
|
|
static int lua_main(lua_State *L) {
|
|
Eina_Bool quit = EINA_FALSE,
|
|
noenv = EINA_FALSE,
|
|
hasexec = EINA_FALSE;
|
|
Eina_List *largs = NULL, *l = NULL;
|
|
Arg_Data *data = NULL;
|
|
|
|
int nonopt;
|
|
|
|
struct Main_Data *m = (struct Main_Data*)lua_touserdata(L, 1);
|
|
|
|
int argc = m->argc;
|
|
char **argv = m->argv;
|
|
|
|
if (argv[0] && argv[0][0]) opt.prog = argv[0];
|
|
|
|
lua_gc(L, LUA_GCSTOP, 0);
|
|
|
|
luaL_openlibs(L);
|
|
|
|
elua_loadfile(L, ELUA_DATA_DIR "/core/module.lua");
|
|
lua_pushcfunction(L, register_require);
|
|
lua_createtable(L, 0, 0);
|
|
luaL_register(L, NULL, utillib);
|
|
lua_call(L, 2, 0);
|
|
|
|
elua_register_cache(L);
|
|
lua_gc(L, LUA_GCRESTART, 0);
|
|
|
|
INF("elua lua state initialized");
|
|
|
|
nonopt = ecore_getopt_parse(&opt, (Ecore_Getopt_Value[]){
|
|
ECORE_GETOPT_VALUE_BOOL(quit), /* license */
|
|
ECORE_GETOPT_VALUE_BOOL(quit), /* copyright */
|
|
ECORE_GETOPT_VALUE_BOOL(quit), /* version */
|
|
ECORE_GETOPT_VALUE_BOOL(quit), /* help */
|
|
|
|
ECORE_GETOPT_VALUE_LIST(largs),
|
|
ECORE_GETOPT_VALUE_LIST(largs),
|
|
ECORE_GETOPT_VALUE_LIST(largs),
|
|
ECORE_GETOPT_VALUE_BOOL(noenv)
|
|
}, argc, argv);
|
|
|
|
INF("arguments parsed");
|
|
|
|
if (quit) return 0;
|
|
|
|
/* load all the things */
|
|
EINA_LIST_FOREACH(largs, l, data) {
|
|
switch (data->type) {
|
|
case ARG_CODE:
|
|
if (!hasexec) hasexec = EINA_TRUE;
|
|
if (dostr(L, data->value, "=(command line)")) {
|
|
m->status = 1;
|
|
return 0;
|
|
}
|
|
break;
|
|
case ARG_MODULE:
|
|
break;
|
|
case ARG_LIBRARY:
|
|
if (dolib(L, data->value)) {
|
|
m->status = 1;
|
|
return 0;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* cleanup */
|
|
EINA_LIST_FREE(largs, data) free(data);
|
|
|
|
/* run script or execute sdin as file */
|
|
if (nonopt >= 0 && nonopt < argc) {
|
|
if ((m->status = doscript(L, argc, argv, nonopt))) return 0;
|
|
} else if (!hasexec) {
|
|
dofile(L, NULL);
|
|
}
|
|
|
|
ecore_main_loop_begin();
|
|
|
|
return 0;
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
struct Main_Data m;
|
|
lua_State *L = NULL;
|
|
|
|
eina_init();
|
|
|
|
if (!(el_log_domain = eina_log_domain_register("elua",
|
|
EINA_COLOR_ORANGE))) {
|
|
printf("cannot set elua log domain\n");
|
|
ERR("could not set elua log domain.");
|
|
el_log_domain = EINA_LOG_DOMAIN_GLOBAL;
|
|
}
|
|
|
|
INF("elua logging initialized: %d", el_log_domain);
|
|
|
|
if (!(L = luaL_newstate())) {
|
|
ERR("could not initialize elua state.");
|
|
shutdown(L, 1);
|
|
}
|
|
|
|
LL = L;
|
|
|
|
INF("elua lua state created");
|
|
|
|
m.argc = argc;
|
|
m.argv = argv;
|
|
m.status = 0;
|
|
|
|
shutdown(L, !!(lua_cpcall(L, lua_main, &m) || m.status));
|
|
|
|
return 0; /* never gets here */
|
|
} |