Extract some common ffi API stuff

This commit is contained in:
Thomas Goyne 2014-07-18 18:21:36 -07:00
parent 0cf35894e1
commit a01a84fb4f
5 changed files with 85 additions and 63 deletions

View file

@ -93,6 +93,7 @@
<ClInclude Include="$(SrcDir)include\libaegisub\line_iterator.h" />
<ClInclude Include="$(SrcDir)include\libaegisub\line_wrap.h" />
<ClInclude Include="$(SrcDir)include\libaegisub\log.h" />
<ClInclude Include="$(SrcDir)include\libaegisub\lua\ffi.h" />
<ClInclude Include="$(SrcDir)include\libaegisub\lua\modules.h" />
<ClInclude Include="$(SrcDir)include\libaegisub\lua\script_reader.h" />
<ClInclude Include="$(SrcDir)include\libaegisub\lua\utils.h" />

View file

@ -203,6 +203,9 @@
<ClInclude Include="$(SrcDir)lua\modules\lpeg.h">
<Filter>Lua\Modules</Filter>
</ClInclude>
<ClInclude Include="$(SrcDir)include\libaegisub\lua\ffi.h">
<Filter>Lua</Filter>
</ClInclude>
<ClInclude Include="$(SrcDir)include\libaegisub\lua\modules.h">
<Filter>Lua</Filter>
</ClInclude>

View file

@ -0,0 +1,62 @@
// Copyright (c) 2014, Thomas Goyne <plorkyeran@aegisub.org>
//
// 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 <libaegisub/type_name.h>
#include <lua.hpp>
namespace agi { namespace lua {
static void register_lib_functions(lua_State *) {
// Base case of recursion; nothing to do
}
template<typename Func, typename... Rest>
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<Func*>::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<typename... Args>
void register_lib_table(lua_State *L, std::initializer_list<const char *> 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
}
} }

View file

@ -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 <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>
#include <lua.hpp>
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<typename T>
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<T*>::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;
}

View file

@ -14,22 +14,11 @@
//
// Aegisub Project http://www.aegisub.org/
#include <libaegisub/type_name.h>
#include <libaegisub/lua/ffi.h>
#include <boost/locale/conversion.hpp>
#include <lua.hpp>
namespace {
template<typename T>
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<T*>::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<std::string (*func)(const char *, std::locale const&)>
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<boost::locale::to_upper<char>>);
push_ffi_function(L, "to_lower_case", wrap<boost::locale::to_lower<char>>);
push_ffi_function(L, "to_fold_case", wrap<boost::locale::fold_case<char>>);
lua_remove(L, -2); // ffi.cast function
agi::lua::register_lib_table(L, {},
"to_upper_case", wrap<boost::locale::to_upper<char>>,
"to_lower_case", wrap<boost::locale::to_lower<char>>,
"to_fold_case", wrap<boost::locale::fold_case<char>>);
return 1;
}