Extract some common ffi API stuff
This commit is contained in:
parent
0cf35894e1
commit
a01a84fb4f
5 changed files with 85 additions and 63 deletions
|
@ -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" />
|
||||
|
|
|
@ -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>
|
||||
|
|
62
libaegisub/include/libaegisub/lua/ffi.h
Normal file
62
libaegisub/include/libaegisub/lua/ffi.h
Normal 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
|
||||
}
|
||||
|
||||
} }
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue