summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Kolesa <d.kolesa@osg.samsung.com>2015-05-06 15:05:55 +0100
committerDaniel Kolesa <d.kolesa@osg.samsung.com>2015-05-06 15:05:55 +0100
commitc77b91529b6402709f98eaebdcbc2a1a299c9c7b (patch)
tree7265ec2881bc3469dd2ca9026974520852a531a4
parent929c8687f262f7997da9e3efcf6a5b37a821a67f (diff)
parent7cc295ae9a539f2b0e98786d6a6ddb8176dcbd49 (diff)
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.
-rw-r--r--src/Makefile_Elua.am44
-rw-r--r--src/Makefile_Elua_Helper.am4
-rw-r--r--src/bin/elua/main.c529
-rw-r--r--src/lib/elua/Elua.h393
-rw-r--r--src/lib/elua/cache.c18
-rw-r--r--src/lib/elua/elua.c535
-rw-r--r--src/lib/elua/elua_private.h19
-rw-r--r--src/lib/elua/io.c4
-rw-r--r--src/scripts/elua/core/gettext.lua1
-rw-r--r--src/tests/elua/elua_lib.c124
-rw-r--r--src/tests/elua/elua_suite.c108
-rw-r--r--src/tests/elua/elua_suite.h9
12 files changed, 1291 insertions, 497 deletions
diff --git a/src/Makefile_Elua.am b/src/Makefile_Elua.am
index a6609d2699..a053053321 100644
--- a/src/Makefile_Elua.am
+++ b/src/Makefile_Elua.am
@@ -14,7 +14,6 @@ lib_elua_libelua_la_SOURCES = \
14 14
15lib_elua_libelua_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl @ELUA_CFLAGS@ \ 15lib_elua_libelua_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl @ELUA_CFLAGS@ \
16 -DLOCALE_DIR=\"@LOCALE_DIR@\" \ 16 -DLOCALE_DIR=\"@LOCALE_DIR@\" \
17 -DPACKAGE_SRC_DIR=\"$(abs_top_srcdir)\" \
18 -DPACKAGE_BIN_DIR=\"$(bindir)\" \ 17 -DPACKAGE_BIN_DIR=\"$(bindir)\" \
19 -DPACKAGE_DATA_DIR=\"$(datadir)/elua\" 18 -DPACKAGE_DATA_DIR=\"$(datadir)/elua\"
20 19
@@ -32,10 +31,7 @@ bin_elua_elua_SOURCES = \
32 bin/elua/main.c 31 bin/elua/main.c
33 32
34bin_elua_elua_CPPFLAGS = -I$(top_builddir)/src/lib/efl @ELUA_CFLAGS@ \ 33bin_elua_elua_CPPFLAGS = -I$(top_builddir)/src/lib/efl @ELUA_CFLAGS@ \
35 -DLOCALE_DIR=\"@LOCALE_DIR@\" \ 34 -DLOCALE_DIR=\"@LOCALE_DIR@\"
36 -DPACKAGE_SRC_DIR=\"$(abs_top_srcdir)\" \
37 -DPACKAGE_BIN_DIR=\"$(bindir)\" \
38 -DPACKAGE_DATA_DIR=\"$(datadir)/elua\"
39 35
40if HAVE_OSX 36if HAVE_OSX
41if HAVE_X86_64 37if HAVE_X86_64
@@ -50,6 +46,11 @@ bin_elua_elua_LDADD = @ELUA_LIBS@ @USE_ELUA_LIBS@
50endif 46endif
51bin_elua_elua_DEPENDENCIES = @ELUA_INTERNAL_LIBS@ lib/elua/libelua.la 47bin_elua_elua_DEPENDENCIES = @ELUA_INTERNAL_LIBS@ lib/elua/libelua.la
52 48
49ELUA_BINDINGS_DIR = $(abs_top_srcdir)/src/bindings/luajit
50ELUA_CORE_DIR = $(abs_top_srcdir)/src/scripts/elua/core
51ELUA_MODULES_DIR = $(abs_top_srcdir)/src/scripts/elua/modules
52ELUA_APPS_DIR = $(abs_top_srcdir)/src/scripts/elua/apps
53
53### Helper for other modules using Elua 54### Helper for other modules using Elua
54include Makefile_Elua_Helper.am 55include Makefile_Elua_Helper.am
55 56
@@ -106,4 +107,37 @@ eluacore_DATA = \
106 107
107EXTRA_DIST += $(eluacore_DATA) 108EXTRA_DIST += $(eluacore_DATA)
108 109
110if EFL_ENABLE_TESTS
111
112check_PROGRAMS += tests/elua/elua_suite
113
114tests_elua_elua_suite_SOURCES = \
115tests/elua/elua_lib.c \
116tests/elua/elua_suite.c \
117tests/elua/elua_suite.h
118
119tests_elua_elua_suite_CPPFLAGS = -I$(top_builddir)/src/lib/efl \
120-DTESTS_BUILD_DIR=\"$(top_builddir)/src/tests/elua\" \
121-DPACKAGE_DATA_DIR=\"$(top_srcdir)/src/tests/elua\" \
122-DPACKAGE_BUILD_DIR=\"$(abs_top_builddir)\" \
123-DELUA_BINDINGS_DIR=\"$(ELUA_BINDINGS_DIR)\" \
124-DELUA_CORE_DIR=\"$(ELUA_CORE_DIR)\" \
125-DELUA_MODULES_DIR=\"$(ELUA_MODULES_DIR)\" \
126-DELUA_APPS_DIR=\"$(ELUA_APPS_DIR)\" \
127@CHECK_CFLAGS@ \
128@ELUA_CFLAGS@
129
130TESTS += tests/elua/elua_suite
131
132if HAVE_OSX
133if HAVE_X86_64
134tests_elua_elua_suite_LDFLAGS = -pagezero_size 10000 -image_base 100000000
135endif
136endif
137
138tests_elua_elua_suite_LDADD = @CHECK_LIBS@ @USE_ELUA_LIBS@
139tests_elua_elua_suite_DEPENDENCIES = @USE_ELUA_INTERNAL_LIBS@
140
141endif
142
109endif 143endif
diff --git a/src/Makefile_Elua_Helper.am b/src/Makefile_Elua_Helper.am
index 0be2ad00bf..10b15541fc 100644
--- a/src/Makefile_Elua_Helper.am
+++ b/src/Makefile_Elua_Helper.am
@@ -3,7 +3,9 @@ ELUA_GEN = @elua_bin@ lualian
3_ELUA_GEN_DEP = @elua_bin@ 3_ELUA_GEN_DEP = @elua_bin@
4else 4else
5ELUA_GEN = ELUA_EOLIAN_LIBRARY_PATH=$(top_builddir)/src/lib/eolian/.libs \ 5ELUA_GEN = ELUA_EOLIAN_LIBRARY_PATH=$(top_builddir)/src/lib/eolian/.libs \
6 EFL_RUN_IN_TREE=1 $(top_builddir)/src/bin/elua/elua${EXEEXT} lualian 6 $(top_builddir)/src/bin/elua/elua${EXEEXT} \
7 -I$(ELUA_BINDINGS_DIR) -C$(ELUA_CORE_DIR) -M$(ELUA_MODULES_DIR) \
8 -A$(ELUA_APPS_DIR) lualian
7_ELUA_GEN_DEP = bin/elua/elua${EXEEXT} scripts/elua/apps/lualian.lua \ 9_ELUA_GEN_DEP = bin/elua/elua${EXEEXT} scripts/elua/apps/lualian.lua \
8 scripts/elua/modules/lualian.lua \ 10 scripts/elua/modules/lualian.lua \
9 scripts/elua/modules/getopt.lua scripts/elua/core/util.lua \ 11 scripts/elua/modules/getopt.lua scripts/elua/core/util.lua \
diff --git a/src/bin/elua/main.c b/src/bin/elua/main.c
index 3716a51984..ed1b4074a4 100644
--- a/src/bin/elua/main.c
+++ b/src/bin/elua/main.c
@@ -2,8 +2,6 @@
2# include <config.h> 2# include <config.h>
3#endif 3#endif
4 4
5/* The Lua runtime component of the EFL */
6
7#include <stdio.h> 5#include <stdio.h>
8#include <stdlib.h> 6#include <stdlib.h>
9#include <getopt.h> 7#include <getopt.h>
@@ -19,313 +17,19 @@
19#include <Eina.h> 17#include <Eina.h>
20#include <Ecore.h> 18#include <Ecore.h>
21 19
22#include "Elua.h" 20#include <Elua.h>
23
24typedef struct Arg_Data
25{
26 int type;
27 const char *value;
28} Arg_Data;
29
30enum
31{
32 ARG_CODE = 0,
33 ARG_LIBRARY,
34 ARG_LIBDIR
35};
36
37static Eina_List *elua_modlist = NULL;
38static int elua_require_ref = LUA_REFNIL;
39static int elua_appload_ref = LUA_REFNIL;
40static const char *elua_progname = NULL;
41static Eina_Prefix *elua_prefix = NULL;
42 21
43static int _el_log_domain = -1; 22static int _el_log_domain = -1;
44 23
45#define DBG(...) EINA_LOG_DOM_DBG(_el_log_domain, __VA_ARGS__)
46#define INF(...) EINA_LOG_DOM_INFO(_el_log_domain, __VA_ARGS__) 24#define INF(...) EINA_LOG_DOM_INFO(_el_log_domain, __VA_ARGS__)
47#define WRN(...) EINA_LOG_DOM_WARN(_el_log_domain, __VA_ARGS__)
48#define ERR(...) EINA_LOG_DOM_ERR(_el_log_domain, __VA_ARGS__) 25#define ERR(...) EINA_LOG_DOM_ERR(_el_log_domain, __VA_ARGS__)
49#define CRT(...) EINA_LOG_DOM_CRITICAL(_el_log_domain, __VA_ARGS__)
50
51static int
52elua_traceback(lua_State *L)
53{
54 lua_getglobal(L, "debug");
55 if (!lua_istable(L, -1))
56 {
57 lua_pop(L, 1);
58 return 1;
59 }
60 lua_getfield(L, -1, "traceback");
61 if (!lua_isfunction(L, -1))
62 {
63 lua_pop(L, 2);
64 return 1;
65 }
66 lua_pushvalue(L, 1);
67 lua_pushinteger(L, 2);
68 lua_call(L, 2, 1);
69 return 1;
70}
71
72static int
73elua_docall(lua_State *L, int narg, int nret)
74{
75 int status;
76 int bs = lua_gettop(L) - narg;
77 lua_pushcfunction(L, elua_traceback);
78 lua_insert(L, bs);
79 status = lua_pcall(L, narg, nret, bs);
80 lua_remove(L, bs);
81 if (status)
82 lua_gc(L, LUA_GCCOLLECT, 0);
83 return status;
84}
85
86static int
87elua_getargs(lua_State *L, int argc, char **argv, int n)
88{
89 int i;
90 int narg = argc - (n + 1);
91 luaL_checkstack(L, narg + 3, "too many arguments to script");
92 for (i = n + 1; i < argc; ++i)
93 {
94 lua_pushstring(L, argv[i]);
95 }
96 lua_createtable(L, narg, n + 1);
97 for (i = 0; i < argc; ++i)
98 {
99 lua_pushstring(L, argv[i]);
100 lua_rawseti(L, -2, i - n);
101 }
102 return narg;
103}
104
105static int
106elua_init_module(lua_State *L)
107{
108 if (!lua_isnoneornil(L, 1))
109 {
110 lua_pushvalue(L, 1);
111 lua_call(L, 0, 0);
112 }
113 if (!lua_isnoneornil(L, 2))
114 {
115 lua_pushvalue(L, 2);
116 elua_modlist = eina_list_append(elua_modlist,
117 (void*)(size_t)luaL_ref(L, LUA_REGISTRYINDEX));
118 }
119 return 0;
120}
121
122static int
123elua_register_require(lua_State *L)
124{
125 const char *corepath = lua_touserdata(L, lua_upvalueindex(1));
126 const char *modpath = lua_touserdata(L, lua_upvalueindex(2));
127 const char *appspath = lua_touserdata(L, lua_upvalueindex(3));
128 Eina_List *largs = lua_touserdata(L, lua_upvalueindex(4)), *l = NULL;
129 Eina_Bool noenv = lua_toboolean (L, lua_upvalueindex(5));
130 Arg_Data *data = NULL;
131 char corepathbuf[PATH_MAX], modpathbuf[PATH_MAX], appspathbuf[PATH_MAX];
132 int n = 3;
133 lua_pushvalue(L, 1);
134 elua_require_ref = luaL_ref(L, LUA_REGISTRYINDEX);
135 lua_pushvalue(L, 2);
136 elua_appload_ref = luaL_ref(L, LUA_REGISTRYINDEX);
137 if (getenv("EFL_RUN_IN_TREE"))
138 {
139 corepath = PACKAGE_SRC_DIR "/src/scripts/elua/core";
140 modpath = PACKAGE_SRC_DIR "/src/scripts/elua/modules";
141 appspath = PACKAGE_SRC_DIR "/src/scripts/elua/apps";
142 }
143 else
144 {
145 if (!corepath)
146 {
147 if (noenv || !(corepath = getenv("ELUA_CORE_DIR")) || !corepath[0])
148 {
149 corepath = corepathbuf;
150 snprintf(corepathbuf, sizeof(corepathbuf), "%s/core",
151 eina_prefix_data_get(elua_prefix));
152 }
153 }
154 if (!modpath)
155 {
156 if (noenv || !(modpath = getenv("ELUA_MODULES_DIR")) || !modpath[0])
157 {
158 modpath = modpathbuf;
159 snprintf(modpathbuf, sizeof(modpathbuf), "%s/modules",
160 eina_prefix_data_get(elua_prefix));
161 }
162 }
163 if (!appspath)
164 {
165 if (noenv || !(appspath = getenv("ELUA_APPS_DIR")) || !appspath[0])
166 {
167 appspath = appspathbuf;
168 snprintf(appspathbuf, sizeof(appspathbuf), "%s/apps",
169 eina_prefix_data_get(elua_prefix));
170 }
171 }
172 }
173 lua_pushfstring(L, "%s/?.lua;", corepath);
174 EINA_LIST_FOREACH(largs, l, data)
175 {
176 if (data->type != ARG_LIBDIR) continue;
177 lua_pushfstring(L, "%s/?.lua;", data->value);
178 ++n;
179 }
180 lua_pushfstring(L, "%s/?.eo.lua;", modpath);
181 lua_pushfstring(L, "%s/?.lua;", modpath);
182 lua_pushvalue(L, 3);
183 lua_concat(L, n + 1);
184 lua_pushfstring(L, "%s/?.lua;", appspath);
185 lua_pushvalue(L, 4);
186 lua_concat(L, 2);
187 return 2;
188}
189
190static int
191elua_dolib(lua_State *L, const char *libname)
192{
193 lua_rawgeti(L, LUA_REGISTRYINDEX, elua_require_ref);
194 lua_pushstring(L, libname);
195 return elua_report_error(L, elua_progname, lua_pcall(L, 1, 0, 0));
196}
197
198static int
199elua_dofile(lua_State *L, const char *fname)
200{
201 return elua_report_error(L, elua_progname, elua_io_loadfile(L, fname)
202 || elua_docall(L, 0, 1));
203}
204
205static int
206elua_dostr(lua_State *L, const char *chunk, const char *chname)
207{
208 return elua_report_error(L, elua_progname, luaL_loadbuffer(L, chunk,
209 strlen(chunk), chname) || elua_docall(L, 0, 0));
210}
211
212static Eina_Bool
213elua_loadapp(lua_State *L, const char *appname)
214{
215 lua_rawgeti(L, LUA_REGISTRYINDEX, elua_appload_ref);
216 lua_pushstring(L, appname);
217 lua_call(L, 1, 2);
218 if (lua_isnil(L, -2))
219 {
220 lua_remove(L, -2);
221 return EINA_FALSE;
222 }
223 lua_pop(L, 1);
224 return EINA_TRUE;
225}
226
227static int
228elua_doscript(lua_State *L, int argc, char **argv, int n, int *quit)
229{
230 int status;
231 const char *fname = argv[n];
232 int narg = elua_getargs(L, argc, argv, n);
233 lua_setglobal(L, "arg");
234 if (fname[0] == '-' && !fname[1])
235 {
236 fname = NULL;
237 }
238 if (fname)
239 {
240 /* check if there is a file of that name */
241 FILE *f = fopen(fname, "r");
242 if (f)
243 {
244 fclose(f);
245 status = elua_io_loadfile(L, fname);
246 }
247 else
248 status = !elua_loadapp(L, fname);
249 }
250 else
251 {
252 status = elua_io_loadfile(L, fname);
253 }
254 lua_insert(L, -(narg + 1));
255 if (!status)
256 {
257 status = elua_docall(L, narg, 1);
258 }
259 else
260 {
261 lua_pop(L, narg);
262 }
263 if (!status)
264 {
265 *quit = lua_toboolean(L, -1);
266 lua_pop(L, 1);
267 }
268 return elua_report_error(L, elua_progname, status);
269}
270
271void
272elua_bin_shutdown(lua_State *L, int c)
273{
274 void *data;
275 INF("elua shutdown");
276
277 EINA_LIST_FREE(elua_modlist, data)
278 {
279 lua_rawgeti(L, LUA_REGISTRYINDEX, (size_t)data);
280 lua_call(L, 0, 0);
281 }
282
283 if (elua_prefix) eina_prefix_free(elua_prefix);
284
285 if (L) lua_close(L);
286 if (_el_log_domain != EINA_LOG_DOMAIN_GLOBAL)
287 eina_log_domain_unregister(_el_log_domain);
288 elua_shutdown();
289 exit(c);
290}
291
292static int elua_cb_ref = LUA_REFNIL;
293static lua_State *elua_state = NULL;
294
295static void
296elua_smart_cb_wrapper(void *data, void *obj EINA_UNUSED, void *einfo EINA_UNUSED)
297{
298 int idx = (size_t)data;
299 lua_rawgeti(elua_state, LUA_REGISTRYINDEX, elua_cb_ref);
300 lua_rawgeti(elua_state, -1, idx);
301 lua_call(elua_state, 0, 0);
302 lua_pop(elua_state, 1);
303}
304
305static int
306elua_register_callbacks(lua_State *L)
307{
308 union { void (*fptr)(void*, void*, void*); void *ptr; } u;
309 lua_pushvalue(L, 1);
310 elua_cb_ref = luaL_ref(L, LUA_REGISTRYINDEX);
311 u.fptr = elua_smart_cb_wrapper;
312 lua_pushlightuserdata(L, u.ptr);
313 return 1;
314}
315 26
316struct Main_Data 27struct Main_Data
317{ 28{
318 int argc; 29 Elua_State *es;
319 char **argv; 30 int argc;
320 int status; 31 char **argv;
321}; 32 int status;
322
323const luaL_reg cutillib[] =
324{
325 { "init_module" , elua_init_module },
326 { "register_callbacks", elua_register_callbacks },
327 { "popenv" , elua_io_popen },
328 { NULL , NULL }
329}; 33};
330 34
331static void 35static void
@@ -335,190 +39,87 @@ elua_print_help(const char *pname, FILE *stream)
335 "A main entry for all EFL/LuaJIT powered applications.\n\n" 39 "A main entry for all EFL/LuaJIT powered applications.\n\n"
336 "The following options are supported:\n\n" 40 "The following options are supported:\n\n"
337 "" 41 ""
338 " -h, --help Show this message.\n" 42 " -h Show this message.\n"
339 " -l, --license Show a license message.\n" 43 " -l Show a license message.\n"
340 " -C[COREDIR], --core-dir=[COREDIR] Elua core directory path.\n" 44 " -C[COREDIR] Elua core directory path.\n"
341 " -M[MODDIR], --modules-dir=[MODDIR] Elua modules directory path.\n" 45 " -M[MODDIR] Elua modules directory path.\n"
342 " -A[APPDIR], --apps-dir=[APPDIR] Elua applications directory path.\n" 46 " -A[APPDIR] Elua applications directory path.\n"
343 " -e[CODE], --execute=[CODE] Execute string 'code'.\n" 47 " -l[LIBRARY] Require library 'library'.\n"
344 " -l[LIBRARY], --library=[LIBRARY] Require library 'library'.\n" 48 " -I[DIR], Append an additional require path.\n"
345 " -I[DIR], --lib-dir=[DIR] Append an additional require path.\n" 49 " -E, Ignore environment variables.\n", pname);
346 " -E, --noenv Ignore environment variables.\n", pname);
347} 50}
348 51
349static struct option lopt[] =
350{
351 { "help" , no_argument , NULL, 'h' },
352
353 { "core-dir" , required_argument, NULL, 'C' },
354 { "modules-dir", required_argument, NULL, 'M' },
355 { "apps-dir" , required_argument, NULL, 'A' },
356
357 { "execute" , required_argument, NULL, 'e' },
358 { "library" , required_argument, NULL, 'l' },
359 { "lib-dir" , required_argument, NULL, 'I' },
360 { "noenv" , no_argument , NULL, 'E' },
361 { NULL , 0 , NULL, 0 }
362};
363
364/* protected main */ 52/* protected main */
365static int 53static int
366elua_main(lua_State *L) 54elua_main(lua_State *L)
367{ 55{
368 Eina_Bool noenv = EINA_FALSE, 56 Eina_Bool noenv = EINA_FALSE;
369 hasexec = EINA_FALSE; 57 const char *coredir = NULL, *moddir = NULL, *appsdir = NULL;
370 Eina_List *largs = NULL, *l = NULL;
371 Arg_Data *data = NULL;
372 const char *coref = NULL;
373 char *coredir = NULL, *moddir = NULL, *appsdir = NULL;
374 char modfile[PATH_MAX];
375 char corefbuf[PATH_MAX];
376 58
377 int ch; 59 struct Main_Data *m = (struct Main_Data*)lua_touserdata(L, 1);
378 60 Elua_State *es = m->es;
379 struct Main_Data *m = (struct Main_Data*)lua_touserdata(L, 1);
380 61
381 int argc = m->argc; 62 int argc = m->argc;
382 char **argv = m->argv; 63 char **argv = m->argv;
383 64
384 elua_progname = (argv[0] && argv[0][0]) ? argv[0] : "elua"; 65 int ch;
385 66
386 while ((ch = getopt_long(argc, argv, "+LhC:M:A:e:l:I:E", lopt, NULL)) != -1) 67 while ((ch = getopt(argc, argv, "+LhC:M:A:l:I:E")) != -1)
387 { 68 switch (ch)
388 switch (ch) 69 {
389 { 70 case 'h':
390 case 'h': 71 elua_print_help(elua_state_prog_name_get(es), stdout); return 0;
391 elua_print_help(elua_progname, stdout); 72 case 'C':
392 return 0; 73 coredir = optarg; break;
393 case 'C': 74 case 'M':
394 coredir = optarg; 75 moddir = optarg; break;
395 break; 76 case 'A':
396 case 'M': 77 appsdir = optarg; break;
397 moddir = optarg; 78 case 'l':
398 break; 79 case 'I':
399 case 'A': 80 if (!optarg[0]) continue;
400 appsdir = optarg; 81 if (ch == 'l')
401 break; 82 elua_util_require(es, optarg);
402 case 'e': 83 else
403 case 'l': 84 elua_state_include_path_add(es, optarg);
404 case 'I': 85 break;
405 { 86 case 'E':
406 Arg_Data *v = malloc(sizeof(Arg_Data)); 87 noenv = EINA_TRUE; break;
407 v->type = (ch == 'e') ? ARG_CODE : ((ch == 'l') 88 }
408 ? ARG_LIBRARY : ARG_LIBDIR);
409 v->value = optarg;
410 largs = eina_list_append(largs, v);
411 break;
412 }
413 }
414 }
415 89
416 INF("arguments parsed"); 90 INF("arguments parsed");
417 91
418 lua_gc(L, LUA_GCSTOP, 0); 92 lua_gc(L, LUA_GCSTOP, 0);
419 93
420 luaL_openlibs(L); 94 elua_state_dirs_set(es, coredir, moddir, appsdir);
421 95 elua_state_dirs_fill(es, noenv);
422 elua_prefix = eina_prefix_new(elua_progname, elua_main, "ELUA", "elua", "checkme",
423 PACKAGE_BIN_DIR, "", PACKAGE_DATA_DIR,
424 LOCALE_DIR);
425 96
426 if (!elua_prefix) 97 if (!elua_state_setup(es))
427 { 98 {
428 ERR("could not find elua prefix");
429 m->status = 1; 99 m->status = 1;
430 return 0; 100 return 0;
431 } 101 }
432 102
433 if (getenv("EFL_RUN_IN_TREE"))
434 {
435 Arg_Data *v = malloc(sizeof(Arg_Data));
436 v->type = ARG_LIBDIR;
437 v->value = PACKAGE_SRC_DIR "/src/bindings/luajit";
438 largs = eina_list_append(largs, v);
439 coref = PACKAGE_SRC_DIR "/src/scripts/elua/core";
440 }
441 else if (!(coref = coredir))
442 {
443 if (noenv || !(coref = getenv("ELUA_CORE_DIR")) || !coref[0])
444 {
445 coref = corefbuf;
446 snprintf(corefbuf, sizeof(corefbuf), "%s/core",
447 eina_prefix_data_get(elua_prefix));
448 }
449 }
450 snprintf(modfile, sizeof(modfile), "%s/module.lua", coref);
451 if (elua_report_error(L, elua_progname, elua_io_loadfile(L, modfile)))
452 {
453 m->status = 1;
454 return 0;
455 }
456 lua_pushlightuserdata(L, coredir);
457 lua_pushlightuserdata(L, moddir);
458 lua_pushlightuserdata(L, appsdir);
459 lua_pushlightuserdata(L, largs);
460 lua_pushboolean (L, noenv);
461 lua_pushcclosure(L, elua_register_require, 5);
462 lua_createtable(L, 0, 0);
463 luaL_register(L, NULL, cutillib);
464 lua_call(L, 2, 0);
465
466 snprintf(modfile, sizeof(modfile), "%s/gettext.lua", coref);
467 if (elua_report_error(L, elua_progname, elua_io_loadfile(L, modfile)))
468 {
469 m->status = 1;
470 return 0;
471 }
472 elua_state_setup_i18n(L);
473 lua_call(L, 1, 0);
474
475 elua_io_register(L);
476 lua_gc(L, LUA_GCRESTART, 0); 103 lua_gc(L, LUA_GCRESTART, 0);
477 104
478 INF("elua lua state initialized"); 105 INF("elua lua state initialized");
479 106
480 /* load all the things */
481 EINA_LIST_FOREACH(largs, l, data)
482 {
483 switch (data->type)
484 {
485 case ARG_CODE:
486 if (!hasexec) hasexec = EINA_TRUE;
487 if (elua_dostr(L, data->value, "=(command line)"))
488 {
489 m->status = 1;
490 return 0;
491 }
492 break;
493 case ARG_LIBRARY:
494 if (elua_dolib(L, data->value))
495 {
496 m->status = 1;
497 return 0;
498 }
499 break;
500 default:
501 break;
502 }
503 }
504
505 /* cleanup */
506 EINA_LIST_FREE(largs, data) free(data);
507
508 /* run script or execute sdin as file */
509 if (optind < argc) 107 if (optind < argc)
510 { 108 {
511 int quit = 0; 109 int quit = 0;
512 if ((m->status = elua_doscript(L, argc, argv, optind, &quit))) return 0; 110 if (!elua_util_script_run(es, argc, argv, optind, &quit))
513 if (quit) return 0; 111 {
112 m->status = 1;
113 return 0;
114 }
115 if (quit)
116 return 0;
514 } 117 }
515 else if (!hasexec) 118 else
516 { 119 {
517 int quit; 120 ERR("nothing to run");
518 if ((m->status = elua_dofile(L, NULL))) return 0; 121 m->status = 1;
519 quit = lua_toboolean(L, -1); 122 return 0;
520 lua_pop(L, 1);
521 if (quit) return 0;
522 } 123 }
523 124
524 ecore_main_loop_begin(); 125 ecore_main_loop_begin();
@@ -526,11 +127,22 @@ elua_main(lua_State *L)
526 return 0; 127 return 0;
527} 128}
528 129
130void
131elua_bin_shutdown(Elua_State *es, int c)
132{
133 INF("elua shutdown");
134 if (es) elua_state_free(es);
135 if (_el_log_domain != EINA_LOG_DOMAIN_GLOBAL)
136 eina_log_domain_unregister(_el_log_domain);
137 elua_shutdown();
138 exit(c);
139}
140
529int 141int
530main(int argc, char **argv) 142main(int argc, char **argv)
531{ 143{
532 struct Main_Data m; 144 struct Main_Data m;
533 lua_State *L = NULL; 145 Elua_State *es = NULL;
534 146
535#ifdef ENABLE_NLS 147#ifdef ENABLE_NLS
536 setlocale(LC_ALL, ""); 148 setlocale(LC_ALL, "");
@@ -550,21 +162,20 @@ main(int argc, char **argv)
550 162
551 INF("elua logging initialized: %d", _el_log_domain); 163 INF("elua logging initialized: %d", _el_log_domain);
552 164
553 if (!(L = luaL_newstate())) 165 if (!(es = elua_state_new((argv[0] && argv[0][0]) ? argv[0] : "elua")))
554 { 166 {
555 ERR("could not initialize elua state."); 167 ERR("could not initialize elua state.");
556 elua_bin_shutdown(L, 1); 168 elua_bin_shutdown(es, 1);
557 } 169 }
558 170
559 elua_state = L;
560
561 INF("elua lua state created"); 171 INF("elua lua state created");
562 172
173 m.es = es;
563 m.argc = argc; 174 m.argc = argc;
564 m.argv = argv; 175 m.argv = argv;
565 m.status = 0; 176 m.status = 0;
566 177
567 elua_bin_shutdown(L, !!(lua_cpcall(L, elua_main, &m) || m.status)); 178 elua_bin_shutdown(es, !!(lua_cpcall(elua_state_lua_state_get(es), elua_main, &m) || m.status));
568 179
569 return 0; /* never gets here */ 180 return 0; /* never gets here */
570} 181}
diff --git a/src/lib/elua/Elua.h b/src/lib/elua/Elua.h
index 8df01de3cc..3b087790b8 100644
--- a/src/lib/elua/Elua.h
+++ b/src/lib/elua/Elua.h
@@ -52,22 +52,405 @@ extern "C" {
52# include <config.h> 52# include <config.h>
53#endif 53#endif
54 54
55/**
56 * @page elua_main Elua library (BETA)
57 *
58 * @date 2015 (created)
59 *
60 * @section toc Table of Contents
61 *
62 * @li @ref elua_main_intro
63 * @li @ref elua_main_compiling
64 * @li @ref elua_main_next_steps
65 *
66 * @section elua_main_intro Introduction
67 *
68 * The Elua library provides all necessary infrastructure required to set up
69 * a fully functional Lua state able of running Elua scripts. This is provided
70 * as a library in order to encourage reuse from different libraries and apps.
71 *
72 * @section elua_main_compiling How to compile
73 *
74 * As Elua is a library, compiling is very simple.
75 *
76 * Compiling C or C++ files into object files:
77 *
78 * @verbatim
79 gcc -c -o main.o main.c `pkg-config --cflags elua`
80 @endverbatim
81 *
82 * Linking object files into a binary executable:
83 *
84 * @verbatim
85 gcc -o my_application main.o `pkg-config --libs elua`
86 @endverbatim
87 *
88 * See @ref pkgconfig
89 *
90 * @section elua_main_next_steps Next Steps
91 *
92 * There is a comperehensive API reference available that should get you up
93 * and running.
94 *
95 * @addtogroup Elua
96 * @{
97 */
98
55#ifdef EFL_BETA_API_SUPPORT 99#ifdef EFL_BETA_API_SUPPORT
56 100
101#include <Eina.h>
102
57#include <lua.h> 103#include <lua.h>
58#include <lualib.h> 104#include <lualib.h>
59#include <lauxlib.h> 105#include <lauxlib.h>
60 106
107/** Opaque Elua state
108 *
109 * @ingroup Elua
110 */
111typedef struct _Elua_State Elua_State;
112
113/**
114 * @brief Initialize the Elua library.
115 *
116 * This initializes the Elua library for usage. It maintains an internal
117 * counter so that multiple calls will only increment/decrement correctly.
118 *
119 * @see elua_shutdown
120 *
121 * @ingroup Elua
122 */
61EAPI int elua_init(void); 123EAPI int elua_init(void);
124
125/**
126 * @brief Shutdown the Elua library.
127 *
128 * Depending on the internal initialization counter, this either decrements
129 * or completely shuts down the Elua library. In any case, call this once for
130 * each init call.
131 *
132 * @see elua_init
133 *
134 * @ingroup Elua
135 */
62EAPI int elua_shutdown(void); 136EAPI int elua_shutdown(void);
63 137
64EAPI int elua_report_error(lua_State *L, const char *pname, int status); 138/**
139 * @brief Create a new Elua state.
140 *
141 * This creates a new Elua state. An Elua state is externally opaque, but
142 * it contains a LuaJIT state as well as some additional information that
143 * is mostly initialized by other APIs.
144 *
145 * @param[in] progname The program name that holds the Elua state. This will
146 * be used for stuff like error reporting. Typically the same as the binary
147 * name of the application (argv[0]).
148 * @return A new Elua state or NULL.
149 *
150 * @ingroup Elua
151 */
152EAPI Elua_State *elua_state_new(const char *progname);
153
154/**
155 * @brief Retrieve an Elua state from a Lua state.
156 *
157 * This doesn't create a new Elua state. Instead it just retrieves an existing
158 * Elua state given a Lua state. If no Elua state could be found (for example
159 * when the Lua state was created independently of Elua), this function returns
160 * NULL.
161 *
162 * @param[in] L The Lua state.
163 * @return An Elua state or NULL.
164 *
165 * @ingroup Elua
166 */
167EAPI Elua_State *elua_state_from_lua_state_get(lua_State *L);
168
169/**
170 * @brief Destroy an Elua state.
171 *
172 * Given an Elua state, this destroys its internal Lua state as well as all
173 * other data its holding and then frees the Elua state itself.
174 *
175 * @param[in] es The Elua state.
176 *
177 * @ingroup Elua
178 */
179EAPI void elua_state_free(Elua_State *es);
180
181/**
182 * @brief Set the Elua directory paths.
183 *
184 * Every Elua state needs three paths - the core script path, the module
185 * path and the apps path. The core path refers to from where core scripts
186 * will be loaded (such as the module system), the module path refers to from
187 * where extra modules will be loaded and the apps path refers to from where
188 * Elua applications will be loaded (this is not a module path).
189 *
190 * If you provide NULL for any path, it will not be set. This allows you to
191 * split the setting into multiple calls. By the time of state use all need
192 * to be set.
193 *
194 * @param[in] es The Elua state.
195 * @param[in] core The core path.
196 * @param[in] mods The modules path.
197 * @param[in] apps The apps path.
198 *
199 * @see elua_state_core_dir_get
200 * @see elua_state_mod_dir_get
201 * @see elua_state_apps_dir_get
202 *
203 * @ingroup Elua
204 */
205EAPI void elua_state_dirs_set(Elua_State *es, const char *core,
206 const char *mods, const char *apps);
207
208/**
209 * @brief Fill the currently unset Elua dirs.
210 *
211 * This checks if any of the three main paths are unset and tries to fill
212 * them from the environment. It first tries environment variables to fill
213 * them (ELUA_CORE_DIR, ELUA_MODULES_DIR, ELUA_APPS_DIR) unless the ignore_env
214 * param is EINA_TRUE. If it is (or if the environment vars weren't set right)
215 * it uses eina prefix of the library to determine the paths. In that case
216 * they will expand to DATADIR/core, DATADIR/modules and DATADIR/apps, where
217 * DATADIR is typically something like /usr/share/elua.
218 *
219 * @param[in] es The Elua state.
220 * @param[in] ignore_env If set to EINA_TRUE, this ignores the env vars.
221 *
222 * @ingroup Elua
223 */
224EAPI void elua_state_dirs_fill(Elua_State *es, Eina_Bool ignore_env);
225
226/**
227 * @brief Retrieve the Elua core dir.
228 *
229 * @param[in] es The Elua state.
230 * @return The path.
231 *
232 * @ingroup Elua
233 */
234EAPI Eina_Stringshare *elua_state_core_dir_get(const Elua_State *es);
235
236/**
237 * @brief Retrieve the Elua module dir.
238 *
239 * @param[in] es The Elua state.
240 * @return The path.
241 *
242 * @ingroup Elua
243 */
244EAPI Eina_Stringshare *elua_state_mod_dir_get(const Elua_State *es);
245
246/**
247 * @brief Retrieve the Elua apps dir.
248 *
249 * @param[in] es The Elua state.
250 * @return The path.
251 *
252 * @ingroup Elua
253 */
254EAPI Eina_Stringshare *elua_state_apps_dir_get(const Elua_State *es);
255
256/**
257 * @brief Retrieve the prog name set on state creation.
258 *
259 * @param[in] es The Elua state.
260 * @return The name.
261 *
262 * @ingroup Elua
263 */
264EAPI Eina_Stringshare *elua_state_prog_name_get(const Elua_State *es);
265
266/**
267 * @brief Add another path to look up modules in to the state.
268 *
269 * @param[in] es The Elua state.
270 *
271 * @ingroup Elua
272 */
273EAPI void elua_state_include_path_add(Elua_State *es, const char *path);
274
275/**
276 * @brief Push the Elua "require" function onto the Lua stack.
277 *
278 * @param[in] es The Elua state.
279 * @return EINA_TRUE if the push was successful, EINA_FALSE otherwise.
280 *
281 * @ingroup Elua
282 */
283EAPI Eina_Bool elua_state_require_ref_push(Elua_State *es);
284
285/**
286 * @brief Push the Elua app loader function onto the Lua stack.
287 *
288 * @param[in] es The Elua state.
289 * @return EINA_TRUE if the push was successful, EINA_FALSE otherwise.
290 *
291 * @ingroup Elua
292 */
293EAPI Eina_Bool elua_state_appload_ref_push(Elua_State *es);
294
295/**
296 * @brief Retrieve the Lua state from an Elua state.
297 *
298 * This function retrieves the Lua state from a valid Elua state. As an
299 * Elua state is always initialized, this will return a valid state, unless
300 * the given Elua state is NULL, in which case it will also return NULL.
301 *
302 * @param[in] es The Elua state.
303 * @return The Lua state or NULL.
304 *
305 * @ingroup Elua
306 */
307EAPI lua_State *elua_state_lua_state_get(const Elua_State *es);
308
309/**
310 * @brief Set up the Elua state.
311 *
312 * This API function sets up 3 things, module system, i18n and I/O. After that
313 * it requires all modules not yet required (i.e. those queued in before the
314 * state was fully initialized).
315 *
316 * This function sets up correct i18n for an Elua state. That means loading
317 * the gettext bindings and making Lua aware of them. This also works when
318 * i18n support is disabled at compilation time, so you can just call it
319 * unconditionally.
320 *
321 * This also loads the Elua module system and makes Lua aware of it. It also
322 * registers the Elua C utility library module.
323 *
324 * Finally, Elua provides its own loadfile based around mmap to replace the
325 * less efficient Lua version. This function takes care of the setup.
326 *
327 * @param[in] es The Elua state.
328 * @return EINA_TRUE on success, EINA_FALSE on failure.
329 *
330 * @ingroup Elua
331 */
332EAPI Eina_Bool elua_state_setup(Elua_State *es);
333
334/**
335 * @brief Loads a file using Elua's own mmap-based IO.
336 *
337 * This function behaves identically to luaL_loadfile when it comes to
338 * semantics. The loaded file remains on the Lua stack. If the input
339 * state is NULL, the return value is -1 and nothing is left on the stack.
340 * On any different error, the error object is left on the stack and this
341 * returns a value larger than zero (LUA_ERR*). On success, zero is returned.
342 *
343 * @param[in] es The Elua state.
344 * @param[in] fname The file name.
345 * @return 0 for no errors, a non-zero value for errors (-1 for NULL es).
346 *
347 * @ingroup Elua
348 */
349EAPI int elua_io_loadfile(const Elua_State *es, const char *fname);
350
351/**
352 * @brief Requires a module.
353 *
354 * Requires a Lua module. Leaves the Lua stack clean.
355 *
356 * @param[in] es The Elua state.
357 * @param[in] libname The library name.
358 * @return EINA_TRUE on success, EINA_FALSE on failure.
359 *
360 * @ingroup Elua
361 */
362EAPI Eina_Bool elua_util_require(Elua_State *es, const char *libname);
363
364/**
365 * @brief Runs a file.
366 *
367 * Runs a file. Uses the Elua mmapped file IO to load the file.
368 *
369 * @param[in] es The Elua state.
370 * @param[in] fname The file name.
371 * @return EINA_TRUE on success, EINA_FALSE on failure.
372 *
373 * @ingroup Elua
374 */
375EAPI Eina_Bool elua_util_file_run(Elua_State *es, const char *fname);
65 376
66EAPI void elua_state_setup_i18n(lua_State *L); 377/**
378 * @brief Runs a string.
379 *
380 * Runs a string.
381 *
382 * @param[in] es The Elua state.
383 * @param[in] chunk The string to run.
384 * @param[in] chname The chunk name to use for traceback/debug.
385 * @return EINA_TRUE on success, EINA_FALSE on failure.
386 *
387 * @ingroup Elua
388 */
389EAPI Eina_Bool elua_util_string_run(Elua_State *es, const char *chunk,
390 const char *chname);
67 391
68EAPI int elua_io_popen(lua_State *L); 392/**
69EAPI int elua_io_loadfile(lua_State *L, const char *fname); 393 * @brief Loads an application.
70EAPI void elua_io_register(lua_State *L); 394 *
395 * This loads an app, respecting the app path set on state initialization.
396 * Actually runs the app. If the input state is NULL, the return value is -1
397 * nd nothing is left on the stack. On any different error, the error object
398 * is left on the stack and this returns 1. On success, zero is returned
399 * (and the return value from the app is left on the stack).
400 *
401 * @param[in] es The Elua state.
402 * @param[in] appname The application name.
403 * @return 0 for no errors, 1 on errors, -1 on null input.
404 *
405 * @ingroup Elua
406 */
407EAPI int elua_util_app_load(Elua_State *es, const char *appname);
408
409/**
410 * @brief Runs a script.
411 *
412 * This is a more complicated function that runs a script. It's a combination
413 * of the previously mentioned util functions. It takes argc and argv, which
414 * are typically given to the program, and an index of the first positional
415 * arg in argv (i.e. not options). The value on this index is then used as
416 * the potential name.
417 *
418 * If this name is either a dash or empty, the script is loaded from stdin.
419 * If it's a value and a file with this name exists, the script is loaded from
420 * the file. Otherwise, the name is treated to be an application name, and
421 * is loaded from the application path.
422 *
423 * If all succeeds, this is then run, and a quit value is written into the
424 * quit arg; if it's true (1), it means the app wants to exit immediately.
425 * If it's false (0), it means the app likely wants to execute a main loop.
426 *
427 * @param[in] es The Elua state.
428 * @param[in] argc The argument count.
429 * @param[in] argv The arguments.
430 * @param[in] n The index of the first positional argt.
431 * @param[out] quit Whether to quit or run a main loop.
432 * @return EINA_TRUE on success, EINA_FALSE on failure.
433 *
434 * @ingroup Elua
435 */
436EAPI Eina_Bool elua_util_script_run(Elua_State *es, int argc, char **argv,
437 int n, int *quit);
438
439/**
440 * @brief Reports an error using Eina logging.
441 *
442 * If the given status is 0, this function just returns it. Otherwise, it takes
443 * the topmost item on the Lua stack, converts it to string (if it cannot be
444 * converted, a "(non-string error)" placeholder is used) and logs it out
445 * as an error, together with the program name set on Elua state init.
446 *
447 * @param[in] es The Elua state.
448 * @param[in] status The status code.
449 * @return The status code.
450 *
451 * @ingroup Elua
452 */
453EAPI int elua_util_error_report(const Elua_State *es, int status);
71 454
72#endif 455#endif
73 456
diff --git a/src/lib/elua/cache.c b/src/lib/elua/cache.c
index e272843c69..b856b0bde9 100644
--- a/src/lib/elua/cache.c
+++ b/src/lib/elua/cache.c
@@ -150,13 +150,16 @@ getf_map(lua_State *L EINA_UNUSED, void *ud, size_t *size)
150} 150}
151 151
152EAPI int 152EAPI int
153elua_io_loadfile(lua_State *L, const char *fname) 153elua_io_loadfile(const Elua_State *es, const char *fname)
154{ 154{
155 Map_Stream s; 155 Map_Stream s;
156 int status; 156 int status;
157 Eina_File *f; 157 Eina_File *f;
158 const char *chname; 158 const char *chname;
159 Eina_Bool bcache = EINA_FALSE; 159 Eina_Bool bcache = EINA_FALSE;
160 lua_State *L;
161 if (!es || !es->luastate) return -1;
162 L = es->luastate;
160 if (!fname) 163 if (!fname)
161 { 164 {
162 return elua_loadstdin(L); 165 return elua_loadstdin(L);
@@ -187,8 +190,9 @@ elua_io_loadfile(lua_State *L, const char *fname)
187static int 190static int
188loadfile(lua_State *L) 191loadfile(lua_State *L)
189{ 192{
193 Elua_State *es = elua_state_from_lua_state_get(L);
190 const char *fname = luaL_optstring(L, 1, NULL); 194 const char *fname = luaL_optstring(L, 1, NULL);
191 int status = elua_io_loadfile(L, fname), 195 int status = elua_io_loadfile(es, fname),
192 hasenv = (lua_gettop(L) >= 3); 196 hasenv = (lua_gettop(L) >= 3);
193 if (!status) 197 if (!status)
194 { 198 {
@@ -204,9 +208,11 @@ loadfile(lua_State *L)
204 return 2; 208 return 2;
205} 209}
206 210
207EAPI void 211Eina_Bool
208elua_io_register(lua_State *L) 212_elua_state_io_setup(const Elua_State *es)
209{ 213{
210 lua_pushcfunction(L, loadfile); 214 EINA_SAFETY_ON_FALSE_RETURN_VAL(es && es->luastate, EINA_FALSE);
211 lua_setglobal(L, "loadfile"); 215 lua_pushcfunction(es->luastate, loadfile);
216 lua_setglobal(es->luastate, "loadfile");
217 return EINA_TRUE;
212} 218}
diff --git a/src/lib/elua/elua.c b/src/lib/elua/elua.c
index 2f88e7be02..3d34b1f9b1 100644
--- a/src/lib/elua/elua.c
+++ b/src/lib/elua/elua.c
@@ -62,22 +62,172 @@ elua_shutdown(void)
62 return _elua_init_counter; 62 return _elua_init_counter;
63} 63}
64 64
65static void 65EAPI Elua_State *
66_elua_errmsg(const char *pname, const char *msg) 66elua_state_new(const char *progname)
67{ 67{
68 ERR("%s%s%s", pname ? pname : "", pname ? ": " : "", msg); 68 Elua_State *ret = NULL;
69 lua_State *L = luaL_newstate();
70 if (!L)
71 return NULL;
72 ret = calloc(1, sizeof(Elua_State));
73 ret->luastate = L;
74 if (progname) ret->progname = eina_stringshare_add(progname);
75 luaL_openlibs(L);
76 lua_pushlightuserdata(L, ret);
77 lua_setfield(L, LUA_REGISTRYINDEX, "elua_ptr");
78 return ret;
69} 79}
70 80
71EAPI int 81EAPI void
72elua_report_error(lua_State *L, const char *pname, int status) 82elua_state_free(Elua_State *es)
83{
84 void *data;
85 if (!es) return;
86 if (es->luastate)
87 {
88 EINA_LIST_FREE(es->cmods, data)
89 {
90 lua_rawgeti(es->luastate, LUA_REGISTRYINDEX, (size_t)data);
91 lua_call(es->luastate, 0, 0);
92 }
93 lua_close(es->luastate);
94 }
95 else if (es->cmods)
96 eina_list_free(es->cmods);
97 EINA_LIST_FREE(es->lmods, data)
98 eina_stringshare_del(data);
99 EINA_LIST_FREE(es->lincs, data)
100 eina_stringshare_del(data);
101 eina_stringshare_del(es->progname);
102 eina_stringshare_del(es->coredir);
103 eina_stringshare_del(es->moddir);
104 eina_stringshare_del(es->appsdir);
105 free(es);
106}
107
108EAPI void
109elua_state_dirs_set(Elua_State *es, const char *core, const char *mods,
110 const char *apps)
111{
112 EINA_SAFETY_ON_NULL_RETURN(es);
113 if (core) es->coredir = eina_stringshare_add(core);
114 if (mods) es->moddir = eina_stringshare_add(mods);
115 if (apps) es->appsdir = eina_stringshare_add(apps);
116}
117
118EAPI void
119elua_state_dirs_fill(Elua_State *es, Eina_Bool ignore_env)
120{
121 const char *coredir = NULL, *moddir = NULL, *appsdir = NULL;
122 char coredirbuf[PATH_MAX], moddirbuf[PATH_MAX], appsdirbuf[PATH_MAX];
123 EINA_SAFETY_ON_NULL_RETURN(es);
124 if (!(coredir = es->coredir))
125 {
126 if (ignore_env || !(coredir = getenv("ELUA_CORE_DIR")) || !coredir[0])
127 {
128 coredir = coredirbuf;
129 snprintf(coredirbuf, sizeof(coredirbuf), "%s/core",
130 eina_prefix_data_get(_elua_pfx));
131 }
132 if (coredir) es->coredir = eina_stringshare_add(coredir);
133 }
134 if (!(moddir = es->moddir))
135 {
136 if (ignore_env || !(moddir = getenv("ELUA_MODULES_DIR")) || !moddir[0])
137 {
138 moddir = moddirbuf;
139 snprintf(moddirbuf, sizeof(moddirbuf), "%s/modules",
140 eina_prefix_data_get(_elua_pfx));
141 }
142 if (moddir) es->moddir = eina_stringshare_add(moddir);
143 }
144 if (!(appsdir = es->appsdir))
145 {
146 if (ignore_env || !(appsdir = getenv("ELUA_APPS_DIR")) || !appsdir[0])
147 {
148 appsdir = appsdirbuf;
149 snprintf(appsdirbuf, sizeof(appsdirbuf), "%s/apps",
150 eina_prefix_data_get(_elua_pfx));
151 }
152 if (appsdir) es->appsdir = eina_stringshare_add(appsdir);
153 }
154}
155
156EAPI Eina_Stringshare *
157elua_state_core_dir_get(const Elua_State *es)
158{
159 EINA_SAFETY_ON_NULL_RETURN_VAL(es, NULL);
160 return es->coredir;
161}
162
163EAPI Eina_Stringshare *
164elua_state_mod_dir_get(const Elua_State *es)
165{
166 EINA_SAFETY_ON_NULL_RETURN_VAL(es, NULL);
167 return es->moddir;
168}
169
170EAPI Eina_Stringshare *
171elua_state_apps_dir_get(const Elua_State *es)
172{
173 EINA_SAFETY_ON_NULL_RETURN_VAL(es, NULL);
174 return es->appsdir;
175}
176
177EAPI Eina_Stringshare *
178elua_state_prog_name_get(const Elua_State *es)
179{
180 EINA_SAFETY_ON_NULL_RETURN_VAL(es, NULL);
181 return es->progname;
182}
183
184EAPI void
185elua_state_include_path_add(Elua_State *es, const char *path)
186{
187 EINA_SAFETY_ON_NULL_RETURN(es);
188 EINA_SAFETY_ON_NULL_RETURN(path);
189 EINA_SAFETY_ON_FALSE_RETURN(path[0]);
190 es->lincs = eina_list_append(es->lincs, eina_stringshare_add(path));
191}
192
193EAPI Eina_Bool
194elua_state_require_ref_push(Elua_State *es)
195{
196 EINA_SAFETY_ON_NULL_RETURN_VAL(es, EINA_FALSE);
197 EINA_SAFETY_ON_FALSE_RETURN_VAL(es->requireref != LUA_REFNIL, EINA_FALSE);
198 lua_rawgeti(es->luastate, LUA_REGISTRYINDEX, es->requireref);
199 return EINA_TRUE;
200}
201
202EAPI Eina_Bool
203elua_state_appload_ref_push(Elua_State *es)
204{
205 EINA_SAFETY_ON_NULL_RETURN_VAL(es, EINA_FALSE);
206 EINA_SAFETY_ON_FALSE_RETURN_VAL(es->apploadref != LUA_REFNIL, EINA_FALSE);
207 lua_rawgeti(es->luastate, LUA_REGISTRYINDEX, es->apploadref);
208 return EINA_TRUE;
209}
210
211EAPI lua_State *
212elua_state_lua_state_get(const Elua_State *es)
213{
214 EINA_SAFETY_ON_NULL_RETURN_VAL(es, NULL);
215 return es->luastate;
216}
217
218EAPI Elua_State *
219elua_state_from_lua_state_get(lua_State *L)
73{ 220{
74 if (status && !lua_isnil(L, -1)) 221 EINA_SAFETY_ON_NULL_RETURN_VAL(L, NULL);
222 lua_getfield(L, LUA_REGISTRYINDEX, "elua_ptr");
223 if (!lua_isnil(L, -1))
75 { 224 {
76 const char *msg = lua_tostring(L, -1); 225 void *st = lua_touserdata(L, -1);
77 _elua_errmsg(pname, msg ? msg : "(non-string error)");
78 lua_pop(L, 1); 226 lua_pop(L, 1);
227 return (Elua_State *)st;
79 } 228 }
80 return status; 229 lua_pop(L, 1);
230 return NULL;
81} 231}
82 232
83static int 233static int
@@ -108,26 +258,377 @@ _elua_gettext_bind_textdomain(lua_State *L)
108#endif 258#endif
109} 259}
110 260
261static int
262_elua_get_message_language(lua_State *L)
263{
264 const char *e;
265 e = getenv("LANGUAGE");
266 if (e && e[0]) goto success;
267 e = getenv("LC_ALL");
268 if (e && e[0]) goto success;
269 e = getenv("LC_MESSAGES");
270 if (e && e[0]) goto success;
271 e = getenv("LANG");
272 if (e && e[0]) goto success;
273 lua_pushnil(L);
274 return 1;
275success:
276 lua_pushstring(L, e);
277 return 1;
278};
279
280static int
281_elua_get_localeconv(lua_State *L)
282{
283 struct lconv *lc = localeconv();
284 lua_createtable(L, 0, 24);
285
286#define ELUA_LCF_S(name) \
287 lua_pushstring(L, lc->name); \
288 lua_setfield(L, -2, #name);
289
290#define ELUA_LCF_C(name) \
291 lua_pushinteger(L, (lc->name == CHAR_MAX) ? -1 : (int)lc->name); \
292 lua_setfield(L, -2, #name);
293
294 ELUA_LCF_S(decimal_point);
295 ELUA_LCF_S(thousands_sep);
296 ELUA_LCF_S(grouping);
297 ELUA_LCF_S(int_curr_symbol);
298 ELUA_LCF_S(currency_symbol);
299 ELUA_LCF_S(mon_decimal_point);
300 ELUA_LCF_S(mon_thousands_sep);
301 ELUA_LCF_S(mon_grouping);
302 ELUA_LCF_S(positive_sign);
303 ELUA_LCF_S(negative_sign);
304
305 ELUA_LCF_C(frac_digits);
306 ELUA_LCF_C(p_cs_precedes);
307 ELUA_LCF_C(n_cs_precedes);
308 ELUA_LCF_C(p_sep_by_space);
309 ELUA_LCF_C(n_sep_by_space);
310 ELUA_LCF_C(p_sign_posn);
311 ELUA_LCF_C(n_sign_posn);
312 ELUA_LCF_C(int_frac_digits);
313 ELUA_LCF_C(int_p_cs_precedes);
314 ELUA_LCF_C(int_n_cs_precedes);
315 ELUA_LCF_C(int_p_sep_by_space);
316 ELUA_LCF_C(int_n_sep_by_space);
317 ELUA_LCF_C(int_p_sign_posn);
318 ELUA_LCF_C(int_n_sign_posn);
319
320#undef ELUA_LCF_S
321#undef ELUA_LCF_C
322
323 return 1;
324};
325
111const luaL_reg gettextlib[] = 326const luaL_reg gettextlib[] =
112{ 327{
113 { "bind_textdomain", _elua_gettext_bind_textdomain }, 328 { "bind_textdomain", _elua_gettext_bind_textdomain },
329 { "get_message_language", _elua_get_message_language },
330 { "get_localeconv", _elua_get_localeconv },
114 { NULL, NULL } 331 { NULL, NULL }
115}; 332};
116 333
117EAPI void 334static Eina_Bool
118elua_state_setup_i18n(lua_State *L) 335_elua_state_i18n_setup(const Elua_State *es)
119{ 336{
120#ifdef ENABLE_NLS 337#ifdef ENABLE_NLS
121 char *(*dgettextp)(const char*, const char*) = dgettext; 338 char *(*dgettextp)(const char*, const char*) = dgettext;
122 char *(*dngettextp)(const char*, const char*, const char*, unsigned long) 339 char *(*dngettextp)(const char*, const char*, const char*, unsigned long)
123 = dngettext; 340 = dngettext;
124#endif 341#endif
125 lua_createtable(L, 0, 0); 342 char buf[PATH_MAX];
126 luaL_register(L, NULL, gettextlib); 343 EINA_SAFETY_ON_NULL_RETURN_VAL(es, EINA_FALSE);
344 EINA_SAFETY_ON_NULL_RETURN_VAL(es->coredir, EINA_FALSE);
345 EINA_SAFETY_ON_NULL_RETURN_VAL(es->progname, EINA_FALSE);
346 snprintf(buf, sizeof(buf), "%s/gettext.lua", es->coredir);
347 if (elua_util_error_report(es, elua_io_loadfile(es, buf)))
348 return EINA_FALSE;
349 lua_createtable(es->luastate, 0, 0);
350 luaL_register(es->luastate, NULL, gettextlib);
127#ifdef ENABLE_NLS 351#ifdef ENABLE_NLS
128 lua_pushlightuserdata(L, *((void**)&dgettextp)); 352 lua_pushlightuserdata(es->luastate, *((void**)&dgettextp));
129 lua_setfield(L, -2, "dgettext"); 353 lua_setfield(es->luastate, -2, "dgettext");
130 lua_pushlightuserdata(L, *((void**)&dngettextp)); 354 lua_pushlightuserdata(es->luastate, *((void**)&dngettextp));
131 lua_setfield(L, -2, "dngettext"); 355 lua_setfield(es->luastate, -2, "dngettext");
132#endif 356#endif
357 lua_call(es->luastate, 1, 0);
358 return EINA_TRUE;
359}
360
361int _elua_module_init(lua_State *L);
362int _elua_module_system_init(lua_State *L);
363
364const luaL_reg _elua_cutillib[] =
365{
366 { "init_module", _elua_module_init },
367 { "popenv" , _elua_io_popen },
368 { NULL , NULL }
369};
370
371static Eina_Bool
372_elua_state_modules_setup(const Elua_State *es)
373{
374 char buf[PATH_MAX];
375 EINA_SAFETY_ON_NULL_RETURN_VAL(es, EINA_FALSE);
376 EINA_SAFETY_ON_NULL_RETURN_VAL(es->coredir, EINA_FALSE);
377 EINA_SAFETY_ON_NULL_RETURN_VAL(es->progname, EINA_FALSE);
378 snprintf(buf, sizeof(buf), "%s/module.lua", es->coredir);
379 if (elua_util_error_report(es, elua_io_loadfile(es, buf)))
380 return EINA_FALSE;
381 lua_pushcfunction(es->luastate, _elua_module_system_init);
382 lua_createtable(es->luastate, 0, 0);
383 luaL_register(es->luastate, NULL, _elua_cutillib);
384 lua_call(es->luastate, 2, 0);
385 return EINA_TRUE;
386}
387
388int
389_elua_module_init(lua_State *L)
390{
391 Elua_State *es = elua_state_from_lua_state_get(L);
392 if (!lua_isnoneornil(L, 1))
393 {
394 lua_pushvalue(L, 1);
395 lua_call(L, 0, 0);
396 }
397 if (!lua_isnoneornil(L, 2))
398 {
399 lua_pushvalue(L, 2);
400 es->cmods = eina_list_append(es->cmods,
401 (void*)(size_t)luaL_ref(L, LUA_REGISTRYINDEX));
402 }
403 return 0;
404}
405
406int
407_elua_module_system_init(lua_State *L)
408{
409 Elua_State *es = elua_state_from_lua_state_get(L);
410 const char *corepath = es->coredir;
411 const char *modpath = es->moddir;
412 const char *appspath = es->appsdir;
413 Eina_Stringshare *data = NULL;
414 int n = 3;
415 if (!corepath || !modpath || !appspath)
416 return 0;
417 lua_pushvalue(L, 1);
418 es->requireref = luaL_ref(L, LUA_REGISTRYINDEX);
419 lua_pushvalue(L, 2);
420 es->apploadref = luaL_ref(L, LUA_REGISTRYINDEX);
421 lua_pushfstring(L, "%s/?.lua;", corepath);
422 EINA_LIST_FREE(es->lincs, data)
423 {
424 lua_pushfstring(L, "%s/?.lua;", data);
425 eina_stringshare_del(data);
426 ++n;
427 }
428 lua_pushfstring(L, "%s/?.eo.lua;", modpath);
429 lua_pushfstring(L, "%s/?.lua;", modpath);
430 lua_pushvalue(L, 3);
431 lua_concat(L, n + 1);
432 lua_pushfstring(L, "%s/?.lua;", appspath);
433 lua_pushvalue(L, 4);
434 lua_concat(L, 2);
435 return 2;
436}
437
438EAPI Eina_Bool
439elua_state_setup(Elua_State *es)
440{
441 Eina_Stringshare *data;
442 Eina_Bool failed = EINA_FALSE;
443
444 if (!_elua_state_modules_setup(es))
445 return EINA_FALSE;
446 if (!_elua_state_i18n_setup(es))
447 return EINA_FALSE;
448 if (!_elua_state_io_setup(es))
449 return EINA_FALSE;
450
451 /* finally require the necessary modules */
452 EINA_LIST_FREE(es->lmods, data)
453 {
454 if (!failed)
455 {
456 if (!elua_state_require_ref_push(es))
457 {
458 failed = EINA_TRUE;
459 break;
460 }
461 lua_pushstring(es->luastate, data);
462 if (elua_util_error_report(es, lua_pcall(es->luastate, 1, 0, 0)))
463 {
464 failed = EINA_TRUE;
465 break;
466 }
467 }
468 eina_stringshare_del(data);
469 }
470
471 return EINA_TRUE;
472}
473
474/* Utility functions - these could be written using the other APIs */
475
476static int
477_elua_traceback(lua_State *L)
478{
479 lua_getglobal(L, "debug");
480 if (!lua_istable(L, -1))
481 {
482 lua_pop(L, 1);
483 return 1;
484 }
485 lua_getfield(L, -1, "traceback");
486 if (!lua_isfunction(L, -1))
487 {
488 lua_pop(L, 2);
489 return 1;
490 }
491 lua_pushvalue(L, 1);
492 lua_pushinteger(L, 2);
493 lua_call(L, 2, 1);
494 return 1;
495}
496
497static int
498_elua_docall(Elua_State *es, int narg, int nret)
499{
500 int status;
501 EINA_SAFETY_ON_NULL_RETURN_VAL(es, -1);
502 int bs = lua_gettop(es->luastate) - narg;
503 lua_pushcfunction(es->luastate, _elua_traceback);
504 lua_insert(es->luastate, bs);
505 status = lua_pcall(es->luastate, narg, nret, bs);
506 lua_remove(es->luastate, bs);
507 if (status)
508 lua_gc(es->luastate, LUA_GCCOLLECT, 0);
509 return status;
510}
511
512static int
513_elua_getargs(Elua_State *es, int argc, char **argv, int n)
514{
515 int i;
516 int narg = argc - (n + 1);
517 EINA_SAFETY_ON_NULL_RETURN_VAL(es, -1);
518 luaL_checkstack(es->luastate, narg + 3, "too many arguments to script");
519 for (i = n + 1; i < argc; ++i)
520 {
521 lua_pushstring(es->luastate, argv[i]);
522 }
523 lua_createtable(es->luastate, narg, n + 1);
524 for (i = 0; i < argc; ++i)
525 {
526 lua_pushstring(es->luastate, argv[i]);
527 lua_rawseti(es->luastate, -2, i - n);
528 }
529 return narg;
530}
531
532EAPI Eina_Bool
533elua_util_require(Elua_State *es, const char *libname)
534{
535 EINA_SAFETY_ON_NULL_RETURN_VAL(es, EINA_FALSE);
536 if (!elua_state_require_ref_push(es))
537 {
538 /* store stuff until things are correctly set up */
539 es->lmods = eina_list_append(es->lmods, eina_stringshare_add(libname));
540 return 0;
541 }
542 lua_pushstring(es->luastate, libname);
543 return !elua_util_error_report(es, lua_pcall(es->luastate, 1, 0, 0));
544}
545
546EAPI Eina_Bool
547elua_util_file_run(Elua_State *es, const char *fname)
548{
549 EINA_SAFETY_ON_NULL_RETURN_VAL(es, EINA_FALSE);
550 return !elua_util_error_report(es, elua_io_loadfile(es, fname)
551 || _elua_docall(es, 0, 1));
552}
553
554EAPI Eina_Bool
555elua_util_string_run(Elua_State *es, const char *chunk, const char *chname)
556{
557 EINA_SAFETY_ON_NULL_RETURN_VAL(es, EINA_FALSE);
558 return !elua_util_error_report(es, luaL_loadbuffer(es->luastate, chunk,
559 strlen(chunk), chname)
560 || _elua_docall(es, 0, 0));
561}
562
563EAPI int
564elua_util_app_load(Elua_State *es, const char *appname)
565{
566 EINA_SAFETY_ON_NULL_RETURN_VAL(es, -1);
567 EINA_SAFETY_ON_FALSE_RETURN_VAL(elua_state_appload_ref_push(es), -1);
568 lua_pushstring(es->luastate, appname);
569 lua_call(es->luastate, 1, 2);
570 if (lua_isnil(es->luastate, -2))
571 {
572 lua_remove(es->luastate, -2);
573 return 1;
574 }
575 lua_pop(es->luastate, 1);
576 return 0;
577}
578
579EAPI Eina_Bool
580elua_util_script_run(Elua_State *es, int argc, char **argv, int n, int *quit)
581{
582 int status, narg;
583 const char *fname;
584 EINA_SAFETY_ON_FALSE_RETURN_VAL(n < argc, -1);
585 EINA_SAFETY_ON_NULL_RETURN_VAL(es, -1);
586 fname = argv[n];
587 narg = _elua_getargs(es, argc, argv, n);
588 lua_setglobal(es->luastate, "arg");
589 if (fname[0] == '-' && !fname[1]) fname = NULL;
590 if (fname)
591 {
592 /* check if there is a file of that name */
593 FILE *f = fopen(fname, "r");
594 if (f)
595 {
596 fclose(f);
597 status = elua_io_loadfile(es, fname);
598 }
599 else
600 status = elua_util_app_load(es, fname);
601 }
602 else
603 status = elua_io_loadfile(es, fname);
604 lua_insert(es->luastate, -(narg + 1));
605 if (!status)
606 status = _elua_docall(es, narg, 1);
607 else
608 lua_pop(es->luastate, narg);
609 if (!status)
610 {
611 *quit = lua_toboolean(es->luastate, -1);
612 lua_pop(es->luastate, 1);
613 }
614 return !elua_util_error_report(es, status);
615}
616
617static void
618_elua_errmsg(const char *pname, const char *msg)
619{
620 ERR("%s%s%s", pname ? pname : "", pname ? ": " : "", msg);
621}
622
623EAPI int
624elua_util_error_report(const Elua_State *es, int status)
625{
626 EINA_SAFETY_ON_FALSE_RETURN_VAL(es, status);
627 if (status && !lua_isnil(es->luastate, -1))
628 {
629 const char *msg = lua_tostring(es->luastate, -1);
630 _elua_errmsg(es->progname, msg ? msg : "(non-string error)");
631 lua_pop(es->luastate, 1);
632 }
633 return status;
133} 634}
diff --git a/src/lib/elua/elua_private.h b/src/lib/elua/elua_private.h
index 0e1e9be515..01d8e4b1ac 100644
--- a/src/lib/elua/elua_private.h
+++ b/src/lib/elua/elua_private.h
@@ -5,8 +5,9 @@
5# include <config.h> 5# include <config.h>
6#endif 6#endif
7 7
8#include <locale.h>
9
8#ifdef ENABLE_NLS 10#ifdef ENABLE_NLS
9# include <locale.h>
10# include <libintl.h> 11# include <libintl.h>
11# define _(x) dgettext(PACKAGE, x) 12# define _(x) dgettext(PACKAGE, x)
12#else 13#else
@@ -27,6 +28,19 @@
27#include <lualib.h> 28#include <lualib.h>
28#include <lauxlib.h> 29#include <lauxlib.h>
29 30
31struct _Elua_State
32{
33 lua_State *luastate;
34 Eina_Stringshare *progname;
35 Eina_Stringshare *coredir;
36 Eina_Stringshare *moddir;
37 Eina_Stringshare *appsdir;
38 Eina_List *lmods;
39 Eina_List *cmods;
40 Eina_List *lincs;
41 int requireref, apploadref;
42};
43
30extern int _elua_log_dom; 44extern int _elua_log_dom;
31 45
32#define DBG(...) EINA_LOG_DOM_DBG(_elua_log_dom, __VA_ARGS__) 46#define DBG(...) EINA_LOG_DOM_DBG(_elua_log_dom, __VA_ARGS__)
@@ -35,4 +49,7 @@ extern int _elua_log_dom;
35#define ERR(...) EINA_LOG_DOM_ERR(_elua_log_dom, __VA_ARGS__) 49#define ERR(...) EINA_LOG_DOM_ERR(_elua_log_dom, __VA_ARGS__)
36#define CRT(...) EINA_LOG_DOM_CRITICAL(_elua_log_dom, __VA_ARGS__) 50#define CRT(...) EINA_LOG_DOM_CRITICAL(_elua_log_dom, __VA_ARGS__)
37 51
52int _elua_io_popen(lua_State *L);
53Eina_Bool _elua_state_io_setup(const Elua_State *es);
54
38#endif 55#endif
diff --git a/src/lib/elua/io.c b/src/lib/elua/io.c
index 4b73a3b789..91eef6f372 100644
--- a/src/lib/elua/io.c
+++ b/src/lib/elua/io.c
@@ -341,8 +341,8 @@ elua_newfile(lua_State *L)
341 return f; 341 return f;
342} 342}
343 343
344EAPI int 344int
345elua_io_popen(lua_State *L) 345_elua_io_popen(lua_State *L)
346{ 346{
347 const char *fname = luaL_checkstring(L, 1); 347 const char *fname = luaL_checkstring(L, 1);
348 const char *mode = luaL_optstring(L, 2, "r"); 348 const char *mode = luaL_optstring(L, 2, "r");
diff --git a/src/scripts/elua/core/gettext.lua b/src/scripts/elua/core/gettext.lua
index a77d50abc8..96af7d3941 100644
--- a/src/scripts/elua/core/gettext.lua
+++ b/src/scripts/elua/core/gettext.lua
@@ -7,7 +7,6 @@ local M = {}
7local gettext = ... 7local gettext = ...
8 8
9local bind_textdomain = gettext.bind_textdomain 9local bind_textdomain = gettext.bind_textdomain
10local bind_textdomain_codeset = gettext.bind_textdomain_codeset
11local dgettext = gettext.dgettext 10local dgettext = gettext.dgettext
12local dngettext = gettext.dngettext 11local dngettext = gettext.dngettext
13 12
diff --git a/src/tests/elua/elua_lib.c b/src/tests/elua/elua_lib.c
new file mode 100644
index 0000000000..82857270db
--- /dev/null
+++ b/src/tests/elua/elua_lib.c
@@ -0,0 +1,124 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#include <stdlib.h>
6#include <stdio.h>
7
8#include<Eina.h>
9#include "Elua.h"
10#include "elua_suite.h"
11
12START_TEST(elua_api)
13{
14 Elua_State *st;
15 lua_State *lst;
16 char buf[] = "tmpXXXXXX";
17 FILE *f;
18 int fd;
19 char *cargv[2];
20 char arg1[] = "test";
21 char arg2[] = "lualian";
22 int quit = 0;
23 cargv[0] = arg1;
24 cargv[1] = arg2;
25
26 fail_if(!elua_init());
27
28 st = elua_state_new("test");
29 fail_if(!st);
30
31 /* test env vars */
32 setenv("ELUA_CORE_DIR", "foo", 1);
33 setenv("ELUA_MODULES_DIR", "bar", 1);
34 setenv("ELUA_APPS_DIR", "baz", 1);
35 elua_state_dirs_fill(st, EINA_FALSE);
36 fail_if(strcmp(elua_state_core_dir_get(st), "foo"));
37 fail_if(strcmp(elua_state_mod_dir_get(st), "bar"));
38 fail_if(strcmp(elua_state_apps_dir_get(st), "baz"));
39 unsetenv("ELUA_CORE_DIR");
40 unsetenv("ELUA_MODULES_DIR");
41 unsetenv("ELUA_APPS_DIR");
42
43 /* now fill it properly */
44 elua_state_dirs_set(st, ELUA_CORE_DIR, ELUA_MODULES_DIR, ELUA_APPS_DIR);
45 fail_if(strcmp(elua_state_core_dir_get(st), ELUA_CORE_DIR));
46 fail_if(strcmp(elua_state_mod_dir_get(st), ELUA_MODULES_DIR));
47 fail_if(strcmp(elua_state_apps_dir_get(st), ELUA_APPS_DIR));
48
49 /* needed for later setup, but untestable alone */
50 elua_state_include_path_add(st, ELUA_BINDINGS_DIR);
51
52 lst = elua_state_lua_state_get(st);
53 fail_if(!lst);
54
55 fail_if(elua_state_from_lua_state_get(lst) != st);
56
57 fail_if(strcmp(elua_state_prog_name_get(st), "test"));
58
59 fail_if(!elua_state_setup(st));
60
61 fail_if(!elua_state_require_ref_push(st));
62 fail_if(lua_type(lst, -1) != LUA_TFUNCTION);
63 lua_pop(lst, 1);
64
65 fail_if(!elua_state_appload_ref_push(st));
66 fail_if(lua_type(lst, -1) != LUA_TFUNCTION);
67 lua_pop(lst, 1);
68
69 fail_if(!elua_util_require(st, "util"));
70 fail_if(!elua_util_string_run(st, "return 1337", "foo"));
71 fail_if(elua_util_string_run(st, "foo bar", "foo")); /* invalid code */
72 fail_if(elua_util_app_load(st, "lualian"));
73 fail_if(lua_type(lst, -1) != LUA_TFUNCTION);
74 lua_pop(lst, 1);
75 fail_if(!elua_util_app_load(st, "non_existent_app"));
76 fail_if(lua_type(lst, -1) != LUA_TSTRING);
77 lua_pop(lst, 1);
78 fail_if(elua_io_loadfile(st, ELUA_CORE_DIR "/util.lua"));
79 fail_if(lua_type(lst, -1) != LUA_TFUNCTION);
80 lua_pop(lst, 1);
81 fail_if(!elua_io_loadfile(st, ELUA_CORE_DIR "/non_existent_file.lua"));
82 fail_if(lua_type(lst, -1) != LUA_TSTRING);
83 lua_pop(lst, 1);
84
85 fd = mkstemp(buf);
86 fail_if(fd < 0);
87 f = fdopen(fd, "w");
88 fail_if(!f);
89 fprintf(f, "return 5\n");
90 fclose(f);
91 fail_if(!elua_util_file_run(st, buf));
92 fail_if(lua_tointeger(lst, -1) != 5);
93 lua_pop(lst, 1);
94 fail_if(remove(buf));
95
96 /* halfassed testing here, but not possible otherwise */
97 fail_if(elua_util_error_report(st, 0));
98 lua_pushliteral(lst, "msg");
99 fail_if(!elua_util_error_report(st, 5));
100 fail_if(lua_gettop(lst) > 0);
101
102 fail_if(!elua_util_script_run(st, 2, cargv, 1, &quit));
103 fail_if(quit != 1);
104
105 f = fopen(buf, "w");
106 fail_if(!f);
107 fprintf(f, "return false");
108 fclose(f);
109 cargv[1] = buf;
110 fail_if(!elua_util_script_run(st, 2, cargv, 1, &quit));
111 fail_if(quit != 0);
112 fail_if(remove(buf));
113
114 elua_state_free(st);
115
116 elua_shutdown();
117}
118END_TEST
119
120void elua_lib_test(TCase *tc)
121{
122 tcase_add_test(tc, elua_api);
123}
124
diff --git a/src/tests/elua/elua_suite.c b/src/tests/elua/elua_suite.c
new file mode 100644
index 0000000000..13a6df8f85
--- /dev/null
+++ b/src/tests/elua/elua_suite.c
@@ -0,0 +1,108 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#include <stdlib.h>
6#include <stdio.h>
7
8#include<Eina.h>
9#include "elua_suite.h"
10
11typedef struct _Elua_Test_Case Elua_Test_Case;
12
13struct _Elua_Test_Case
14{
15 const char *test_case;
16 void (*build)(TCase *tc);
17};
18
19static const Elua_Test_Case etc[] = {
20 { "Elua Library", elua_lib_test},
21 { NULL, NULL }
22};
23
24static void
25_list_tests(void)
26{
27 const Elua_Test_Case *itr;
28
29 itr = etc;
30 fputs("Available Test Cases:\n", stderr);
31 for (; itr->test_case; itr++)
32 fprintf(stderr, "\t%s\n", itr->test_case);
33}
34
35static Eina_Bool
36_use_test(int argc, const char **argv, const char *test_case)
37{
38 if (argc < 1)
39 return 1;
40
41 for (; argc > 0; argc--, argv++)
42 if (strcmp(test_case, *argv) == 0)
43 return 1;
44 return 0;
45}
46
47static Suite *
48elua_suite_build(int argc, const char **argv)
49{
50 TCase *tc;
51 Suite *s;
52 int i;
53
54 s = suite_create("Elua");
55
56 for (i = 0; etc[i].test_case; ++i)
57 {
58 if (!_use_test(argc, argv, etc[i].test_case)) continue;
59 tc = tcase_create(etc[i].test_case);
60
61 etc[i].build(tc);
62
63 suite_add_tcase(s, tc);
64#ifndef _WIN32
65 tcase_set_timeout(tc, 0);
66#endif
67 }
68
69 return s;
70}
71
72int
73main(int argc, char **argv)
74{
75 Suite *s;
76 SRunner *sr;
77 int i, failed_count;
78 setenv("CK_FORK", "no", 0);
79
80 for (i = 1; i < argc; i++)
81 if ((strcmp(argv[i], "-h" ) == 0) ||
82 (strcmp(argv[i], "--help") == 0))
83 {
84 fprintf(stderr, "Usage:\n\t%s [test_case1 .. [test_caseN]]\n",
85 argv[0]);
86 _list_tests();
87 return 0;
88 }
89 else if ((strcmp(argv[i], "-l" ) == 0) ||
90 (strcmp(argv[i], "--list") == 0))
91 {
92 _list_tests();
93 return 0;
94 }
95
96 putenv("EFL_RUN_IN_TREE=1");
97
98 s = elua_suite_build(argc - 1, (const char **)argv + 1);
99 sr = srunner_create(s);
100
101 srunner_set_xml(sr, TESTS_BUILD_DIR "/check-results.xml");
102
103 srunner_run_all(sr, CK_ENV);
104 failed_count = srunner_ntests_failed(sr);
105 srunner_free(sr);
106
107 return (failed_count == 0) ? 0 : 255;
108}
diff --git a/src/tests/elua/elua_suite.h b/src/tests/elua/elua_suite.h
new file mode 100644
index 0000000000..0d48d02617
--- /dev/null
+++ b/src/tests/elua/elua_suite.h
@@ -0,0 +1,9 @@
1#ifndef _ELUA_SUITE_H
2#define _ELUA_SUITE_H
3
4#include <check.h>
5
6void elua_lib_test(TCase *tc);
7
8#endif /* _ELUA_SUITE_H */
9