From a01a84fb4fdc0abca39ab1ab18d262c0ec5caacb Mon Sep 17 00:00:00 2001 From: Thomas Goyne Date: Fri, 18 Jul 2014 18:21:36 -0700 Subject: [PATCH] Extract some common ffi API stuff --- build/libaegisub/libaegisub.vcxproj | 1 + build/libaegisub/libaegisub.vcxproj.filters | 3 + libaegisub/include/libaegisub/lua/ffi.h | 62 +++++++++++++++++++++ libaegisub/lua/modules/lfs.cpp | 53 +++++------------- libaegisub/lua/modules/unicode.cpp | 29 ++-------- 5 files changed, 85 insertions(+), 63 deletions(-) create mode 100644 libaegisub/include/libaegisub/lua/ffi.h diff --git a/build/libaegisub/libaegisub.vcxproj b/build/libaegisub/libaegisub.vcxproj index 370c3177a..db84d57e4 100644 --- a/build/libaegisub/libaegisub.vcxproj +++ b/build/libaegisub/libaegisub.vcxproj @@ -93,6 +93,7 @@ + diff --git a/build/libaegisub/libaegisub.vcxproj.filters b/build/libaegisub/libaegisub.vcxproj.filters index 7288ab0e1..06a808a0d 100644 --- a/build/libaegisub/libaegisub.vcxproj.filters +++ b/build/libaegisub/libaegisub.vcxproj.filters @@ -203,6 +203,9 @@ Lua\Modules + + Lua + Lua diff --git a/libaegisub/include/libaegisub/lua/ffi.h b/libaegisub/include/libaegisub/lua/ffi.h new file mode 100644 index 000000000..0dc09f563 --- /dev/null +++ b/libaegisub/include/libaegisub/lua/ffi.h @@ -0,0 +1,62 @@ +// Copyright (c) 2014, Thomas Goyne +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +// +// Aegisub Project http://www.aegisub.org/ + +#include + +#include + +namespace agi { namespace lua { +static void register_lib_functions(lua_State *) { + // Base case of recursion; nothing to do +} + +template +void register_lib_functions(lua_State *L, const char *name, Func *func, Rest... rest) { + lua_pushvalue(L, -2); // push cast function + lua_pushstring(L, type_name::name().c_str()); + // This cast isn't legal, but LuaJIT internally requires that it work, so we can rely on it too + lua_pushlightuserdata(L, (void *)func); + lua_call(L, 2, 1); + lua_setfield(L, -2, name); + + register_lib_functions(L, rest...); +} + +template +void register_lib_table(lua_State *L, std::initializer_list types, Args... functions) { + static_assert((sizeof...(functions) & 1) == 0, "Functions must be alternating names and function pointers"); + + lua_getglobal(L, "require"); + lua_pushstring(L, "ffi"); + lua_call(L, 1, 1); + + // Register all passed type with the ffi + for (auto type : types) { + lua_getfield(L, -1, "cdef"); + lua_pushfstring(L, "typedef struct %s %s;", type, type); + lua_call(L, 1, 0); + } + + lua_getfield(L, -1, "cast"); + lua_remove(L, -2); // ffi table + + lua_createtable(L, 0, sizeof...(functions) / 2); + register_lib_functions(L, functions...); + lua_remove(L, -2); // ffi.cast function + // Leaves lib table on the stack +} + +} } diff --git a/libaegisub/lua/modules/lfs.cpp b/libaegisub/lua/modules/lfs.cpp index 7f81b2afd..2f6d377b1 100644 --- a/libaegisub/lua/modules/lfs.cpp +++ b/libaegisub/lua/modules/lfs.cpp @@ -15,11 +15,10 @@ // Aegisub Project http://www.aegisub.org/ #include "libaegisub/fs.h" -#include "libaegisub/type_name.h" +#include "libaegisub/lua/ffi.h" #include #include -#include using namespace agi::fs; namespace bfs = boost::filesystem; @@ -121,45 +120,21 @@ time_t get_mtime(const char *path, char **err) { uintmax_t get_size(const char *path, char **err) { return wrap(err, [=] { return Size(path); }); } - -template -void push_ffi_function(lua_State *L, const char *name, T *func) { - lua_pushvalue(L, -2); // push cast function - lua_pushstring(L, agi::type_name::name().c_str()); - // This cast isn't legal, but LuaJIT internally requires that it work - lua_pushlightuserdata(L, (void *)func); - lua_call(L, 2, 1); - lua_setfield(L, -2, name); -} } extern "C" int luaopen_lfs_impl(lua_State *L) { - lua_getglobal(L, "require"); - lua_pushstring(L, "ffi"); - lua_call(L, 1, 1); - - lua_getfield(L, -1, "cdef"); - lua_pushstring(L, "typedef struct DirectoryIterator DirectoryIterator;"); - lua_call(L, 1, 0); - - lua_getfield(L, -1, "cast"); - lua_remove(L, -2); // ffi table - - lua_createtable(L, 0, 12); - push_ffi_function(L, "chdir", lfs_chdir); - push_ffi_function(L, "currentdir", currentdir); - push_ffi_function(L, "mkdir", mkdir); - push_ffi_function(L, "rmdir", lfs_rmdir); - push_ffi_function(L, "touch", touch); - push_ffi_function(L, "get_mtime", get_mtime); - push_ffi_function(L, "get_mode", get_mode); - push_ffi_function(L, "get_size", get_size); - - push_ffi_function(L, "dir_new", dir_new); - push_ffi_function(L, "dir_free", dir_free); - push_ffi_function(L, "dir_next", dir_next); - push_ffi_function(L, "dir_close", dir_close); - - lua_remove(L, -2); // ffi.cast function + agi::lua::register_lib_table(L, {"DirectoryIterator"}, + "chdir", lfs_chdir, + "currentdir", currentdir, + "mkdir", mkdir, + "rmdir", lfs_rmdir, + "touch", touch, + "get_mtime", get_mtime, + "get_mode", get_mode, + "get_size", get_size, + "dir_new", dir_new, + "dir_free", dir_free, + "dir_next", dir_next, + "dir_close", dir_close); return 1; } diff --git a/libaegisub/lua/modules/unicode.cpp b/libaegisub/lua/modules/unicode.cpp index a11487449..0141c8d89 100644 --- a/libaegisub/lua/modules/unicode.cpp +++ b/libaegisub/lua/modules/unicode.cpp @@ -14,22 +14,11 @@ // // Aegisub Project http://www.aegisub.org/ -#include +#include #include -#include namespace { -template -void push_ffi_function(lua_State *L, const char *name, T *func) { - lua_pushvalue(L, -2); // push cast function - lua_pushstring(L, agi::type_name::name().c_str()); - // This cast isn't legal, but LuaJIT internally requires that it work - lua_pushlightuserdata(L, (void *)func); - lua_call(L, 2, 1); - lua_setfield(L, -2, name); -} - template char *wrap(const char *str, char **err) { try { @@ -42,17 +31,9 @@ char *wrap(const char *str, char **err) { } extern "C" int luaopen_unicode_impl(lua_State *L) { - lua_getglobal(L, "require"); - lua_pushstring(L, "ffi"); - lua_call(L, 1, 1); - lua_getfield(L, -1, "cast"); - lua_remove(L, -2); // ffi table - - lua_createtable(L, 0, 3); - push_ffi_function(L, "to_upper_case", wrap>); - push_ffi_function(L, "to_lower_case", wrap>); - push_ffi_function(L, "to_fold_case", wrap>); - - lua_remove(L, -2); // ffi.cast function + agi::lua::register_lib_table(L, {}, + "to_upper_case", wrap>, + "to_lower_case", wrap>, + "to_fold_case", wrap>); return 1; }