forked from enlightenment/efl
Merge branch 'devs/q66/elua_lib_overhaul'
This merge introduces a solid, documented API for the Elua library, allowing people to embed Elua into their own applications. For now this library is beta and will remain so for a while, in case more changes are necessary.
This commit is contained in:
commit
c77b91529b
|
@ -14,7 +14,6 @@ lib_elua_libelua_la_SOURCES = \
|
|||
|
||||
lib_elua_libelua_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl @ELUA_CFLAGS@ \
|
||||
-DLOCALE_DIR=\"@LOCALE_DIR@\" \
|
||||
-DPACKAGE_SRC_DIR=\"$(abs_top_srcdir)\" \
|
||||
-DPACKAGE_BIN_DIR=\"$(bindir)\" \
|
||||
-DPACKAGE_DATA_DIR=\"$(datadir)/elua\"
|
||||
|
||||
|
@ -32,10 +31,7 @@ bin_elua_elua_SOURCES = \
|
|||
bin/elua/main.c
|
||||
|
||||
bin_elua_elua_CPPFLAGS = -I$(top_builddir)/src/lib/efl @ELUA_CFLAGS@ \
|
||||
-DLOCALE_DIR=\"@LOCALE_DIR@\" \
|
||||
-DPACKAGE_SRC_DIR=\"$(abs_top_srcdir)\" \
|
||||
-DPACKAGE_BIN_DIR=\"$(bindir)\" \
|
||||
-DPACKAGE_DATA_DIR=\"$(datadir)/elua\"
|
||||
-DLOCALE_DIR=\"@LOCALE_DIR@\"
|
||||
|
||||
if HAVE_OSX
|
||||
if HAVE_X86_64
|
||||
|
@ -50,6 +46,11 @@ bin_elua_elua_LDADD = @ELUA_LIBS@ @USE_ELUA_LIBS@
|
|||
endif
|
||||
bin_elua_elua_DEPENDENCIES = @ELUA_INTERNAL_LIBS@ lib/elua/libelua.la
|
||||
|
||||
ELUA_BINDINGS_DIR = $(abs_top_srcdir)/src/bindings/luajit
|
||||
ELUA_CORE_DIR = $(abs_top_srcdir)/src/scripts/elua/core
|
||||
ELUA_MODULES_DIR = $(abs_top_srcdir)/src/scripts/elua/modules
|
||||
ELUA_APPS_DIR = $(abs_top_srcdir)/src/scripts/elua/apps
|
||||
|
||||
### Helper for other modules using Elua
|
||||
include Makefile_Elua_Helper.am
|
||||
|
||||
|
@ -106,4 +107,37 @@ eluacore_DATA = \
|
|||
|
||||
EXTRA_DIST += $(eluacore_DATA)
|
||||
|
||||
if EFL_ENABLE_TESTS
|
||||
|
||||
check_PROGRAMS += tests/elua/elua_suite
|
||||
|
||||
tests_elua_elua_suite_SOURCES = \
|
||||
tests/elua/elua_lib.c \
|
||||
tests/elua/elua_suite.c \
|
||||
tests/elua/elua_suite.h
|
||||
|
||||
tests_elua_elua_suite_CPPFLAGS = -I$(top_builddir)/src/lib/efl \
|
||||
-DTESTS_BUILD_DIR=\"$(top_builddir)/src/tests/elua\" \
|
||||
-DPACKAGE_DATA_DIR=\"$(top_srcdir)/src/tests/elua\" \
|
||||
-DPACKAGE_BUILD_DIR=\"$(abs_top_builddir)\" \
|
||||
-DELUA_BINDINGS_DIR=\"$(ELUA_BINDINGS_DIR)\" \
|
||||
-DELUA_CORE_DIR=\"$(ELUA_CORE_DIR)\" \
|
||||
-DELUA_MODULES_DIR=\"$(ELUA_MODULES_DIR)\" \
|
||||
-DELUA_APPS_DIR=\"$(ELUA_APPS_DIR)\" \
|
||||
@CHECK_CFLAGS@ \
|
||||
@ELUA_CFLAGS@
|
||||
|
||||
TESTS += tests/elua/elua_suite
|
||||
|
||||
if HAVE_OSX
|
||||
if HAVE_X86_64
|
||||
tests_elua_elua_suite_LDFLAGS = -pagezero_size 10000 -image_base 100000000
|
||||
endif
|
||||
endif
|
||||
|
||||
tests_elua_elua_suite_LDADD = @CHECK_LIBS@ @USE_ELUA_LIBS@
|
||||
tests_elua_elua_suite_DEPENDENCIES = @USE_ELUA_INTERNAL_LIBS@
|
||||
|
||||
endif
|
||||
|
||||
endif
|
||||
|
|
|
@ -3,7 +3,9 @@ ELUA_GEN = @elua_bin@ lualian
|
|||
_ELUA_GEN_DEP = @elua_bin@
|
||||
else
|
||||
ELUA_GEN = ELUA_EOLIAN_LIBRARY_PATH=$(top_builddir)/src/lib/eolian/.libs \
|
||||
EFL_RUN_IN_TREE=1 $(top_builddir)/src/bin/elua/elua${EXEEXT} lualian
|
||||
$(top_builddir)/src/bin/elua/elua${EXEEXT} \
|
||||
-I$(ELUA_BINDINGS_DIR) -C$(ELUA_CORE_DIR) -M$(ELUA_MODULES_DIR) \
|
||||
-A$(ELUA_APPS_DIR) lualian
|
||||
_ELUA_GEN_DEP = bin/elua/elua${EXEEXT} scripts/elua/apps/lualian.lua \
|
||||
scripts/elua/modules/lualian.lua \
|
||||
scripts/elua/modules/getopt.lua scripts/elua/core/util.lua \
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
# include <config.h>
|
||||
#endif
|
||||
|
||||
/* The Lua runtime component of the EFL */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <getopt.h>
|
||||
|
@ -19,313 +17,19 @@
|
|||
#include <Eina.h>
|
||||
#include <Ecore.h>
|
||||
|
||||
#include "Elua.h"
|
||||
|
||||
typedef struct Arg_Data
|
||||
{
|
||||
int type;
|
||||
const char *value;
|
||||
} Arg_Data;
|
||||
|
||||
enum
|
||||
{
|
||||
ARG_CODE = 0,
|
||||
ARG_LIBRARY,
|
||||
ARG_LIBDIR
|
||||
};
|
||||
|
||||
static Eina_List *elua_modlist = NULL;
|
||||
static int elua_require_ref = LUA_REFNIL;
|
||||
static int elua_appload_ref = LUA_REFNIL;
|
||||
static const char *elua_progname = NULL;
|
||||
static Eina_Prefix *elua_prefix = NULL;
|
||||
#include <Elua.h>
|
||||
|
||||
static int _el_log_domain = -1;
|
||||
|
||||
#define DBG(...) EINA_LOG_DOM_DBG(_el_log_domain, __VA_ARGS__)
|
||||
#define INF(...) EINA_LOG_DOM_INFO(_el_log_domain, __VA_ARGS__)
|
||||
#define WRN(...) EINA_LOG_DOM_WARN(_el_log_domain, __VA_ARGS__)
|
||||
#define ERR(...) EINA_LOG_DOM_ERR(_el_log_domain, __VA_ARGS__)
|
||||
#define CRT(...) EINA_LOG_DOM_CRITICAL(_el_log_domain, __VA_ARGS__)
|
||||
|
||||
static int
|
||||
elua_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
|
||||
elua_docall(lua_State *L, int narg, int nret)
|
||||
{
|
||||
int status;
|
||||
int bs = lua_gettop(L) - narg;
|
||||
lua_pushcfunction(L, elua_traceback);
|
||||
lua_insert(L, bs);
|
||||
status = lua_pcall(L, narg, nret, bs);
|
||||
lua_remove(L, bs);
|
||||
if (status)
|
||||
lua_gc(L, LUA_GCCOLLECT, 0);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int
|
||||
elua_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
|
||||
elua_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);
|
||||
elua_modlist = eina_list_append(elua_modlist,
|
||||
(void*)(size_t)luaL_ref(L, LUA_REGISTRYINDEX));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
elua_register_require(lua_State *L)
|
||||
{
|
||||
const char *corepath = lua_touserdata(L, lua_upvalueindex(1));
|
||||
const char *modpath = lua_touserdata(L, lua_upvalueindex(2));
|
||||
const char *appspath = lua_touserdata(L, lua_upvalueindex(3));
|
||||
Eina_List *largs = lua_touserdata(L, lua_upvalueindex(4)), *l = NULL;
|
||||
Eina_Bool noenv = lua_toboolean (L, lua_upvalueindex(5));
|
||||
Arg_Data *data = NULL;
|
||||
char corepathbuf[PATH_MAX], modpathbuf[PATH_MAX], appspathbuf[PATH_MAX];
|
||||
int n = 3;
|
||||
lua_pushvalue(L, 1);
|
||||
elua_require_ref = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
lua_pushvalue(L, 2);
|
||||
elua_appload_ref = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
if (getenv("EFL_RUN_IN_TREE"))
|
||||
{
|
||||
corepath = PACKAGE_SRC_DIR "/src/scripts/elua/core";
|
||||
modpath = PACKAGE_SRC_DIR "/src/scripts/elua/modules";
|
||||
appspath = PACKAGE_SRC_DIR "/src/scripts/elua/apps";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!corepath)
|
||||
{
|
||||
if (noenv || !(corepath = getenv("ELUA_CORE_DIR")) || !corepath[0])
|
||||
{
|
||||
corepath = corepathbuf;
|
||||
snprintf(corepathbuf, sizeof(corepathbuf), "%s/core",
|
||||
eina_prefix_data_get(elua_prefix));
|
||||
}
|
||||
}
|
||||
if (!modpath)
|
||||
{
|
||||
if (noenv || !(modpath = getenv("ELUA_MODULES_DIR")) || !modpath[0])
|
||||
{
|
||||
modpath = modpathbuf;
|
||||
snprintf(modpathbuf, sizeof(modpathbuf), "%s/modules",
|
||||
eina_prefix_data_get(elua_prefix));
|
||||
}
|
||||
}
|
||||
if (!appspath)
|
||||
{
|
||||
if (noenv || !(appspath = getenv("ELUA_APPS_DIR")) || !appspath[0])
|
||||
{
|
||||
appspath = appspathbuf;
|
||||
snprintf(appspathbuf, sizeof(appspathbuf), "%s/apps",
|
||||
eina_prefix_data_get(elua_prefix));
|
||||
}
|
||||
}
|
||||
}
|
||||
lua_pushfstring(L, "%s/?.lua;", corepath);
|
||||
EINA_LIST_FOREACH(largs, l, data)
|
||||
{
|
||||
if (data->type != ARG_LIBDIR) continue;
|
||||
lua_pushfstring(L, "%s/?.lua;", data->value);
|
||||
++n;
|
||||
}
|
||||
lua_pushfstring(L, "%s/?.eo.lua;", modpath);
|
||||
lua_pushfstring(L, "%s/?.lua;", modpath);
|
||||
lua_pushvalue(L, 3);
|
||||
lua_concat(L, n + 1);
|
||||
lua_pushfstring(L, "%s/?.lua;", appspath);
|
||||
lua_pushvalue(L, 4);
|
||||
lua_concat(L, 2);
|
||||
return 2;
|
||||
}
|
||||
|
||||
static int
|
||||
elua_dolib(lua_State *L, const char *libname)
|
||||
{
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, elua_require_ref);
|
||||
lua_pushstring(L, libname);
|
||||
return elua_report_error(L, elua_progname, lua_pcall(L, 1, 0, 0));
|
||||
}
|
||||
|
||||
static int
|
||||
elua_dofile(lua_State *L, const char *fname)
|
||||
{
|
||||
return elua_report_error(L, elua_progname, elua_io_loadfile(L, fname)
|
||||
|| elua_docall(L, 0, 1));
|
||||
}
|
||||
|
||||
static int
|
||||
elua_dostr(lua_State *L, const char *chunk, const char *chname)
|
||||
{
|
||||
return elua_report_error(L, elua_progname, luaL_loadbuffer(L, chunk,
|
||||
strlen(chunk), chname) || elua_docall(L, 0, 0));
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
elua_loadapp(lua_State *L, const char *appname)
|
||||
{
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, elua_appload_ref);
|
||||
lua_pushstring(L, appname);
|
||||
lua_call(L, 1, 2);
|
||||
if (lua_isnil(L, -2))
|
||||
{
|
||||
lua_remove(L, -2);
|
||||
return EINA_FALSE;
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
elua_doscript(lua_State *L, int argc, char **argv, int n, int *quit)
|
||||
{
|
||||
int status;
|
||||
const char *fname = argv[n];
|
||||
int narg = elua_getargs(L, argc, argv, n);
|
||||
lua_setglobal(L, "arg");
|
||||
if (fname[0] == '-' && !fname[1])
|
||||
{
|
||||
fname = NULL;
|
||||
}
|
||||
if (fname)
|
||||
{
|
||||
/* check if there is a file of that name */
|
||||
FILE *f = fopen(fname, "r");
|
||||
if (f)
|
||||
{
|
||||
fclose(f);
|
||||
status = elua_io_loadfile(L, fname);
|
||||
}
|
||||
else
|
||||
status = !elua_loadapp(L, fname);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = elua_io_loadfile(L, fname);
|
||||
}
|
||||
lua_insert(L, -(narg + 1));
|
||||
if (!status)
|
||||
{
|
||||
status = elua_docall(L, narg, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
lua_pop(L, narg);
|
||||
}
|
||||
if (!status)
|
||||
{
|
||||
*quit = lua_toboolean(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
return elua_report_error(L, elua_progname, status);
|
||||
}
|
||||
|
||||
void
|
||||
elua_bin_shutdown(lua_State *L, int c)
|
||||
{
|
||||
void *data;
|
||||
INF("elua shutdown");
|
||||
|
||||
EINA_LIST_FREE(elua_modlist, data)
|
||||
{
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, (size_t)data);
|
||||
lua_call(L, 0, 0);
|
||||
}
|
||||
|
||||
if (elua_prefix) eina_prefix_free(elua_prefix);
|
||||
|
||||
if (L) lua_close(L);
|
||||
if (_el_log_domain != EINA_LOG_DOMAIN_GLOBAL)
|
||||
eina_log_domain_unregister(_el_log_domain);
|
||||
elua_shutdown();
|
||||
exit(c);
|
||||
}
|
||||
|
||||
static int elua_cb_ref = LUA_REFNIL;
|
||||
static lua_State *elua_state = NULL;
|
||||
|
||||
static void
|
||||
elua_smart_cb_wrapper(void *data, void *obj EINA_UNUSED, void *einfo EINA_UNUSED)
|
||||
{
|
||||
int idx = (size_t)data;
|
||||
lua_rawgeti(elua_state, LUA_REGISTRYINDEX, elua_cb_ref);
|
||||
lua_rawgeti(elua_state, -1, idx);
|
||||
lua_call(elua_state, 0, 0);
|
||||
lua_pop(elua_state, 1);
|
||||
}
|
||||
|
||||
static int
|
||||
elua_register_callbacks(lua_State *L)
|
||||
{
|
||||
union { void (*fptr)(void*, void*, void*); void *ptr; } u;
|
||||
lua_pushvalue(L, 1);
|
||||
elua_cb_ref = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
u.fptr = elua_smart_cb_wrapper;
|
||||
lua_pushlightuserdata(L, u.ptr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct Main_Data
|
||||
{
|
||||
int argc;
|
||||
char **argv;
|
||||
int status;
|
||||
};
|
||||
|
||||
const luaL_reg cutillib[] =
|
||||
{
|
||||
{ "init_module" , elua_init_module },
|
||||
{ "register_callbacks", elua_register_callbacks },
|
||||
{ "popenv" , elua_io_popen },
|
||||
{ NULL , NULL }
|
||||
Elua_State *es;
|
||||
int argc;
|
||||
char **argv;
|
||||
int status;
|
||||
};
|
||||
|
||||
static void
|
||||
|
@ -335,190 +39,87 @@ elua_print_help(const char *pname, FILE *stream)
|
|||
"A main entry for all EFL/LuaJIT powered applications.\n\n"
|
||||
"The following options are supported:\n\n"
|
||||
""
|
||||
" -h, --help Show this message.\n"
|
||||
" -l, --license Show a license message.\n"
|
||||
" -C[COREDIR], --core-dir=[COREDIR] Elua core directory path.\n"
|
||||
" -M[MODDIR], --modules-dir=[MODDIR] Elua modules directory path.\n"
|
||||
" -A[APPDIR], --apps-dir=[APPDIR] Elua applications directory path.\n"
|
||||
" -e[CODE], --execute=[CODE] Execute string 'code'.\n"
|
||||
" -l[LIBRARY], --library=[LIBRARY] Require library 'library'.\n"
|
||||
" -I[DIR], --lib-dir=[DIR] Append an additional require path.\n"
|
||||
" -E, --noenv Ignore environment variables.\n", pname);
|
||||
" -h Show this message.\n"
|
||||
" -l Show a license message.\n"
|
||||
" -C[COREDIR] Elua core directory path.\n"
|
||||
" -M[MODDIR] Elua modules directory path.\n"
|
||||
" -A[APPDIR] Elua applications directory path.\n"
|
||||
" -l[LIBRARY] Require library 'library'.\n"
|
||||
" -I[DIR], Append an additional require path.\n"
|
||||
" -E, Ignore environment variables.\n", pname);
|
||||
}
|
||||
|
||||
static struct option lopt[] =
|
||||
{
|
||||
{ "help" , no_argument , NULL, 'h' },
|
||||
|
||||
{ "core-dir" , required_argument, NULL, 'C' },
|
||||
{ "modules-dir", required_argument, NULL, 'M' },
|
||||
{ "apps-dir" , required_argument, NULL, 'A' },
|
||||
|
||||
{ "execute" , required_argument, NULL, 'e' },
|
||||
{ "library" , required_argument, NULL, 'l' },
|
||||
{ "lib-dir" , required_argument, NULL, 'I' },
|
||||
{ "noenv" , no_argument , NULL, 'E' },
|
||||
{ NULL , 0 , NULL, 0 }
|
||||
};
|
||||
|
||||
/* protected main */
|
||||
static int
|
||||
elua_main(lua_State *L)
|
||||
{
|
||||
Eina_Bool noenv = EINA_FALSE,
|
||||
hasexec = EINA_FALSE;
|
||||
Eina_List *largs = NULL, *l = NULL;
|
||||
Arg_Data *data = NULL;
|
||||
const char *coref = NULL;
|
||||
char *coredir = NULL, *moddir = NULL, *appsdir = NULL;
|
||||
char modfile[PATH_MAX];
|
||||
char corefbuf[PATH_MAX];
|
||||
Eina_Bool noenv = EINA_FALSE;
|
||||
const char *coredir = NULL, *moddir = NULL, *appsdir = NULL;
|
||||
|
||||
int ch;
|
||||
|
||||
struct Main_Data *m = (struct Main_Data*)lua_touserdata(L, 1);
|
||||
struct Main_Data *m = (struct Main_Data*)lua_touserdata(L, 1);
|
||||
Elua_State *es = m->es;
|
||||
|
||||
int argc = m->argc;
|
||||
char **argv = m->argv;
|
||||
|
||||
elua_progname = (argv[0] && argv[0][0]) ? argv[0] : "elua";
|
||||
int ch;
|
||||
|
||||
while ((ch = getopt_long(argc, argv, "+LhC:M:A:e:l:I:E", lopt, NULL)) != -1)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case 'h':
|
||||
elua_print_help(elua_progname, stdout);
|
||||
return 0;
|
||||
case 'C':
|
||||
coredir = optarg;
|
||||
break;
|
||||
case 'M':
|
||||
moddir = optarg;
|
||||
break;
|
||||
case 'A':
|
||||
appsdir = optarg;
|
||||
break;
|
||||
case 'e':
|
||||
case 'l':
|
||||
case 'I':
|
||||
{
|
||||
Arg_Data *v = malloc(sizeof(Arg_Data));
|
||||
v->type = (ch == 'e') ? ARG_CODE : ((ch == 'l')
|
||||
? ARG_LIBRARY : ARG_LIBDIR);
|
||||
v->value = optarg;
|
||||
largs = eina_list_append(largs, v);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
while ((ch = getopt(argc, argv, "+LhC:M:A:l:I:E")) != -1)
|
||||
switch (ch)
|
||||
{
|
||||
case 'h':
|
||||
elua_print_help(elua_state_prog_name_get(es), stdout); return 0;
|
||||
case 'C':
|
||||
coredir = optarg; break;
|
||||
case 'M':
|
||||
moddir = optarg; break;
|
||||
case 'A':
|
||||
appsdir = optarg; break;
|
||||
case 'l':
|
||||
case 'I':
|
||||
if (!optarg[0]) continue;
|
||||
if (ch == 'l')
|
||||
elua_util_require(es, optarg);
|
||||
else
|
||||
elua_state_include_path_add(es, optarg);
|
||||
break;
|
||||
case 'E':
|
||||
noenv = EINA_TRUE; break;
|
||||
}
|
||||
|
||||
INF("arguments parsed");
|
||||
|
||||
lua_gc(L, LUA_GCSTOP, 0);
|
||||
|
||||
luaL_openlibs(L);
|
||||
elua_state_dirs_set(es, coredir, moddir, appsdir);
|
||||
elua_state_dirs_fill(es, noenv);
|
||||
|
||||
elua_prefix = eina_prefix_new(elua_progname, elua_main, "ELUA", "elua", "checkme",
|
||||
PACKAGE_BIN_DIR, "", PACKAGE_DATA_DIR,
|
||||
LOCALE_DIR);
|
||||
|
||||
if (!elua_prefix)
|
||||
{
|
||||
ERR("could not find elua prefix");
|
||||
m->status = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (getenv("EFL_RUN_IN_TREE"))
|
||||
{
|
||||
Arg_Data *v = malloc(sizeof(Arg_Data));
|
||||
v->type = ARG_LIBDIR;
|
||||
v->value = PACKAGE_SRC_DIR "/src/bindings/luajit";
|
||||
largs = eina_list_append(largs, v);
|
||||
coref = PACKAGE_SRC_DIR "/src/scripts/elua/core";
|
||||
}
|
||||
else if (!(coref = coredir))
|
||||
{
|
||||
if (noenv || !(coref = getenv("ELUA_CORE_DIR")) || !coref[0])
|
||||
{
|
||||
coref = corefbuf;
|
||||
snprintf(corefbuf, sizeof(corefbuf), "%s/core",
|
||||
eina_prefix_data_get(elua_prefix));
|
||||
}
|
||||
}
|
||||
snprintf(modfile, sizeof(modfile), "%s/module.lua", coref);
|
||||
if (elua_report_error(L, elua_progname, elua_io_loadfile(L, modfile)))
|
||||
if (!elua_state_setup(es))
|
||||
{
|
||||
m->status = 1;
|
||||
return 0;
|
||||
}
|
||||
lua_pushlightuserdata(L, coredir);
|
||||
lua_pushlightuserdata(L, moddir);
|
||||
lua_pushlightuserdata(L, appsdir);
|
||||
lua_pushlightuserdata(L, largs);
|
||||
lua_pushboolean (L, noenv);
|
||||
lua_pushcclosure(L, elua_register_require, 5);
|
||||
lua_createtable(L, 0, 0);
|
||||
luaL_register(L, NULL, cutillib);
|
||||
lua_call(L, 2, 0);
|
||||
|
||||
snprintf(modfile, sizeof(modfile), "%s/gettext.lua", coref);
|
||||
if (elua_report_error(L, elua_progname, elua_io_loadfile(L, modfile)))
|
||||
{
|
||||
m->status = 1;
|
||||
return 0;
|
||||
}
|
||||
elua_state_setup_i18n(L);
|
||||
lua_call(L, 1, 0);
|
||||
|
||||
elua_io_register(L);
|
||||
lua_gc(L, LUA_GCRESTART, 0);
|
||||
|
||||
INF("elua lua state initialized");
|
||||
|
||||
/* load all the things */
|
||||
EINA_LIST_FOREACH(largs, l, data)
|
||||
{
|
||||
switch (data->type)
|
||||
{
|
||||
case ARG_CODE:
|
||||
if (!hasexec) hasexec = EINA_TRUE;
|
||||
if (elua_dostr(L, data->value, "=(command line)"))
|
||||
{
|
||||
m->status = 1;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case ARG_LIBRARY:
|
||||
if (elua_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 (optind < argc)
|
||||
{
|
||||
int quit = 0;
|
||||
if ((m->status = elua_doscript(L, argc, argv, optind, &quit))) return 0;
|
||||
if (quit) return 0;
|
||||
if (!elua_util_script_run(es, argc, argv, optind, &quit))
|
||||
{
|
||||
m->status = 1;
|
||||
return 0;
|
||||
}
|
||||
if (quit)
|
||||
return 0;
|
||||
}
|
||||
else if (!hasexec)
|
||||
else
|
||||
{
|
||||
int quit;
|
||||
if ((m->status = elua_dofile(L, NULL))) return 0;
|
||||
quit = lua_toboolean(L, -1);
|
||||
lua_pop(L, 1);
|
||||
if (quit) return 0;
|
||||
ERR("nothing to run");
|
||||
m->status = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ecore_main_loop_begin();
|
||||
|
@ -526,11 +127,22 @@ elua_main(lua_State *L)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
elua_bin_shutdown(Elua_State *es, int c)
|
||||
{
|
||||
INF("elua shutdown");
|
||||
if (es) elua_state_free(es);
|
||||
if (_el_log_domain != EINA_LOG_DOMAIN_GLOBAL)
|
||||
eina_log_domain_unregister(_el_log_domain);
|
||||
elua_shutdown();
|
||||
exit(c);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
struct Main_Data m;
|
||||
lua_State *L = NULL;
|
||||
Elua_State *es = NULL;
|
||||
|
||||
#ifdef ENABLE_NLS
|
||||
setlocale(LC_ALL, "");
|
||||
|
@ -550,21 +162,20 @@ main(int argc, char **argv)
|
|||
|
||||
INF("elua logging initialized: %d", _el_log_domain);
|
||||
|
||||
if (!(L = luaL_newstate()))
|
||||
if (!(es = elua_state_new((argv[0] && argv[0][0]) ? argv[0] : "elua")))
|
||||
{
|
||||
ERR("could not initialize elua state.");
|
||||
elua_bin_shutdown(L, 1);
|
||||
elua_bin_shutdown(es, 1);
|
||||
}
|
||||
|
||||
elua_state = L;
|
||||
|
||||
INF("elua lua state created");
|
||||
|
||||
m.es = es;
|
||||
m.argc = argc;
|
||||
m.argv = argv;
|
||||
m.status = 0;
|
||||
|
||||
elua_bin_shutdown(L, !!(lua_cpcall(L, elua_main, &m) || m.status));
|
||||
elua_bin_shutdown(es, !!(lua_cpcall(elua_state_lua_state_get(es), elua_main, &m) || m.status));
|
||||
|
||||
return 0; /* never gets here */
|
||||
}
|
||||
|
|
|
@ -52,22 +52,405 @@ extern "C" {
|
|||
# include <config.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @page elua_main Elua library (BETA)
|
||||
*
|
||||
* @date 2015 (created)
|
||||
*
|
||||
* @section toc Table of Contents
|
||||
*
|
||||
* @li @ref elua_main_intro
|
||||
* @li @ref elua_main_compiling
|
||||
* @li @ref elua_main_next_steps
|
||||
*
|
||||
* @section elua_main_intro Introduction
|
||||
*
|
||||
* The Elua library provides all necessary infrastructure required to set up
|
||||
* a fully functional Lua state able of running Elua scripts. This is provided
|
||||
* as a library in order to encourage reuse from different libraries and apps.
|
||||
*
|
||||
* @section elua_main_compiling How to compile
|
||||
*
|
||||
* As Elua is a library, compiling is very simple.
|
||||
*
|
||||
* Compiling C or C++ files into object files:
|
||||
*
|
||||
* @verbatim
|
||||
gcc -c -o main.o main.c `pkg-config --cflags elua`
|
||||
@endverbatim
|
||||
*
|
||||
* Linking object files into a binary executable:
|
||||
*
|
||||
* @verbatim
|
||||
gcc -o my_application main.o `pkg-config --libs elua`
|
||||
@endverbatim
|
||||
*
|
||||
* See @ref pkgconfig
|
||||
*
|
||||
* @section elua_main_next_steps Next Steps
|
||||
*
|
||||
* There is a comperehensive API reference available that should get you up
|
||||
* and running.
|
||||
*
|
||||
* @addtogroup Elua
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifdef EFL_BETA_API_SUPPORT
|
||||
|
||||
#include <Eina.h>
|
||||
|
||||
#include <lua.h>
|
||||
#include <lualib.h>
|
||||
#include <lauxlib.h>
|
||||
|
||||
/** Opaque Elua state
|
||||
*
|
||||
* @ingroup Elua
|
||||
*/
|
||||
typedef struct _Elua_State Elua_State;
|
||||
|
||||
/**
|
||||
* @brief Initialize the Elua library.
|
||||
*
|
||||
* This initializes the Elua library for usage. It maintains an internal
|
||||
* counter so that multiple calls will only increment/decrement correctly.
|
||||
*
|
||||
* @see elua_shutdown
|
||||
*
|
||||
* @ingroup Elua
|
||||
*/
|
||||
EAPI int elua_init(void);
|
||||
|
||||
/**
|
||||
* @brief Shutdown the Elua library.
|
||||
*
|
||||
* Depending on the internal initialization counter, this either decrements
|
||||
* or completely shuts down the Elua library. In any case, call this once for
|
||||
* each init call.
|
||||
*
|
||||
* @see elua_init
|
||||
*
|
||||
* @ingroup Elua
|
||||
*/
|
||||
EAPI int elua_shutdown(void);
|
||||
|
||||
EAPI int elua_report_error(lua_State *L, const char *pname, int status);
|
||||
/**
|
||||
* @brief Create a new Elua state.
|
||||
*
|
||||
* This creates a new Elua state. An Elua state is externally opaque, but
|
||||
* it contains a LuaJIT state as well as some additional information that
|
||||
* is mostly initialized by other APIs.
|
||||
*
|
||||
* @param[in] progname The program name that holds the Elua state. This will
|
||||
* be used for stuff like error reporting. Typically the same as the binary
|
||||
* name of the application (argv[0]).
|
||||
* @return A new Elua state or NULL.
|
||||
*
|
||||
* @ingroup Elua
|
||||
*/
|
||||
EAPI Elua_State *elua_state_new(const char *progname);
|
||||
|
||||
EAPI void elua_state_setup_i18n(lua_State *L);
|
||||
/**
|
||||
* @brief Retrieve an Elua state from a Lua state.
|
||||
*
|
||||
* This doesn't create a new Elua state. Instead it just retrieves an existing
|
||||
* Elua state given a Lua state. If no Elua state could be found (for example
|
||||
* when the Lua state was created independently of Elua), this function returns
|
||||
* NULL.
|
||||
*
|
||||
* @param[in] L The Lua state.
|
||||
* @return An Elua state or NULL.
|
||||
*
|
||||
* @ingroup Elua
|
||||
*/
|
||||
EAPI Elua_State *elua_state_from_lua_state_get(lua_State *L);
|
||||
|
||||
EAPI int elua_io_popen(lua_State *L);
|
||||
EAPI int elua_io_loadfile(lua_State *L, const char *fname);
|
||||
EAPI void elua_io_register(lua_State *L);
|
||||
/**
|
||||
* @brief Destroy an Elua state.
|
||||
*
|
||||
* Given an Elua state, this destroys its internal Lua state as well as all
|
||||
* other data its holding and then frees the Elua state itself.
|
||||
*
|
||||
* @param[in] es The Elua state.
|
||||
*
|
||||
* @ingroup Elua
|
||||
*/
|
||||
EAPI void elua_state_free(Elua_State *es);
|
||||
|
||||
/**
|
||||
* @brief Set the Elua directory paths.
|
||||
*
|
||||
* Every Elua state needs three paths - the core script path, the module
|
||||
* path and the apps path. The core path refers to from where core scripts
|
||||
* will be loaded (such as the module system), the module path refers to from
|
||||
* where extra modules will be loaded and the apps path refers to from where
|
||||
* Elua applications will be loaded (this is not a module path).
|
||||
*
|
||||
* If you provide NULL for any path, it will not be set. This allows you to
|
||||
* split the setting into multiple calls. By the time of state use all need
|
||||
* to be set.
|
||||
*
|
||||
* @param[in] es The Elua state.
|
||||
* @param[in] core The core path.
|
||||
* @param[in] mods The modules path.
|
||||
* @param[in] apps The apps path.
|
||||
*
|
||||
* @see elua_state_core_dir_get
|
||||
* @see elua_state_mod_dir_get
|
||||
* @see elua_state_apps_dir_get
|
||||
*
|
||||
* @ingroup Elua
|
||||
*/
|
||||
EAPI void elua_state_dirs_set(Elua_State *es, const char *core,
|
||||
const char *mods, const char *apps);
|
||||
|
||||
/**
|
||||
* @brief Fill the currently unset Elua dirs.
|
||||
*
|
||||
* This checks if any of the three main paths are unset and tries to fill
|
||||
* them from the environment. It first tries environment variables to fill
|
||||
* them (ELUA_CORE_DIR, ELUA_MODULES_DIR, ELUA_APPS_DIR) unless the ignore_env
|
||||
* param is EINA_TRUE. If it is (or if the environment vars weren't set right)
|
||||
* it uses eina prefix of the library to determine the paths. In that case
|
||||
* they will expand to DATADIR/core, DATADIR/modules and DATADIR/apps, where
|
||||
* DATADIR is typically something like /usr/share/elua.
|
||||
*
|
||||
* @param[in] es The Elua state.
|
||||
* @param[in] ignore_env If set to EINA_TRUE, this ignores the env vars.
|
||||
*
|
||||
* @ingroup Elua
|
||||
*/
|
||||
EAPI void elua_state_dirs_fill(Elua_State *es, Eina_Bool ignore_env);
|
||||
|
||||
/**
|
||||
* @brief Retrieve the Elua core dir.
|
||||
*
|
||||
* @param[in] es The Elua state.
|
||||
* @return The path.
|
||||
*
|
||||
* @ingroup Elua
|
||||
*/
|
||||
EAPI Eina_Stringshare *elua_state_core_dir_get(const Elua_State *es);
|
||||
|
||||
/**
|
||||
* @brief Retrieve the Elua module dir.
|
||||
*
|
||||
* @param[in] es The Elua state.
|
||||
* @return The path.
|
||||
*
|
||||
* @ingroup Elua
|
||||
*/
|
||||
EAPI Eina_Stringshare *elua_state_mod_dir_get(const Elua_State *es);
|
||||
|
||||
/**
|
||||
* @brief Retrieve the Elua apps dir.
|
||||
*
|
||||
* @param[in] es The Elua state.
|
||||
* @return The path.
|
||||
*
|
||||
* @ingroup Elua
|
||||
*/
|
||||
EAPI Eina_Stringshare *elua_state_apps_dir_get(const Elua_State *es);
|
||||
|
||||
/**
|
||||
* @brief Retrieve the prog name set on state creation.
|
||||
*
|
||||
* @param[in] es The Elua state.
|
||||
* @return The name.
|
||||
*
|
||||
* @ingroup Elua
|
||||
*/
|
||||
EAPI Eina_Stringshare *elua_state_prog_name_get(const Elua_State *es);
|
||||
|
||||
/**
|
||||
* @brief Add another path to look up modules in to the state.
|
||||
*
|
||||
* @param[in] es The Elua state.
|
||||
*
|
||||
* @ingroup Elua
|
||||
*/
|
||||
EAPI void elua_state_include_path_add(Elua_State *es, const char *path);
|
||||
|
||||
/**
|
||||
* @brief Push the Elua "require" function onto the Lua stack.
|
||||
*
|
||||
* @param[in] es The Elua state.
|
||||
* @return EINA_TRUE if the push was successful, EINA_FALSE otherwise.
|
||||
*
|
||||
* @ingroup Elua
|
||||
*/
|
||||
EAPI Eina_Bool elua_state_require_ref_push(Elua_State *es);
|
||||
|
||||
/**
|
||||
* @brief Push the Elua app loader function onto the Lua stack.
|
||||
*
|
||||
* @param[in] es The Elua state.
|
||||
* @return EINA_TRUE if the push was successful, EINA_FALSE otherwise.
|
||||
*
|
||||
* @ingroup Elua
|
||||
*/
|
||||
EAPI Eina_Bool elua_state_appload_ref_push(Elua_State *es);
|
||||
|
||||
/**
|
||||
* @brief Retrieve the Lua state from an Elua state.
|
||||
*
|
||||
* This function retrieves the Lua state from a valid Elua state. As an
|
||||
* Elua state is always initialized, this will return a valid state, unless
|
||||
* the given Elua state is NULL, in which case it will also return NULL.
|
||||
*
|
||||
* @param[in] es The Elua state.
|
||||
* @return The Lua state or NULL.
|
||||
*
|
||||
* @ingroup Elua
|
||||
*/
|
||||
EAPI lua_State *elua_state_lua_state_get(const Elua_State *es);
|
||||
|
||||
/**
|
||||
* @brief Set up the Elua state.
|
||||
*
|
||||
* This API function sets up 3 things, module system, i18n and I/O. After that
|
||||
* it requires all modules not yet required (i.e. those queued in before the
|
||||
* state was fully initialized).
|
||||
*
|
||||
* This function sets up correct i18n for an Elua state. That means loading
|
||||
* the gettext bindings and making Lua aware of them. This also works when
|
||||
* i18n support is disabled at compilation time, so you can just call it
|
||||
* unconditionally.
|
||||
*
|
||||
* This also loads the Elua module system and makes Lua aware of it. It also
|
||||
* registers the Elua C utility library module.
|
||||
*
|
||||
* Finally, Elua provides its own loadfile based around mmap to replace the
|
||||
* less efficient Lua version. This function takes care of the setup.
|
||||
*
|
||||
* @param[in] es The Elua state.
|
||||
* @return EINA_TRUE on success, EINA_FALSE on failure.
|
||||
*
|
||||
* @ingroup Elua
|
||||
*/
|
||||
EAPI Eina_Bool elua_state_setup(Elua_State *es);
|
||||
|
||||
/**
|
||||
* @brief Loads a file using Elua's own mmap-based IO.
|
||||
*
|
||||
* This function behaves identically to luaL_loadfile when it comes to
|
||||
* semantics. The loaded file remains on the Lua stack. If the input
|
||||
* state is NULL, the return value is -1 and nothing is left on the stack.
|
||||
* On any different error, the error object is left on the stack and this
|
||||
* returns a value larger than zero (LUA_ERR*). On success, zero is returned.
|
||||
*
|
||||
* @param[in] es The Elua state.
|
||||
* @param[in] fname The file name.
|
||||
* @return 0 for no errors, a non-zero value for errors (-1 for NULL es).
|
||||
*
|
||||
* @ingroup Elua
|
||||
*/
|
||||
EAPI int elua_io_loadfile(const Elua_State *es, const char *fname);
|
||||
|
||||
/**
|
||||
* @brief Requires a module.
|
||||
*
|
||||
* Requires a Lua module. Leaves the Lua stack clean.
|
||||
*
|
||||
* @param[in] es The Elua state.
|
||||
* @param[in] libname The library name.
|
||||
* @return EINA_TRUE on success, EINA_FALSE on failure.
|
||||
*
|
||||
* @ingroup Elua
|
||||
*/
|
||||
EAPI Eina_Bool elua_util_require(Elua_State *es, const char *libname);
|
||||
|
||||
/**
|
||||
* @brief Runs a file.
|
||||
*
|
||||
* Runs a file. Uses the Elua mmapped file IO to load the file.
|
||||
*
|
||||
* @param[in] es The Elua state.
|
||||
* @param[in] fname The file name.
|
||||
* @return EINA_TRUE on success, EINA_FALSE on failure.
|
||||
*
|
||||
* @ingroup Elua
|
||||
*/
|
||||
EAPI Eina_Bool elua_util_file_run(Elua_State *es, const char *fname);
|
||||
|
||||
/**
|
||||
* @brief Runs a string.
|
||||
*
|
||||
* Runs a string.
|
||||
*
|
||||
* @param[in] es The Elua state.
|
||||
* @param[in] chunk The string to run.
|
||||
* @param[in] chname The chunk name to use for traceback/debug.
|
||||
* @return EINA_TRUE on success, EINA_FALSE on failure.
|
||||
*
|
||||
* @ingroup Elua
|
||||
*/
|
||||
EAPI Eina_Bool elua_util_string_run(Elua_State *es, const char *chunk,
|
||||
const char *chname);
|
||||
|
||||
/**
|
||||
* @brief Loads an application.
|
||||
*
|
||||
* This loads an app, respecting the app path set on state initialization.
|
||||
* Actually runs the app. If the input state is NULL, the return value is -1
|
||||
* nd nothing is left on the stack. On any different error, the error object
|
||||
* is left on the stack and this returns 1. On success, zero is returned
|
||||
* (and the return value from the app is left on the stack).
|
||||
*
|
||||
* @param[in] es The Elua state.
|
||||
* @param[in] appname The application name.
|
||||
* @return 0 for no errors, 1 on errors, -1 on null input.
|
||||
*
|
||||
* @ingroup Elua
|
||||
*/
|
||||
EAPI int elua_util_app_load(Elua_State *es, const char *appname);
|
||||
|
||||
/**
|
||||
* @brief Runs a script.
|
||||
*
|
||||
* This is a more complicated function that runs a script. It's a combination
|
||||
* of the previously mentioned util functions. It takes argc and argv, which
|
||||
* are typically given to the program, and an index of the first positional
|
||||
* arg in argv (i.e. not options). The value on this index is then used as
|
||||
* the potential name.
|
||||
*
|
||||
* If this name is either a dash or empty, the script is loaded from stdin.
|
||||
* If it's a value and a file with this name exists, the script is loaded from
|
||||
* the file. Otherwise, the name is treated to be an application name, and
|
||||
* is loaded from the application path.
|
||||
*
|
||||
* If all succeeds, this is then run, and a quit value is written into the
|
||||
* quit arg; if it's true (1), it means the app wants to exit immediately.
|
||||
* If it's false (0), it means the app likely wants to execute a main loop.
|
||||
*
|
||||
* @param[in] es The Elua state.
|
||||
* @param[in] argc The argument count.
|
||||
* @param[in] argv The arguments.
|
||||
* @param[in] n The index of the first positional argt.
|
||||
* @param[out] quit Whether to quit or run a main loop.
|
||||
* @return EINA_TRUE on success, EINA_FALSE on failure.
|
||||
*
|
||||
* @ingroup Elua
|
||||
*/
|
||||
EAPI Eina_Bool elua_util_script_run(Elua_State *es, int argc, char **argv,
|
||||
int n, int *quit);
|
||||
|
||||
/**
|
||||
* @brief Reports an error using Eina logging.
|
||||
*
|
||||
* If the given status is 0, this function just returns it. Otherwise, it takes
|
||||
* the topmost item on the Lua stack, converts it to string (if it cannot be
|
||||
* converted, a "(non-string error)" placeholder is used) and logs it out
|
||||
* as an error, together with the program name set on Elua state init.
|
||||
*
|
||||
* @param[in] es The Elua state.
|
||||
* @param[in] status The status code.
|
||||
* @return The status code.
|
||||
*
|
||||
* @ingroup Elua
|
||||
*/
|
||||
EAPI int elua_util_error_report(const Elua_State *es, int status);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -150,13 +150,16 @@ getf_map(lua_State *L EINA_UNUSED, void *ud, size_t *size)
|
|||
}
|
||||
|
||||
EAPI int
|
||||
elua_io_loadfile(lua_State *L, const char *fname)
|
||||
elua_io_loadfile(const Elua_State *es, const char *fname)
|
||||
{
|
||||
Map_Stream s;
|
||||
int status;
|
||||
Eina_File *f;
|
||||
const char *chname;
|
||||
Eina_Bool bcache = EINA_FALSE;
|
||||
lua_State *L;
|
||||
if (!es || !es->luastate) return -1;
|
||||
L = es->luastate;
|
||||
if (!fname)
|
||||
{
|
||||
return elua_loadstdin(L);
|
||||
|
@ -187,8 +190,9 @@ elua_io_loadfile(lua_State *L, const char *fname)
|
|||
static int
|
||||
loadfile(lua_State *L)
|
||||
{
|
||||
Elua_State *es = elua_state_from_lua_state_get(L);
|
||||
const char *fname = luaL_optstring(L, 1, NULL);
|
||||
int status = elua_io_loadfile(L, fname),
|
||||
int status = elua_io_loadfile(es, fname),
|
||||
hasenv = (lua_gettop(L) >= 3);
|
||||
if (!status)
|
||||
{
|
||||
|
@ -204,9 +208,11 @@ loadfile(lua_State *L)
|
|||
return 2;
|
||||
}
|
||||
|
||||
EAPI void
|
||||
elua_io_register(lua_State *L)
|
||||
Eina_Bool
|
||||
_elua_state_io_setup(const Elua_State *es)
|
||||
{
|
||||
lua_pushcfunction(L, loadfile);
|
||||
lua_setglobal(L, "loadfile");
|
||||
EINA_SAFETY_ON_FALSE_RETURN_VAL(es && es->luastate, EINA_FALSE);
|
||||
lua_pushcfunction(es->luastate, loadfile);
|
||||
lua_setglobal(es->luastate, "loadfile");
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
|
|
@ -62,22 +62,172 @@ elua_shutdown(void)
|
|||
return _elua_init_counter;
|
||||
}
|
||||
|
||||
static void
|
||||
_elua_errmsg(const char *pname, const char *msg)
|
||||
EAPI Elua_State *
|
||||
elua_state_new(const char *progname)
|
||||
{
|
||||
ERR("%s%s%s", pname ? pname : "", pname ? ": " : "", msg);
|
||||
Elua_State *ret = NULL;
|
||||
lua_State *L = luaL_newstate();
|
||||
if (!L)
|
||||
return NULL;
|
||||
ret = calloc(1, sizeof(Elua_State));
|
||||
ret->luastate = L;
|
||||
if (progname) ret->progname = eina_stringshare_add(progname);
|
||||
luaL_openlibs(L);
|
||||
lua_pushlightuserdata(L, ret);
|
||||
lua_setfield(L, LUA_REGISTRYINDEX, "elua_ptr");
|
||||
return ret;
|
||||
}
|
||||
|
||||
EAPI int
|
||||
elua_report_error(lua_State *L, const char *pname, int status)
|
||||
EAPI void
|
||||
elua_state_free(Elua_State *es)
|
||||
{
|
||||
if (status && !lua_isnil(L, -1))
|
||||
void *data;
|
||||
if (!es) return;
|
||||
if (es->luastate)
|
||||
{
|
||||
const char *msg = lua_tostring(L, -1);
|
||||
_elua_errmsg(pname, msg ? msg : "(non-string error)");
|
||||
lua_pop(L, 1);
|
||||
EINA_LIST_FREE(es->cmods, data)
|
||||
{
|
||||
lua_rawgeti(es->luastate, LUA_REGISTRYINDEX, (size_t)data);
|
||||
lua_call(es->luastate, 0, 0);
|
||||
}
|
||||
lua_close(es->luastate);
|
||||
}
|
||||
return status;
|
||||
else if (es->cmods)
|
||||
eina_list_free(es->cmods);
|
||||
EINA_LIST_FREE(es->lmods, data)
|
||||
eina_stringshare_del(data);
|
||||
EINA_LIST_FREE(es->lincs, data)
|
||||
eina_stringshare_del(data);
|
||||
eina_stringshare_del(es->progname);
|
||||
eina_stringshare_del(es->coredir);
|
||||
eina_stringshare_del(es->moddir);
|
||||
eina_stringshare_del(es->appsdir);
|
||||
free(es);
|
||||
}
|
||||
|
||||
EAPI void
|
||||
elua_state_dirs_set(Elua_State *es, const char *core, const char *mods,
|
||||
const char *apps)
|
||||
{
|
||||
EINA_SAFETY_ON_NULL_RETURN(es);
|
||||
if (core) es->coredir = eina_stringshare_add(core);
|
||||
if (mods) es->moddir = eina_stringshare_add(mods);
|
||||
if (apps) es->appsdir = eina_stringshare_add(apps);
|
||||
}
|
||||
|
||||
EAPI void
|
||||
elua_state_dirs_fill(Elua_State *es, Eina_Bool ignore_env)
|
||||
{
|
||||
const char *coredir = NULL, *moddir = NULL, *appsdir = NULL;
|
||||
char coredirbuf[PATH_MAX], moddirbuf[PATH_MAX], appsdirbuf[PATH_MAX];
|
||||
EINA_SAFETY_ON_NULL_RETURN(es);
|
||||
if (!(coredir = es->coredir))
|
||||
{
|
||||
if (ignore_env || !(coredir = getenv("ELUA_CORE_DIR")) || !coredir[0])
|
||||
{
|
||||
coredir = coredirbuf;
|
||||
snprintf(coredirbuf, sizeof(coredirbuf), "%s/core",
|
||||
eina_prefix_data_get(_elua_pfx));
|
||||
}
|
||||
if (coredir) es->coredir = eina_stringshare_add(coredir);
|
||||
}
|
||||
if (!(moddir = es->moddir))
|
||||
{
|
||||
if (ignore_env || !(moddir = getenv("ELUA_MODULES_DIR")) || !moddir[0])
|
||||
{
|
||||
moddir = moddirbuf;
|
||||
snprintf(moddirbuf, sizeof(moddirbuf), "%s/modules",
|
||||
eina_prefix_data_get(_elua_pfx));
|
||||
}
|
||||
if (moddir) es->moddir = eina_stringshare_add(moddir);
|
||||
}
|
||||
if (!(appsdir = es->appsdir))
|
||||
{
|
||||
if (ignore_env || !(appsdir = getenv("ELUA_APPS_DIR")) || !appsdir[0])
|
||||
{
|
||||
appsdir = appsdirbuf;
|
||||
snprintf(appsdirbuf, sizeof(appsdirbuf), "%s/apps",
|
||||
eina_prefix_data_get(_elua_pfx));
|
||||
}
|
||||
if (appsdir) es->appsdir = eina_stringshare_add(appsdir);
|
||||
}
|
||||
}
|
||||
|
||||
EAPI Eina_Stringshare *
|
||||
elua_state_core_dir_get(const Elua_State *es)
|
||||
{
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(es, NULL);
|
||||
return es->coredir;
|
||||
}
|
||||
|
||||
EAPI Eina_Stringshare *
|
||||
elua_state_mod_dir_get(const Elua_State *es)
|
||||
{
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(es, NULL);
|
||||
return es->moddir;
|
||||
}
|
||||
|
||||
EAPI Eina_Stringshare *
|
||||
elua_state_apps_dir_get(const Elua_State *es)
|
||||
{
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(es, NULL);
|
||||
return es->appsdir;
|
||||
}
|
||||
|
||||
EAPI Eina_Stringshare *
|
||||
elua_state_prog_name_get(const Elua_State *es)
|
||||
{
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(es, NULL);
|
||||
return es->progname;
|
||||
}
|
||||
|
||||
EAPI void
|
||||
elua_state_include_path_add(Elua_State *es, const char *path)
|
||||
{
|
||||
EINA_SAFETY_ON_NULL_RETURN(es);
|
||||
EINA_SAFETY_ON_NULL_RETURN(path);
|
||||
EINA_SAFETY_ON_FALSE_RETURN(path[0]);
|
||||
es->lincs = eina_list_append(es->lincs, eina_stringshare_add(path));
|
||||
}
|
||||
|
||||
EAPI Eina_Bool
|
||||
elua_state_require_ref_push(Elua_State *es)
|
||||
{
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(es, EINA_FALSE);
|
||||
EINA_SAFETY_ON_FALSE_RETURN_VAL(es->requireref != LUA_REFNIL, EINA_FALSE);
|
||||
lua_rawgeti(es->luastate, LUA_REGISTRYINDEX, es->requireref);
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
EAPI Eina_Bool
|
||||
elua_state_appload_ref_push(Elua_State *es)
|
||||
{
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(es, EINA_FALSE);
|
||||
EINA_SAFETY_ON_FALSE_RETURN_VAL(es->apploadref != LUA_REFNIL, EINA_FALSE);
|
||||
lua_rawgeti(es->luastate, LUA_REGISTRYINDEX, es->apploadref);
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
EAPI lua_State *
|
||||
elua_state_lua_state_get(const Elua_State *es)
|
||||
{
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(es, NULL);
|
||||
return es->luastate;
|
||||
}
|
||||
|
||||
EAPI Elua_State *
|
||||
elua_state_from_lua_state_get(lua_State *L)
|
||||
{
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(L, NULL);
|
||||
lua_getfield(L, LUA_REGISTRYINDEX, "elua_ptr");
|
||||
if (!lua_isnil(L, -1))
|
||||
{
|
||||
void *st = lua_touserdata(L, -1);
|
||||
lua_pop(L, 1);
|
||||
return (Elua_State *)st;
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -108,26 +258,377 @@ _elua_gettext_bind_textdomain(lua_State *L)
|
|||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
_elua_get_message_language(lua_State *L)
|
||||
{
|
||||
const char *e;
|
||||
e = getenv("LANGUAGE");
|
||||
if (e && e[0]) goto success;
|
||||
e = getenv("LC_ALL");
|
||||
if (e && e[0]) goto success;
|
||||
e = getenv("LC_MESSAGES");
|
||||
if (e && e[0]) goto success;
|
||||
e = getenv("LANG");
|
||||
if (e && e[0]) goto success;
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
success:
|
||||
lua_pushstring(L, e);
|
||||
return 1;
|
||||
};
|
||||
|
||||
static int
|
||||
_elua_get_localeconv(lua_State *L)
|
||||
{
|
||||
struct lconv *lc = localeconv();
|
||||
lua_createtable(L, 0, 24);
|
||||
|
||||
#define ELUA_LCF_S(name) \
|
||||
lua_pushstring(L, lc->name); \
|
||||
lua_setfield(L, -2, #name);
|
||||
|
||||
#define ELUA_LCF_C(name) \
|
||||
lua_pushinteger(L, (lc->name == CHAR_MAX) ? -1 : (int)lc->name); \
|
||||
lua_setfield(L, -2, #name);
|
||||
|
||||
ELUA_LCF_S(decimal_point);
|
||||
ELUA_LCF_S(thousands_sep);
|
||||
ELUA_LCF_S(grouping);
|
||||
ELUA_LCF_S(int_curr_symbol);
|
||||
ELUA_LCF_S(currency_symbol);
|
||||
ELUA_LCF_S(mon_decimal_point);
|
||||
ELUA_LCF_S(mon_thousands_sep);
|
||||
ELUA_LCF_S(mon_grouping);
|
||||
ELUA_LCF_S(positive_sign);
|
||||
ELUA_LCF_S(negative_sign);
|
||||
|
||||
ELUA_LCF_C(frac_digits);
|
||||
ELUA_LCF_C(p_cs_precedes);
|
||||
ELUA_LCF_C(n_cs_precedes);
|
||||
ELUA_LCF_C(p_sep_by_space);
|
||||
ELUA_LCF_C(n_sep_by_space);
|
||||
ELUA_LCF_C(p_sign_posn);
|
||||
ELUA_LCF_C(n_sign_posn);
|
||||
ELUA_LCF_C(int_frac_digits);
|
||||
ELUA_LCF_C(int_p_cs_precedes);
|
||||
ELUA_LCF_C(int_n_cs_precedes);
|
||||
ELUA_LCF_C(int_p_sep_by_space);
|
||||
ELUA_LCF_C(int_n_sep_by_space);
|
||||
ELUA_LCF_C(int_p_sign_posn);
|
||||
ELUA_LCF_C(int_n_sign_posn);
|
||||
|
||||
#undef ELUA_LCF_S
|
||||
#undef ELUA_LCF_C
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
const luaL_reg gettextlib[] =
|
||||
{
|
||||
{ "bind_textdomain", _elua_gettext_bind_textdomain },
|
||||
{ "get_message_language", _elua_get_message_language },
|
||||
{ "get_localeconv", _elua_get_localeconv },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
EAPI void
|
||||
elua_state_setup_i18n(lua_State *L)
|
||||
static Eina_Bool
|
||||
_elua_state_i18n_setup(const Elua_State *es)
|
||||
{
|
||||
#ifdef ENABLE_NLS
|
||||
char *(*dgettextp)(const char*, const char*) = dgettext;
|
||||
char *(*dngettextp)(const char*, const char*, const char*, unsigned long)
|
||||
= dngettext;
|
||||
#endif
|
||||
lua_createtable(L, 0, 0);
|
||||
luaL_register(L, NULL, gettextlib);
|
||||
char buf[PATH_MAX];
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(es, EINA_FALSE);
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(es->coredir, EINA_FALSE);
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(es->progname, EINA_FALSE);
|
||||
snprintf(buf, sizeof(buf), "%s/gettext.lua", es->coredir);
|
||||
if (elua_util_error_report(es, elua_io_loadfile(es, buf)))
|
||||
return EINA_FALSE;
|
||||
lua_createtable(es->luastate, 0, 0);
|
||||
luaL_register(es->luastate, NULL, gettextlib);
|
||||
#ifdef ENABLE_NLS
|
||||
lua_pushlightuserdata(L, *((void**)&dgettextp));
|
||||
lua_setfield(L, -2, "dgettext");
|
||||
lua_pushlightuserdata(L, *((void**)&dngettextp));
|
||||
lua_setfield(L, -2, "dngettext");
|
||||
lua_pushlightuserdata(es->luastate, *((void**)&dgettextp));
|
||||
lua_setfield(es->luastate, -2, "dgettext");
|
||||
lua_pushlightuserdata(es->luastate, *((void**)&dngettextp));
|
||||
lua_setfield(es->luastate, -2, "dngettext");
|
||||
#endif
|
||||
lua_call(es->luastate, 1, 0);
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
int _elua_module_init(lua_State *L);
|
||||
int _elua_module_system_init(lua_State *L);
|
||||
|
||||
const luaL_reg _elua_cutillib[] =
|
||||
{
|
||||
{ "init_module", _elua_module_init },
|
||||
{ "popenv" , _elua_io_popen },
|
||||
{ NULL , NULL }
|
||||
};
|
||||
|
||||
static Eina_Bool
|
||||
_elua_state_modules_setup(const Elua_State *es)
|
||||
{
|
||||
char buf[PATH_MAX];
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(es, EINA_FALSE);
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(es->coredir, EINA_FALSE);
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(es->progname, EINA_FALSE);
|
||||
snprintf(buf, sizeof(buf), "%s/module.lua", es->coredir);
|
||||
if (elua_util_error_report(es, elua_io_loadfile(es, buf)))
|
||||
return EINA_FALSE;
|
||||
lua_pushcfunction(es->luastate, _elua_module_system_init);
|
||||
lua_createtable(es->luastate, 0, 0);
|
||||
luaL_register(es->luastate, NULL, _elua_cutillib);
|
||||
lua_call(es->luastate, 2, 0);
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
int
|
||||
_elua_module_init(lua_State *L)
|
||||
{
|
||||
Elua_State *es = elua_state_from_lua_state_get(L);
|
||||
if (!lua_isnoneornil(L, 1))
|
||||
{
|
||||
lua_pushvalue(L, 1);
|
||||
lua_call(L, 0, 0);
|
||||
}
|
||||
if (!lua_isnoneornil(L, 2))
|
||||
{
|
||||
lua_pushvalue(L, 2);
|
||||
es->cmods = eina_list_append(es->cmods,
|
||||
(void*)(size_t)luaL_ref(L, LUA_REGISTRYINDEX));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
_elua_module_system_init(lua_State *L)
|
||||
{
|
||||
Elua_State *es = elua_state_from_lua_state_get(L);
|
||||
const char *corepath = es->coredir;
|
||||
const char *modpath = es->moddir;
|
||||
const char *appspath = es->appsdir;
|
||||
Eina_Stringshare *data = NULL;
|
||||
int n = 3;
|
||||
if (!corepath || !modpath || !appspath)
|
||||
return 0;
|
||||
lua_pushvalue(L, 1);
|
||||
es->requireref = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
lua_pushvalue(L, 2);
|
||||
es->apploadref = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
lua_pushfstring(L, "%s/?.lua;", corepath);
|
||||
EINA_LIST_FREE(es->lincs, data)
|
||||
{
|
||||
lua_pushfstring(L, "%s/?.lua;", data);
|
||||
eina_stringshare_del(data);
|
||||
++n;
|
||||
}
|
||||
lua_pushfstring(L, "%s/?.eo.lua;", modpath);
|
||||
lua_pushfstring(L, "%s/?.lua;", modpath);
|
||||
lua_pushvalue(L, 3);
|
||||
lua_concat(L, n + 1);
|
||||
lua_pushfstring(L, "%s/?.lua;", appspath);
|
||||
lua_pushvalue(L, 4);
|
||||
lua_concat(L, 2);
|
||||
return 2;
|
||||
}
|
||||
|
||||
EAPI Eina_Bool
|
||||
elua_state_setup(Elua_State *es)
|
||||
{
|
||||
Eina_Stringshare *data;
|
||||
Eina_Bool failed = EINA_FALSE;
|
||||
|
||||
if (!_elua_state_modules_setup(es))
|
||||
return EINA_FALSE;
|
||||
if (!_elua_state_i18n_setup(es))
|
||||
return EINA_FALSE;
|
||||
if (!_elua_state_io_setup(es))
|
||||
return EINA_FALSE;
|
||||
|
||||
/* finally require the necessary modules */
|
||||
EINA_LIST_FREE(es->lmods, data)
|
||||
{
|
||||
if (!failed)
|
||||
{
|
||||
if (!elua_state_require_ref_push(es))
|
||||
{
|
||||
failed = EINA_TRUE;
|
||||
break;
|
||||
}
|
||||
lua_pushstring(es->luastate, data);
|
||||
if (elua_util_error_report(es, lua_pcall(es->luastate, 1, 0, 0)))
|
||||
{
|
||||
failed = EINA_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
eina_stringshare_del(data);
|
||||
}
|
||||
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
/* Utility functions - these could be written using the other APIs */
|
||||
|
||||
static int
|
||||
_elua_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
|
||||
_elua_docall(Elua_State *es, int narg, int nret)
|
||||
{
|
||||
int status;
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(es, -1);
|
||||
int bs = lua_gettop(es->luastate) - narg;
|
||||
lua_pushcfunction(es->luastate, _elua_traceback);
|
||||
lua_insert(es->luastate, bs);
|
||||
status = lua_pcall(es->luastate, narg, nret, bs);
|
||||
lua_remove(es->luastate, bs);
|
||||
if (status)
|
||||
lua_gc(es->luastate, LUA_GCCOLLECT, 0);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int
|
||||
_elua_getargs(Elua_State *es, int argc, char **argv, int n)
|
||||
{
|
||||
int i;
|
||||
int narg = argc - (n + 1);
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(es, -1);
|
||||
luaL_checkstack(es->luastate, narg + 3, "too many arguments to script");
|
||||
for (i = n + 1; i < argc; ++i)
|
||||
{
|
||||
lua_pushstring(es->luastate, argv[i]);
|
||||
}
|
||||
lua_createtable(es->luastate, narg, n + 1);
|
||||
for (i = 0; i < argc; ++i)
|
||||
{
|
||||
lua_pushstring(es->luastate, argv[i]);
|
||||
lua_rawseti(es->luastate, -2, i - n);
|
||||
}
|
||||
return narg;
|
||||
}
|
||||
|
||||
EAPI Eina_Bool
|
||||
elua_util_require(Elua_State *es, const char *libname)
|
||||
{
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(es, EINA_FALSE);
|
||||
if (!elua_state_require_ref_push(es))
|
||||
{
|
||||
/* store stuff until things are correctly set up */
|
||||
es->lmods = eina_list_append(es->lmods, eina_stringshare_add(libname));
|
||||
return 0;
|
||||
}
|
||||
lua_pushstring(es->luastate, libname);
|
||||
return !elua_util_error_report(es, lua_pcall(es->luastate, 1, 0, 0));
|
||||
}
|
||||
|
||||
EAPI Eina_Bool
|
||||
elua_util_file_run(Elua_State *es, const char *fname)
|
||||
{
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(es, EINA_FALSE);
|
||||
return !elua_util_error_report(es, elua_io_loadfile(es, fname)
|
||||
|| _elua_docall(es, 0, 1));
|
||||
}
|
||||
|
||||
EAPI Eina_Bool
|
||||
elua_util_string_run(Elua_State *es, const char *chunk, const char *chname)
|
||||
{
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(es, EINA_FALSE);
|
||||
return !elua_util_error_report(es, luaL_loadbuffer(es->luastate, chunk,
|
||||
strlen(chunk), chname)
|
||||
|| _elua_docall(es, 0, 0));
|
||||
}
|
||||
|
||||
EAPI int
|
||||
elua_util_app_load(Elua_State *es, const char *appname)
|
||||
{
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(es, -1);
|
||||
EINA_SAFETY_ON_FALSE_RETURN_VAL(elua_state_appload_ref_push(es), -1);
|
||||
lua_pushstring(es->luastate, appname);
|
||||
lua_call(es->luastate, 1, 2);
|
||||
if (lua_isnil(es->luastate, -2))
|
||||
{
|
||||
lua_remove(es->luastate, -2);
|
||||
return 1;
|
||||
}
|
||||
lua_pop(es->luastate, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
EAPI Eina_Bool
|
||||
elua_util_script_run(Elua_State *es, int argc, char **argv, int n, int *quit)
|
||||
{
|
||||
int status, narg;
|
||||
const char *fname;
|
||||
EINA_SAFETY_ON_FALSE_RETURN_VAL(n < argc, -1);
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(es, -1);
|
||||
fname = argv[n];
|
||||
narg = _elua_getargs(es, argc, argv, n);
|
||||
lua_setglobal(es->luastate, "arg");
|
||||
if (fname[0] == '-' && !fname[1]) fname = NULL;
|
||||
if (fname)
|
||||
{
|
||||
/* check if there is a file of that name */
|
||||
FILE *f = fopen(fname, "r");
|
||||
if (f)
|
||||
{
|
||||
fclose(f);
|
||||
status = elua_io_loadfile(es, fname);
|
||||
}
|
||||
else
|
||||
status = elua_util_app_load(es, fname);
|
||||
}
|
||||
else
|
||||
status = elua_io_loadfile(es, fname);
|
||||
lua_insert(es->luastate, -(narg + 1));
|
||||
if (!status)
|
||||
status = _elua_docall(es, narg, 1);
|
||||
else
|
||||
lua_pop(es->luastate, narg);
|
||||
if (!status)
|
||||
{
|
||||
*quit = lua_toboolean(es->luastate, -1);
|
||||
lua_pop(es->luastate, 1);
|
||||
}
|
||||
return !elua_util_error_report(es, status);
|
||||
}
|
||||
|
||||
static void
|
||||
_elua_errmsg(const char *pname, const char *msg)
|
||||
{
|
||||
ERR("%s%s%s", pname ? pname : "", pname ? ": " : "", msg);
|
||||
}
|
||||
|
||||
EAPI int
|
||||
elua_util_error_report(const Elua_State *es, int status)
|
||||
{
|
||||
EINA_SAFETY_ON_FALSE_RETURN_VAL(es, status);
|
||||
if (status && !lua_isnil(es->luastate, -1))
|
||||
{
|
||||
const char *msg = lua_tostring(es->luastate, -1);
|
||||
_elua_errmsg(es->progname, msg ? msg : "(non-string error)");
|
||||
lua_pop(es->luastate, 1);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
|
|
@ -5,8 +5,9 @@
|
|||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <locale.h>
|
||||
|
||||
#ifdef ENABLE_NLS
|
||||
# include <locale.h>
|
||||
# include <libintl.h>
|
||||
# define _(x) dgettext(PACKAGE, x)
|
||||
#else
|
||||
|
@ -27,6 +28,19 @@
|
|||
#include <lualib.h>
|
||||
#include <lauxlib.h>
|
||||
|
||||
struct _Elua_State
|
||||
{
|
||||
lua_State *luastate;
|
||||
Eina_Stringshare *progname;
|
||||
Eina_Stringshare *coredir;
|
||||
Eina_Stringshare *moddir;
|
||||
Eina_Stringshare *appsdir;
|
||||
Eina_List *lmods;
|
||||
Eina_List *cmods;
|
||||
Eina_List *lincs;
|
||||
int requireref, apploadref;
|
||||
};
|
||||
|
||||
extern int _elua_log_dom;
|
||||
|
||||
#define DBG(...) EINA_LOG_DOM_DBG(_elua_log_dom, __VA_ARGS__)
|
||||
|
@ -35,4 +49,7 @@ extern int _elua_log_dom;
|
|||
#define ERR(...) EINA_LOG_DOM_ERR(_elua_log_dom, __VA_ARGS__)
|
||||
#define CRT(...) EINA_LOG_DOM_CRITICAL(_elua_log_dom, __VA_ARGS__)
|
||||
|
||||
int _elua_io_popen(lua_State *L);
|
||||
Eina_Bool _elua_state_io_setup(const Elua_State *es);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -341,8 +341,8 @@ elua_newfile(lua_State *L)
|
|||
return f;
|
||||
}
|
||||
|
||||
EAPI int
|
||||
elua_io_popen(lua_State *L)
|
||||
int
|
||||
_elua_io_popen(lua_State *L)
|
||||
{
|
||||
const char *fname = luaL_checkstring(L, 1);
|
||||
const char *mode = luaL_optstring(L, 2, "r");
|
||||
|
|
|
@ -7,7 +7,6 @@ local M = {}
|
|||
local gettext = ...
|
||||
|
||||
local bind_textdomain = gettext.bind_textdomain
|
||||
local bind_textdomain_codeset = gettext.bind_textdomain_codeset
|
||||
local dgettext = gettext.dgettext
|
||||
local dngettext = gettext.dngettext
|
||||
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include<Eina.h>
|
||||
#include "Elua.h"
|
||||
#include "elua_suite.h"
|
||||
|
||||
START_TEST(elua_api)
|
||||
{
|
||||
Elua_State *st;
|
||||
lua_State *lst;
|
||||
char buf[] = "tmpXXXXXX";
|
||||
FILE *f;
|
||||
int fd;
|
||||
char *cargv[2];
|
||||
char arg1[] = "test";
|
||||
char arg2[] = "lualian";
|
||||
int quit = 0;
|
||||
cargv[0] = arg1;
|
||||
cargv[1] = arg2;
|
||||
|
||||
fail_if(!elua_init());
|
||||
|
||||
st = elua_state_new("test");
|
||||
fail_if(!st);
|
||||
|
||||
/* test env vars */
|
||||
setenv("ELUA_CORE_DIR", "foo", 1);
|
||||
setenv("ELUA_MODULES_DIR", "bar", 1);
|
||||
setenv("ELUA_APPS_DIR", "baz", 1);
|
||||
elua_state_dirs_fill(st, EINA_FALSE);
|
||||
fail_if(strcmp(elua_state_core_dir_get(st), "foo"));
|
||||
fail_if(strcmp(elua_state_mod_dir_get(st), "bar"));
|
||||
fail_if(strcmp(elua_state_apps_dir_get(st), "baz"));
|
||||
unsetenv("ELUA_CORE_DIR");
|
||||
unsetenv("ELUA_MODULES_DIR");
|
||||
unsetenv("ELUA_APPS_DIR");
|
||||
|
||||
/* now fill it properly */
|
||||
elua_state_dirs_set(st, ELUA_CORE_DIR, ELUA_MODULES_DIR, ELUA_APPS_DIR);
|
||||
fail_if(strcmp(elua_state_core_dir_get(st), ELUA_CORE_DIR));
|
||||
fail_if(strcmp(elua_state_mod_dir_get(st), ELUA_MODULES_DIR));
|
||||
fail_if(strcmp(elua_state_apps_dir_get(st), ELUA_APPS_DIR));
|
||||
|
||||
/* needed for later setup, but untestable alone */
|
||||
elua_state_include_path_add(st, ELUA_BINDINGS_DIR);
|
||||
|
||||
lst = elua_state_lua_state_get(st);
|
||||
fail_if(!lst);
|
||||
|
||||
fail_if(elua_state_from_lua_state_get(lst) != st);
|
||||
|
||||
fail_if(strcmp(elua_state_prog_name_get(st), "test"));
|
||||
|
||||
fail_if(!elua_state_setup(st));
|
||||
|
||||
fail_if(!elua_state_require_ref_push(st));
|
||||
fail_if(lua_type(lst, -1) != LUA_TFUNCTION);
|
||||
lua_pop(lst, 1);
|
||||
|
||||
fail_if(!elua_state_appload_ref_push(st));
|
||||
fail_if(lua_type(lst, -1) != LUA_TFUNCTION);
|
||||
lua_pop(lst, 1);
|
||||
|
||||
fail_if(!elua_util_require(st, "util"));
|
||||
fail_if(!elua_util_string_run(st, "return 1337", "foo"));
|
||||
fail_if(elua_util_string_run(st, "foo bar", "foo")); /* invalid code */
|
||||
fail_if(elua_util_app_load(st, "lualian"));
|
||||
fail_if(lua_type(lst, -1) != LUA_TFUNCTION);
|
||||
lua_pop(lst, 1);
|
||||
fail_if(!elua_util_app_load(st, "non_existent_app"));
|
||||
fail_if(lua_type(lst, -1) != LUA_TSTRING);
|
||||
lua_pop(lst, 1);
|
||||
fail_if(elua_io_loadfile(st, ELUA_CORE_DIR "/util.lua"));
|
||||
fail_if(lua_type(lst, -1) != LUA_TFUNCTION);
|
||||
lua_pop(lst, 1);
|
||||
fail_if(!elua_io_loadfile(st, ELUA_CORE_DIR "/non_existent_file.lua"));
|
||||
fail_if(lua_type(lst, -1) != LUA_TSTRING);
|
||||
lua_pop(lst, 1);
|
||||
|
||||
fd = mkstemp(buf);
|
||||
fail_if(fd < 0);
|
||||
f = fdopen(fd, "w");
|
||||
fail_if(!f);
|
||||
fprintf(f, "return 5\n");
|
||||
fclose(f);
|
||||
fail_if(!elua_util_file_run(st, buf));
|
||||
fail_if(lua_tointeger(lst, -1) != 5);
|
||||
lua_pop(lst, 1);
|
||||
fail_if(remove(buf));
|
||||
|
||||
/* halfassed testing here, but not possible otherwise */
|
||||
fail_if(elua_util_error_report(st, 0));
|
||||
lua_pushliteral(lst, "msg");
|
||||
fail_if(!elua_util_error_report(st, 5));
|
||||
fail_if(lua_gettop(lst) > 0);
|
||||
|
||||
fail_if(!elua_util_script_run(st, 2, cargv, 1, &quit));
|
||||
fail_if(quit != 1);
|
||||
|
||||
f = fopen(buf, "w");
|
||||
fail_if(!f);
|
||||
fprintf(f, "return false");
|
||||
fclose(f);
|
||||
cargv[1] = buf;
|
||||
fail_if(!elua_util_script_run(st, 2, cargv, 1, &quit));
|
||||
fail_if(quit != 0);
|
||||
fail_if(remove(buf));
|
||||
|
||||
elua_state_free(st);
|
||||
|
||||
elua_shutdown();
|
||||
}
|
||||
END_TEST
|
||||
|
||||
void elua_lib_test(TCase *tc)
|
||||
{
|
||||
tcase_add_test(tc, elua_api);
|
||||
}
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include<Eina.h>
|
||||
#include "elua_suite.h"
|
||||
|
||||
typedef struct _Elua_Test_Case Elua_Test_Case;
|
||||
|
||||
struct _Elua_Test_Case
|
||||
{
|
||||
const char *test_case;
|
||||
void (*build)(TCase *tc);
|
||||
};
|
||||
|
||||
static const Elua_Test_Case etc[] = {
|
||||
{ "Elua Library", elua_lib_test},
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static void
|
||||
_list_tests(void)
|
||||
{
|
||||
const Elua_Test_Case *itr;
|
||||
|
||||
itr = etc;
|
||||
fputs("Available Test Cases:\n", stderr);
|
||||
for (; itr->test_case; itr++)
|
||||
fprintf(stderr, "\t%s\n", itr->test_case);
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_use_test(int argc, const char **argv, const char *test_case)
|
||||
{
|
||||
if (argc < 1)
|
||||
return 1;
|
||||
|
||||
for (; argc > 0; argc--, argv++)
|
||||
if (strcmp(test_case, *argv) == 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Suite *
|
||||
elua_suite_build(int argc, const char **argv)
|
||||
{
|
||||
TCase *tc;
|
||||
Suite *s;
|
||||
int i;
|
||||
|
||||
s = suite_create("Elua");
|
||||
|
||||
for (i = 0; etc[i].test_case; ++i)
|
||||
{
|
||||
if (!_use_test(argc, argv, etc[i].test_case)) continue;
|
||||
tc = tcase_create(etc[i].test_case);
|
||||
|
||||
etc[i].build(tc);
|
||||
|
||||
suite_add_tcase(s, tc);
|
||||
#ifndef _WIN32
|
||||
tcase_set_timeout(tc, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
Suite *s;
|
||||
SRunner *sr;
|
||||
int i, failed_count;
|
||||
setenv("CK_FORK", "no", 0);
|
||||
|
||||
for (i = 1; i < argc; i++)
|
||||
if ((strcmp(argv[i], "-h" ) == 0) ||
|
||||
(strcmp(argv[i], "--help") == 0))
|
||||
{
|
||||
fprintf(stderr, "Usage:\n\t%s [test_case1 .. [test_caseN]]\n",
|
||||
argv[0]);
|
||||
_list_tests();
|
||||
return 0;
|
||||
}
|
||||
else if ((strcmp(argv[i], "-l" ) == 0) ||
|
||||
(strcmp(argv[i], "--list") == 0))
|
||||
{
|
||||
_list_tests();
|
||||
return 0;
|
||||
}
|
||||
|
||||
putenv("EFL_RUN_IN_TREE=1");
|
||||
|
||||
s = elua_suite_build(argc - 1, (const char **)argv + 1);
|
||||
sr = srunner_create(s);
|
||||
|
||||
srunner_set_xml(sr, TESTS_BUILD_DIR "/check-results.xml");
|
||||
|
||||
srunner_run_all(sr, CK_ENV);
|
||||
failed_count = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
|
||||
return (failed_count == 0) ? 0 : 255;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef _ELUA_SUITE_H
|
||||
#define _ELUA_SUITE_H
|
||||
|
||||
#include <check.h>
|
||||
|
||||
void elua_lib_test(TCase *tc);
|
||||
|
||||
#endif /* _ELUA_SUITE_H */
|
||||
|
Loading…
Reference in New Issue