forked from enlightenment/efl
Elua: initial commit
Elua is a LuaJIT based runtime for the EFL meant to provide facilities for rapid application development. The name is temporary. The EFL bindings will be generated with Eolian. @feature
This commit is contained in:
parent
3e81b73aa8
commit
832f652a5a
46
configure.ac
46
configure.ac
|
@ -4307,6 +4307,51 @@ EFL_EVAL_PKGS([ETHUMB_CLIENT])
|
||||||
EFL_LIB_END_OPTIONAL([Ethumb_Client])
|
EFL_LIB_END_OPTIONAL([Ethumb_Client])
|
||||||
#### End of Ethumb_Client
|
#### End of Ethumb_Client
|
||||||
|
|
||||||
|
#### Elua
|
||||||
|
|
||||||
|
have_elua="yes"
|
||||||
|
if test "${want_lua_old}" = "yes"; then
|
||||||
|
have_elua="no"
|
||||||
|
fi
|
||||||
|
|
||||||
|
EFL_LIB_START_OPTIONAL([Elua], [test "${have_elua}" = "yes"])
|
||||||
|
|
||||||
|
### Default values
|
||||||
|
|
||||||
|
AM_CONDITIONAL([HAVE_ELUA], [test "x${have_elua}" = "xyes"])
|
||||||
|
|
||||||
|
### Additional options to configure
|
||||||
|
|
||||||
|
### Checks for programs
|
||||||
|
|
||||||
|
## Compatibility layers
|
||||||
|
EFL_PLATFORM_DEPEND([ELUA], [evil])
|
||||||
|
|
||||||
|
### Checks for libraries
|
||||||
|
EFL_INTERNAL_DEPEND_PKG([ELUA], [eina])
|
||||||
|
EFL_INTERNAL_DEPEND_PKG([ELUA], [eo])
|
||||||
|
EFL_INTERNAL_DEPEND_PKG([ELUA], [ecore])
|
||||||
|
|
||||||
|
EFL_DEPEND_PKG([ELUA], [LUAJIT], [luajit >= 2.0.0])
|
||||||
|
|
||||||
|
EFL_EVAL_PKGS([ELUA])
|
||||||
|
|
||||||
|
### Checks for header files
|
||||||
|
|
||||||
|
### Checks for types
|
||||||
|
|
||||||
|
### Checks for structures
|
||||||
|
|
||||||
|
### Checks for compiler characteristics
|
||||||
|
|
||||||
|
### Checks for linker characteristics
|
||||||
|
|
||||||
|
### Checks for library functions
|
||||||
|
|
||||||
|
### Check availability
|
||||||
|
|
||||||
|
EFL_LIB_END_OPTIONAL([Elua])
|
||||||
|
#### End of Elua
|
||||||
|
|
||||||
AC_ARG_ENABLE([always-build-examples],
|
AC_ARG_ENABLE([always-build-examples],
|
||||||
[AC_HELP_STRING([--enable-always-build-examples],
|
[AC_HELP_STRING([--enable-always-build-examples],
|
||||||
|
@ -4567,6 +4612,7 @@ echo "Edje............: ${efl_lib_optional_edje} (${features_edje})"
|
||||||
echo "Emotion.........: ${efl_lib_optional_emotion} (${features_emotion})"
|
echo "Emotion.........: ${efl_lib_optional_emotion} (${features_emotion})"
|
||||||
echo "Ethumb..........: ${efl_lib_optional_ethumb}"
|
echo "Ethumb..........: ${efl_lib_optional_ethumb}"
|
||||||
echo "Ethumb_Client...: ${efl_lib_optional_ethumb_client}"
|
echo "Ethumb_Client...: ${efl_lib_optional_ethumb_client}"
|
||||||
|
echo "Elua............: $have_elua"
|
||||||
if test "${build_tests}" = "none"; then
|
if test "${build_tests}" = "none"; then
|
||||||
echo "Tests...........: no"
|
echo "Tests...........: no"
|
||||||
elif test "${build_tests}" = "auto"; then
|
elif test "${build_tests}" = "auto"; then
|
||||||
|
|
|
@ -79,6 +79,8 @@ include Makefile_Eolian_Cxx.am
|
||||||
include Makefile_Eet_Cxx.am
|
include Makefile_Eet_Cxx.am
|
||||||
include Makefile_Eo_Cxx.am
|
include Makefile_Eo_Cxx.am
|
||||||
|
|
||||||
|
include Makefile_Elua.am
|
||||||
|
|
||||||
.PHONY: benchmark examples
|
.PHONY: benchmark examples
|
||||||
|
|
||||||
BENCHMARK_SUBDIRS = \
|
BENCHMARK_SUBDIRS = \
|
||||||
|
@ -105,7 +107,8 @@ examples/eldbus \
|
||||||
examples/ephysics \
|
examples/ephysics \
|
||||||
examples/edje \
|
examples/edje \
|
||||||
examples/emotion \
|
examples/emotion \
|
||||||
examples/ethumb_client
|
examples/ethumb_client \
|
||||||
|
examples/elua
|
||||||
|
|
||||||
if HAVE_CXX11
|
if HAVE_CXX11
|
||||||
EXAMPLES_SUBDIRS += \
|
EXAMPLES_SUBDIRS += \
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
if HAVE_ELUA
|
||||||
|
|
||||||
|
bin_PROGRAMS += bin/elua/elua
|
||||||
|
|
||||||
|
bin_elua_elua_SOURCES = \
|
||||||
|
bin/elua/cache.c \
|
||||||
|
bin/elua/main.c
|
||||||
|
|
||||||
|
bin_elua_elua_CPPFLAGS = -I$(top_builddir)/src/lib/efl \
|
||||||
|
-DELUA_DATA_DIR="\"$(datadir)/elua\"" @ELUA_CFLAGS@
|
||||||
|
bin_elua_elua_LDADD = @ELUA_LIBS@
|
||||||
|
bin_elua_elua_DEPENDENCIES = @ELUA_INTERNAL_LIBS@
|
||||||
|
|
||||||
|
eluamodulesdir = $(datadir)/elua/modules
|
||||||
|
eluamodules_DATA = bin/elua/elm.lua
|
||||||
|
EXTRA_DIST += $(eluamodules_DATA)
|
||||||
|
|
||||||
|
eluacoredir = $(datadir)/elua/core
|
||||||
|
eluacore_DATA = bin/elua/module.lua
|
||||||
|
EXTRA_DIST += $(eluacore_DATA)
|
||||||
|
|
||||||
|
endif
|
|
@ -0,0 +1,192 @@
|
||||||
|
/* elua bytecode caching */
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "main.h"
|
||||||
|
|
||||||
|
/* bytecode caching */
|
||||||
|
|
||||||
|
static int check_bc(const char *fname, const char *mode, Eina_Bool *bc) {
|
||||||
|
const char *ext = strstr(fname, ".lua");
|
||||||
|
if (ext && !ext[4] && (!mode || strchr(mode, 't'))) {
|
||||||
|
/* loading lua source file, try cached */
|
||||||
|
char buf[PATH_MAX];
|
||||||
|
snprintf(buf, sizeof(buf), "%sc", fname);
|
||||||
|
int fd = open(buf, O_RDONLY);
|
||||||
|
if (fd < 0) {
|
||||||
|
/* no cached bytecode */
|
||||||
|
*bc = EINA_TRUE;
|
||||||
|
} else {
|
||||||
|
/* cached bytecode, check timestamp */
|
||||||
|
struct stat s1, s2;
|
||||||
|
stat(fname, &s1);
|
||||||
|
stat(buf, &s2);
|
||||||
|
if (s2.st_ctime > s1.st_ctime) {
|
||||||
|
/* bytecode new enough, chunkname stays the same */
|
||||||
|
return fd;
|
||||||
|
} else {
|
||||||
|
/* bytecode too old, remove old file */
|
||||||
|
close(fd);
|
||||||
|
*bc = EINA_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int writef(lua_State *L EINA_UNUSED, const void *p, size_t size,
|
||||||
|
void *ud) {
|
||||||
|
FILE *f = ud;
|
||||||
|
return ferror(f) || (fwrite(p, 1, size, f) != size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write_bc(lua_State *L, const char *fname) {
|
||||||
|
char buf[PATH_MAX];
|
||||||
|
snprintf(buf, sizeof(buf), "%sc", fname);
|
||||||
|
FILE *f = fopen(buf, "wb");
|
||||||
|
if (f) {
|
||||||
|
if (lua_dump(L, writef, f)) {
|
||||||
|
fclose(f);
|
||||||
|
remove(buf);
|
||||||
|
} else fclose(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* loadfile - regular version */
|
||||||
|
|
||||||
|
typedef struct Cached_Stream {
|
||||||
|
FILE *f;
|
||||||
|
char buff[LUAL_BUFFERSIZE];
|
||||||
|
} Cached_Stream;
|
||||||
|
|
||||||
|
static const char *getf(lua_State *L EINA_UNUSED, void *ud, size_t *size) {
|
||||||
|
Cached_Stream *s = ud;
|
||||||
|
if (feof(s->f)) return NULL;
|
||||||
|
*size = fread(s->buff, 1, sizeof(s->buff), s->f);
|
||||||
|
return (*size > 0) ? s->buff : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int elua_loadfilex(lua_State *L, const char *fname, const char *mode) {
|
||||||
|
Cached_Stream s;
|
||||||
|
int status;
|
||||||
|
const char *chname;
|
||||||
|
Eina_Bool bcache = EINA_FALSE;
|
||||||
|
if (!fname) {
|
||||||
|
s.f = stdin;
|
||||||
|
chname = "=stdin";
|
||||||
|
} else {
|
||||||
|
if (!(s.f = fopen(fname, "rb"))) {
|
||||||
|
lua_pushfstring(L, "cannot open %s: %s", fname, strerror(errno));
|
||||||
|
return LUA_ERRFILE;
|
||||||
|
}
|
||||||
|
chname = lua_pushfstring(L, "@%s", fname);
|
||||||
|
int fd = check_bc(fname, mode, &bcache);
|
||||||
|
if (fd >= 0) {
|
||||||
|
fclose(s.f);
|
||||||
|
s.f = fdopen(fd, "rb");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
status = lua_loadx(L, getf, &s, chname, mode);
|
||||||
|
if (ferror(s.f)) {
|
||||||
|
lua_pop(L, 1);
|
||||||
|
lua_pushfstring(L, "cannot read %s: %s", chname + 1, strerror(errno));
|
||||||
|
if (fname) {
|
||||||
|
lua_remove(L, -2);
|
||||||
|
fclose(s.f);
|
||||||
|
}
|
||||||
|
return LUA_ERRFILE;
|
||||||
|
}
|
||||||
|
/* trigger bytecode writing */
|
||||||
|
if (!status && bcache) write_bc(L, fname);
|
||||||
|
if (fname) {
|
||||||
|
lua_remove(L, -2);
|
||||||
|
fclose(s.f);
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
int elua_loadfile(lua_State *L, const char *fname) {
|
||||||
|
return elua_loadfilex(L, fname, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* loadfile - mmap version */
|
||||||
|
|
||||||
|
typedef struct Map_Stream {
|
||||||
|
char *fmap;
|
||||||
|
size_t flen;
|
||||||
|
} Map_Stream;
|
||||||
|
|
||||||
|
static const char *getf_map(lua_State *L EINA_UNUSED, void *ud, size_t *size) {
|
||||||
|
Map_Stream *s = ud;
|
||||||
|
*size = s->flen;
|
||||||
|
return s->fmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
int elua_loadfilex_mmap(lua_State *L, const char *fname, const char *mode) {
|
||||||
|
Map_Stream s;
|
||||||
|
int status, fd, nfd;
|
||||||
|
const char *chname;
|
||||||
|
Eina_Bool bcache = EINA_FALSE;
|
||||||
|
if (!fname) {
|
||||||
|
return elua_loadfilex(L, fname, mode);
|
||||||
|
}
|
||||||
|
if ((fd = open(fname, O_RDONLY, 0)) < 0) {
|
||||||
|
lua_pushfstring(L, "cannot open %s: %s", fname, strerror(errno));
|
||||||
|
return LUA_ERRFILE;
|
||||||
|
}
|
||||||
|
chname = lua_pushfstring(L, "@%s", fname);
|
||||||
|
if ((nfd = check_bc(fname, mode, &bcache)) > 0) {
|
||||||
|
close(fd);
|
||||||
|
fd = nfd;
|
||||||
|
}
|
||||||
|
s.flen = lseek(fd, 0, SEEK_END);
|
||||||
|
lseek(fd, 0, SEEK_SET);
|
||||||
|
if ((s.fmap = mmap(NULL, s.flen, PROT_READ, MAP_FILE|MAP_PRIVATE, fd, 0))
|
||||||
|
== MAP_FAILED) {
|
||||||
|
lua_pushfstring(L, "cannot read %s: %s", chname + 1, strerror(errno));
|
||||||
|
lua_remove(L, -2);
|
||||||
|
return LUA_ERRFILE;
|
||||||
|
}
|
||||||
|
status = lua_loadx(L, getf_map, &s, chname, mode);
|
||||||
|
munmap(s.fmap, s.flen);
|
||||||
|
close(fd);
|
||||||
|
if (!status && bcache) write_bc(L, fname);
|
||||||
|
lua_remove(L, -2);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
int elua_loadfile_mmap(lua_State *L, const char *fname) {
|
||||||
|
return elua_loadfilex_mmap(L, fname, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* lua function */
|
||||||
|
|
||||||
|
static int loadfile(lua_State *L) {
|
||||||
|
const char *fname = luaL_optstring(L, 1, NULL);
|
||||||
|
const char *mode = luaL_optstring(L, 2, NULL);
|
||||||
|
int status, hasenv = (lua_gettop(L) >= 3);
|
||||||
|
if (lua_toboolean(L, 4)) {
|
||||||
|
status = elua_loadfilex_mmap(L, fname, mode);
|
||||||
|
} else {
|
||||||
|
status = elua_loadfilex(L, fname, mode);
|
||||||
|
}
|
||||||
|
if (!status) {
|
||||||
|
if (hasenv) {
|
||||||
|
lua_pushvalue(L, 3);
|
||||||
|
lua_setfenv(L, -2);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_insert(L, -2);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void elua_register_cache(lua_State *L) {
|
||||||
|
lua_pushcfunction(L, loadfile);
|
||||||
|
lua_setglobal(L, "loadfile");
|
||||||
|
}
|
|
@ -0,0 +1,129 @@
|
||||||
|
local ffi = require("ffi")
|
||||||
|
local util = erequire("util")
|
||||||
|
|
||||||
|
local elm, evas
|
||||||
|
|
||||||
|
local M = {}
|
||||||
|
|
||||||
|
ffi.cdef [[
|
||||||
|
typedef struct Evas_Object Evas_Object;
|
||||||
|
|
||||||
|
typedef void(*Evas_Smart_Cb)(void *data, Evas_Object *obj, void *event_info);
|
||||||
|
|
||||||
|
int elm_init(int argc, char **argv);
|
||||||
|
int elm_exit(void);
|
||||||
|
|
||||||
|
Evas_Object *elm_win_add(Evas_Object *parent, const char *name, int type);
|
||||||
|
void elm_win_title_set(Evas_Object *obj, const char *title);
|
||||||
|
void elm_win_resize_object_add(Evas_Object *obj, Evas_Object *subobj);
|
||||||
|
|
||||||
|
Evas_Object *elm_bg_add(Evas_Object *parent);
|
||||||
|
Evas_Object *elm_label_add(Evas_Object *parent);
|
||||||
|
Evas_Object *elm_button_add(Evas_Object *parent);
|
||||||
|
Evas_Object *elm_box_add(Evas_Object *parent);
|
||||||
|
void elm_box_pack_end(Evas_Object *obj, Evas_Object *subobj);
|
||||||
|
void elm_object_part_text_set(Evas_Object *obj, const char *part, const char *text);
|
||||||
|
|
||||||
|
void evas_object_show(Evas_Object *obj);
|
||||||
|
void evas_object_size_hint_weight_set(Evas_Object *obj, double x, double y);
|
||||||
|
void evas_object_resize(Evas_Object *obj, int w, int h);
|
||||||
|
|
||||||
|
void evas_object_smart_callback_add(Evas_Object *obj, const char *event, Evas_Smart_Cb func, const void *data);
|
||||||
|
void evas_object_smart_callback_del_full(Evas_Object *obj, const char *event, Evas_Smart_Cb func, const void *data);
|
||||||
|
]]
|
||||||
|
|
||||||
|
local callbacks = {}
|
||||||
|
|
||||||
|
local smart_cb_wrapper = ffi.cast("Evas_Smart_Cb",
|
||||||
|
util.register_callbacks(callbacks))
|
||||||
|
|
||||||
|
util.init_module(function()
|
||||||
|
elm, evas = ffi.load("elementary"), ffi.load("evas")
|
||||||
|
elm.elm_init(0, nil)
|
||||||
|
end, function()
|
||||||
|
elm.elm_exit()
|
||||||
|
end)
|
||||||
|
|
||||||
|
local Evas_Object = {
|
||||||
|
resize = function(self, w, h)
|
||||||
|
evas.evas_object_resize(self.__o, w, h)
|
||||||
|
end,
|
||||||
|
show = function(self) evas.evas_object_show(self.__o) end,
|
||||||
|
size_hint_weight_set = function(self, x, y)
|
||||||
|
evas.evas_object_size_hint_weight_set(self.__o, x, y)
|
||||||
|
end,
|
||||||
|
smart_callback_add = function(self, ev, cb)
|
||||||
|
local cbt = callbacks[cb]
|
||||||
|
if not cbt then
|
||||||
|
callbacks[#callbacks + 1] = cb
|
||||||
|
cbt = { #callbacks, 0 }
|
||||||
|
callbacks[cb] = cbt
|
||||||
|
end
|
||||||
|
cbt[2] = cbt[2] + 1
|
||||||
|
evas.evas_object_smart_callback_add(self.__o, ev, smart_cb_wrapper,
|
||||||
|
ffi.cast("void*", cbt[1]))
|
||||||
|
end,
|
||||||
|
smart_callback_del = function(self, ev, cb)
|
||||||
|
local cbt = callbacks[cb]
|
||||||
|
if not cbt then return end
|
||||||
|
local cbi = cbt[1]
|
||||||
|
evas.evas_object_smart_callback_del_full(self.__o, ev, smart_cb_wrapper,
|
||||||
|
ffi.cast("void*", cbi))
|
||||||
|
local cnt = cbt[2] - 1
|
||||||
|
if cnt == 0 then
|
||||||
|
callbacks[cbi], callbacks[cb] = nil, nil
|
||||||
|
else
|
||||||
|
cbt[2] = cnt
|
||||||
|
end
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
M.Window = function(name, title)
|
||||||
|
local o = setmetatable({
|
||||||
|
__o = elm.elm_win_add(nil, name, 0),
|
||||||
|
resize_object_add = function(self, o)
|
||||||
|
elm.elm_win_resize_object_add(self.__o, o.__o)
|
||||||
|
end
|
||||||
|
}, { __index = Evas_Object })
|
||||||
|
elm.elm_win_title_set(o.__o, title)
|
||||||
|
return o
|
||||||
|
end
|
||||||
|
|
||||||
|
M.Background = function(parent)
|
||||||
|
return setmetatable({
|
||||||
|
__o = elm.elm_bg_add(parent.__o)
|
||||||
|
}, { __index = Evas_Object })
|
||||||
|
end
|
||||||
|
|
||||||
|
M.Label = function(parent)
|
||||||
|
return setmetatable({
|
||||||
|
__o = elm.elm_label_add(parent.__o),
|
||||||
|
text_set = function(self, label)
|
||||||
|
elm.elm_object_part_text_set(self.__o, nil, label)
|
||||||
|
end
|
||||||
|
}, { __index = Evas_Object })
|
||||||
|
end
|
||||||
|
|
||||||
|
M.Button = function(parent)
|
||||||
|
return setmetatable({
|
||||||
|
__o = elm.elm_button_add(parent.__o),
|
||||||
|
text_set = function(self, label)
|
||||||
|
elm.elm_object_part_text_set(self.__o, nil, label)
|
||||||
|
end
|
||||||
|
}, { __index = Evas_Object })
|
||||||
|
end
|
||||||
|
|
||||||
|
M.Box = function(parent)
|
||||||
|
return setmetatable({
|
||||||
|
__o = elm.elm_box_add(parent.__o),
|
||||||
|
pack_end = function(self, obj)
|
||||||
|
elm.elm_box_pack_end(self.__o, obj.__o)
|
||||||
|
end
|
||||||
|
}, { __index = Evas_Object })
|
||||||
|
end
|
||||||
|
|
||||||
|
M.exit = function()
|
||||||
|
elm.elm_exit()
|
||||||
|
end
|
||||||
|
|
||||||
|
_G["elm"] = M
|
|
@ -0,0 +1,328 @@
|
||||||
|
/* The Lua runtime component of the EFL */
|
||||||
|
|
||||||
|
#include "main.h"
|
||||||
|
|
||||||
|
static Eina_List *modlist = NULL;
|
||||||
|
static int require_ref = LUA_REFNIL;
|
||||||
|
|
||||||
|
int el_log_domain = -1;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ARG_CODE = 0, ARG_MODULE, ARG_LIBRARY
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct Arg_Data {
|
||||||
|
int type;
|
||||||
|
const char *value;
|
||||||
|
} Arg_Data;
|
||||||
|
|
||||||
|
static Eina_Bool append_cb(const Ecore_Getopt *parser EINA_UNUSED,
|
||||||
|
const Ecore_Getopt_Desc *desc EINA_UNUSED,
|
||||||
|
const char *str,
|
||||||
|
void *data,
|
||||||
|
Ecore_Getopt_Value *val)
|
||||||
|
{
|
||||||
|
Eina_List **l = val->listp;
|
||||||
|
Arg_Data *v = malloc(sizeof(Arg_Data));
|
||||||
|
v->type = (size_t)data;
|
||||||
|
v->value = str;
|
||||||
|
*l = eina_list_append(*l, v);
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Ecore_Getopt opt = {
|
||||||
|
"elua", "%prog [options] [script [args]]", "0.0.1", "See COPYING",
|
||||||
|
"See COPYING", "A main entry for all EFL/LuaJIT powered applications.",
|
||||||
|
0, {
|
||||||
|
ECORE_GETOPT_LICENSE('L', "license"),
|
||||||
|
ECORE_GETOPT_COPYRIGHT('c', "copyright"),
|
||||||
|
ECORE_GETOPT_VERSION('v', "version"),
|
||||||
|
ECORE_GETOPT_HELP('h', "help"),
|
||||||
|
|
||||||
|
ECORE_GETOPT_CALLBACK_ARGS('e', "execute", "Execute string "
|
||||||
|
"'code'.", "CODE", append_cb, (void*)ARG_CODE),
|
||||||
|
ECORE_GETOPT_CALLBACK_ARGS('m', "module", "Include module 'module'.",
|
||||||
|
"MODULE", append_cb, (void*)ARG_MODULE),
|
||||||
|
ECORE_GETOPT_CALLBACK_ARGS('l', "library", "Require library 'library'.",
|
||||||
|
"LIBRARY", append_cb, (void*)ARG_LIBRARY),
|
||||||
|
ECORE_GETOPT_STORE_TRUE('E', "noenv", "Ignore environment vars."),
|
||||||
|
|
||||||
|
ECORE_GETOPT_SENTINEL
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static void errmsg(const char *pname, const char *msg) {
|
||||||
|
ERR("%s%s%s", pname ? pname : "", pname ? ": " : "", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int report(lua_State *L, int status) {
|
||||||
|
if (status && !lua_isnil(L, -1)) {
|
||||||
|
const char *msg = lua_tostring(L, -1);
|
||||||
|
errmsg(opt.prog, msg ? msg : "(non-string error)");
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int traceback(lua_State *L) {
|
||||||
|
lua_getglobal(L, "debug");
|
||||||
|
if (!lua_istable(L, -1)) {
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
lua_getfield(L, -1, "traceback");
|
||||||
|
if (!lua_isfunction(L, -1)) {
|
||||||
|
lua_pop(L, 2);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
lua_pushvalue(L, 1);
|
||||||
|
lua_pushinteger(L, 2);
|
||||||
|
lua_call(L, 2, 1);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int docall(lua_State *L, int narg) {
|
||||||
|
int status;
|
||||||
|
int bs = lua_gettop(L) - narg;
|
||||||
|
lua_pushcfunction(L, traceback);
|
||||||
|
lua_insert(L, bs);
|
||||||
|
status = lua_pcall(L, narg, 0, bs);
|
||||||
|
lua_remove(L, bs);
|
||||||
|
if (status) lua_gc(L, LUA_GCCOLLECT, 0);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getargs(lua_State *L, int argc, char **argv, int n) {
|
||||||
|
int i;
|
||||||
|
int narg = argc - (n + 1);
|
||||||
|
luaL_checkstack(L, narg + 3, "too many arguments to script");
|
||||||
|
for (i = n + 1; i < argc; ++i) lua_pushstring(L, argv[i]);
|
||||||
|
lua_createtable(L, narg, n + 1);
|
||||||
|
for (i = 0; i < argc; ++i) {
|
||||||
|
lua_pushstring(L, argv[i]);
|
||||||
|
lua_rawseti(L, -2, i - n);
|
||||||
|
}
|
||||||
|
return narg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int init_module(lua_State *L) {
|
||||||
|
if (!lua_isnoneornil(L, 1)) {
|
||||||
|
lua_pushvalue(L, 1);
|
||||||
|
lua_call(L, 0, 0);
|
||||||
|
}
|
||||||
|
if (!lua_isnoneornil(L, 2)) {
|
||||||
|
lua_pushvalue(L, 2);
|
||||||
|
modlist = eina_list_append(modlist,
|
||||||
|
(void*)(size_t)luaL_ref(L, LUA_REGISTRYINDEX));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int register_require(lua_State *L) {
|
||||||
|
lua_pushvalue(L, 1);
|
||||||
|
require_ref = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||||
|
lua_pushliteral(L, ELUA_DATA_DIR "/core/?.lua;");
|
||||||
|
lua_pushliteral(L, ELUA_DATA_DIR "/modules/?.lua;");
|
||||||
|
lua_pushvalue(L, 2);
|
||||||
|
lua_concat(L, 3);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dolib(lua_State *L, const char *libname) {
|
||||||
|
lua_rawgeti(L, LUA_REGISTRYINDEX, require_ref);
|
||||||
|
lua_pushstring(L, libname);
|
||||||
|
return report(L, lua_pcall(L, 1, 0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dofile(lua_State *L, const char *fname) {
|
||||||
|
return report(L, elua_loadfile(L, fname) || docall(L, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dostr(lua_State *L, const char *chunk, const char *chname) {
|
||||||
|
return report(L, luaL_loadbuffer(L, chunk, strlen(chunk), chname)
|
||||||
|
|| docall(L, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int doscript(lua_State *L, int argc, char **argv, int n) {
|
||||||
|
int status;
|
||||||
|
const char *fname = argv[n];
|
||||||
|
int narg = getargs(L, argc, argv, n);
|
||||||
|
lua_setglobal(L, "arg");
|
||||||
|
if (fname[0] == '-' && !fname[1]) {
|
||||||
|
fname = NULL;
|
||||||
|
}
|
||||||
|
status = elua_loadfile(L, fname);
|
||||||
|
lua_insert(L, -(narg + 1));
|
||||||
|
if (!status) {
|
||||||
|
status = docall(L, narg);
|
||||||
|
} else {
|
||||||
|
lua_pop(L, narg);
|
||||||
|
}
|
||||||
|
return report(L, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
void shutdown(lua_State *L, int c) {
|
||||||
|
void *data;
|
||||||
|
INF("elua shutdown");
|
||||||
|
|
||||||
|
EINA_LIST_FREE(modlist, data) {
|
||||||
|
lua_rawgeti(L, LUA_REGISTRYINDEX, (size_t)data);
|
||||||
|
lua_call(L, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (L) lua_close(L);
|
||||||
|
eina_shutdown();
|
||||||
|
exit(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cb_ref = LUA_REFNIL;
|
||||||
|
static lua_State *LL = NULL;
|
||||||
|
|
||||||
|
static void smart_cb_wrapper(void *data, void *obj EINA_UNUSED,
|
||||||
|
void *einfo EINA_UNUSED) {
|
||||||
|
int idx = (size_t)data;
|
||||||
|
lua_rawgeti(LL, LUA_REGISTRYINDEX, cb_ref);
|
||||||
|
lua_rawgeti(LL, -1, idx);
|
||||||
|
lua_call(LL, 0, 0);
|
||||||
|
lua_pop(LL, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int register_callbacks(lua_State *L) {
|
||||||
|
union { void (*fptr)(void*, void*, void*); void *ptr; } u;
|
||||||
|
lua_pushvalue(L, 1);
|
||||||
|
cb_ref = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||||
|
u.fptr = smart_cb_wrapper;
|
||||||
|
lua_pushlightuserdata(L, u.ptr);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Main_Data {
|
||||||
|
int argc;
|
||||||
|
char **argv;
|
||||||
|
int status;
|
||||||
|
};
|
||||||
|
|
||||||
|
const luaL_reg utillib[] = {
|
||||||
|
{ "init_module", init_module },
|
||||||
|
{ "register_callbacks", register_callbacks },
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
/* protected main */
|
||||||
|
static int lua_main(lua_State *L) {
|
||||||
|
Eina_Bool quit = EINA_FALSE,
|
||||||
|
noenv = EINA_FALSE,
|
||||||
|
hasexec = EINA_FALSE;
|
||||||
|
Eina_List *largs = NULL, *l = NULL;
|
||||||
|
Arg_Data *data = NULL;
|
||||||
|
|
||||||
|
int nonopt;
|
||||||
|
|
||||||
|
struct Main_Data *m = (struct Main_Data*)lua_touserdata(L, 1);
|
||||||
|
|
||||||
|
int argc = m->argc;
|
||||||
|
char **argv = m->argv;
|
||||||
|
|
||||||
|
if (argv[0] && argv[0][0]) opt.prog = argv[0];
|
||||||
|
|
||||||
|
lua_gc(L, LUA_GCSTOP, 0);
|
||||||
|
|
||||||
|
luaL_openlibs(L);
|
||||||
|
|
||||||
|
elua_loadfile(L, ELUA_DATA_DIR "/core/module.lua");
|
||||||
|
lua_pushcfunction(L, register_require);
|
||||||
|
lua_createtable(L, 0, 0);
|
||||||
|
luaL_register(L, NULL, utillib);
|
||||||
|
lua_call(L, 2, 0);
|
||||||
|
|
||||||
|
elua_register_cache(L);
|
||||||
|
lua_gc(L, LUA_GCRESTART, 0);
|
||||||
|
|
||||||
|
INF("elua lua state initialized");
|
||||||
|
|
||||||
|
nonopt = ecore_getopt_parse(&opt, (Ecore_Getopt_Value[]){
|
||||||
|
ECORE_GETOPT_VALUE_BOOL(quit), /* license */
|
||||||
|
ECORE_GETOPT_VALUE_BOOL(quit), /* copyright */
|
||||||
|
ECORE_GETOPT_VALUE_BOOL(quit), /* version */
|
||||||
|
ECORE_GETOPT_VALUE_BOOL(quit), /* help */
|
||||||
|
|
||||||
|
ECORE_GETOPT_VALUE_LIST(largs),
|
||||||
|
ECORE_GETOPT_VALUE_LIST(largs),
|
||||||
|
ECORE_GETOPT_VALUE_LIST(largs),
|
||||||
|
ECORE_GETOPT_VALUE_BOOL(noenv)
|
||||||
|
}, argc, argv);
|
||||||
|
|
||||||
|
INF("arguments parsed");
|
||||||
|
|
||||||
|
if (quit) return 0;
|
||||||
|
|
||||||
|
/* load all the things */
|
||||||
|
EINA_LIST_FOREACH(largs, l, data) {
|
||||||
|
switch (data->type) {
|
||||||
|
case ARG_CODE:
|
||||||
|
if (!hasexec) hasexec = EINA_TRUE;
|
||||||
|
if (dostr(L, data->value, "=(command line)")) {
|
||||||
|
m->status = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ARG_MODULE:
|
||||||
|
break;
|
||||||
|
case ARG_LIBRARY:
|
||||||
|
if (dolib(L, data->value)) {
|
||||||
|
m->status = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cleanup */
|
||||||
|
EINA_LIST_FREE(largs, data) free(data);
|
||||||
|
|
||||||
|
/* run script or execute sdin as file */
|
||||||
|
if (nonopt >= 0 && nonopt < argc) {
|
||||||
|
if ((m->status = doscript(L, argc, argv, nonopt))) return 0;
|
||||||
|
} else if (!hasexec) {
|
||||||
|
dofile(L, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
ecore_main_loop_begin();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
struct Main_Data m;
|
||||||
|
lua_State *L = NULL;
|
||||||
|
|
||||||
|
eina_init();
|
||||||
|
|
||||||
|
if (!(el_log_domain = eina_log_domain_register("elua",
|
||||||
|
EINA_COLOR_ORANGE))) {
|
||||||
|
printf("cannot set elua log domain\n");
|
||||||
|
ERR("could not set elua log domain.");
|
||||||
|
el_log_domain = EINA_LOG_DOMAIN_GLOBAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
INF("elua logging initialized: %d", el_log_domain);
|
||||||
|
|
||||||
|
if (!(L = luaL_newstate())) {
|
||||||
|
ERR("could not initialize elua state.");
|
||||||
|
shutdown(L, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
LL = L;
|
||||||
|
|
||||||
|
INF("elua lua state created");
|
||||||
|
|
||||||
|
m.argc = argc;
|
||||||
|
m.argv = argv;
|
||||||
|
m.status = 0;
|
||||||
|
|
||||||
|
shutdown(L, !!(lua_cpcall(L, lua_main, &m) || m.status));
|
||||||
|
|
||||||
|
return 0; /* never gets here */
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
#ifndef LUAR_MAIN_H
|
||||||
|
#define LUAR_MAIN_H
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ELUA_DATA_DIR
|
||||||
|
#define ELUA_DATA_DIR "."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <Eina.h>
|
||||||
|
#include <Ecore.h>
|
||||||
|
#include <Ecore_Getopt.h>
|
||||||
|
|
||||||
|
#include <lua.h>
|
||||||
|
#include <lualib.h>
|
||||||
|
#include <lauxlib.h>
|
||||||
|
|
||||||
|
extern int el_log_domain;
|
||||||
|
|
||||||
|
#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__)
|
||||||
|
|
||||||
|
int elua_loadfilex(lua_State *L, const char *fname, const char *mode);
|
||||||
|
int elua_loadfile(lua_State *L, const char *fname);
|
||||||
|
int elua_loadfilex_mmap(lua_State *L, const char *fname, const char *mode);
|
||||||
|
int elua_loadfile_mmap(lua_State *L, const char *fname);
|
||||||
|
void elua_register_cache(lua_State *L);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,72 @@
|
||||||
|
-- elua module system
|
||||||
|
|
||||||
|
local M = {}
|
||||||
|
|
||||||
|
local util = select(2, ...)
|
||||||
|
|
||||||
|
local preload = {
|
||||||
|
util = function() return util end
|
||||||
|
}
|
||||||
|
|
||||||
|
local loaded = {
|
||||||
|
}
|
||||||
|
|
||||||
|
local path = "./?.lua;/?/init.lua"
|
||||||
|
|
||||||
|
local loaders = {
|
||||||
|
function(modname)
|
||||||
|
local v = preload[modname]
|
||||||
|
if not v then
|
||||||
|
return ("\no field preload['%s']"):format(modname)
|
||||||
|
end
|
||||||
|
return v
|
||||||
|
end,
|
||||||
|
function(modname)
|
||||||
|
local fname, err = package.searchpath(modname, path)
|
||||||
|
if not fname then return err end
|
||||||
|
local f, err = loadfile(fname)
|
||||||
|
if not f then
|
||||||
|
error("error loading module '" .. modname .. "' from file '"
|
||||||
|
.. fname .. "':\n" .. err, 2)
|
||||||
|
end
|
||||||
|
return f
|
||||||
|
end
|
||||||
|
}
|
||||||
|
M.loaders = loaders
|
||||||
|
|
||||||
|
local find_loader = function(modname, env)
|
||||||
|
env = env or _G
|
||||||
|
local err = { ("module '%s' not found\n"):format(modname) }
|
||||||
|
for i = 1, #loaders do
|
||||||
|
local v = loaders[i](modname)
|
||||||
|
if type(v) == "function" then
|
||||||
|
return setfenv(v, env)
|
||||||
|
elseif type(v) == "string" then
|
||||||
|
err[#err + 1] = v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nil, table.concat(err)
|
||||||
|
end
|
||||||
|
|
||||||
|
M.require = function(modname)
|
||||||
|
local v = loaded[modname]
|
||||||
|
if v ~= nil then return v end
|
||||||
|
local loader, err = find_loader(modname)
|
||||||
|
if not loader then error(err, 2) end
|
||||||
|
local ret = loader(modname)
|
||||||
|
if ret ~= nil then
|
||||||
|
loaded[modname] = ret
|
||||||
|
return ret
|
||||||
|
elseif loaded[modname] == nil then
|
||||||
|
loaded[modname] = true
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
return loaded[modname]
|
||||||
|
end
|
||||||
|
|
||||||
|
-- register require
|
||||||
|
path = (...)(M.require, path)
|
||||||
|
|
||||||
|
_G["erequire"] = M.require
|
||||||
|
|
||||||
|
return M
|
|
@ -0,0 +1,17 @@
|
||||||
|
if HAVE_ELUA
|
||||||
|
|
||||||
|
MAINTAINERCLEANFILES = Makefile.in
|
||||||
|
|
||||||
|
DATA_FILES = Makefile.examples
|
||||||
|
EXTRA_DIST = $(DATA_FILES)
|
||||||
|
|
||||||
|
install-examples:
|
||||||
|
mkdir -p $(datadir)/elua/examples
|
||||||
|
$(install_sh_DATA) -c $(DATA_FILES) $(datadir)/elua/examples
|
||||||
|
|
||||||
|
uninstall-local:
|
||||||
|
for f in $(DATA_FILES); do \
|
||||||
|
rm -f $(datadir)/elua/examples/$$f ; \
|
||||||
|
done
|
||||||
|
|
||||||
|
endif
|
|
@ -0,0 +1,38 @@
|
||||||
|
local win = elm.Window("test", "Hello World")
|
||||||
|
|
||||||
|
win:smart_callback_add("delete,request", function()
|
||||||
|
elm.exit()
|
||||||
|
end)
|
||||||
|
|
||||||
|
local bg = elm.Background(win)
|
||||||
|
bg:size_hint_weight_set(1.0, 1.0)
|
||||||
|
win:resize_object_add(bg)
|
||||||
|
bg:show()
|
||||||
|
|
||||||
|
local bx = elm.Box(win)
|
||||||
|
bx:size_hint_weight_set(1.0, 1.0)
|
||||||
|
win:resize_object_add(bx)
|
||||||
|
bx:show()
|
||||||
|
|
||||||
|
local lbl = elm.Label(win)
|
||||||
|
lbl:text_set("Lua runtime test")
|
||||||
|
bx:pack_end(lbl)
|
||||||
|
lbl:show()
|
||||||
|
|
||||||
|
local counter = nil
|
||||||
|
local step = 5
|
||||||
|
|
||||||
|
local btn = elm.Button(win)
|
||||||
|
btn:text_set("Reset counter")
|
||||||
|
bx:pack_end(btn)
|
||||||
|
btn:smart_callback_add("clicked", function()
|
||||||
|
if not counter then
|
||||||
|
btn:text_set("Add " .. step)
|
||||||
|
end
|
||||||
|
counter = counter and (counter + step) or 0
|
||||||
|
lbl:text_set(tostring(counter))
|
||||||
|
end)
|
||||||
|
btn:show()
|
||||||
|
|
||||||
|
win:resize(360, 360)
|
||||||
|
win:show()
|
Loading…
Reference in New Issue