forked from mia/Aegisub
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_iterator.h" />
|
||||||
<ClInclude Include="$(SrcDir)include\libaegisub\line_wrap.h" />
|
<ClInclude Include="$(SrcDir)include\libaegisub\line_wrap.h" />
|
||||||
<ClInclude Include="$(SrcDir)include\libaegisub\log.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\modules.h" />
|
||||||
<ClInclude Include="$(SrcDir)include\libaegisub\lua\script_reader.h" />
|
<ClInclude Include="$(SrcDir)include\libaegisub\lua\script_reader.h" />
|
||||||
<ClInclude Include="$(SrcDir)include\libaegisub\lua\utils.h" />
|
<ClInclude Include="$(SrcDir)include\libaegisub\lua\utils.h" />
|
||||||
|
|
|
@ -203,6 +203,9 @@
|
||||||
<ClInclude Include="$(SrcDir)lua\modules\lpeg.h">
|
<ClInclude Include="$(SrcDir)lua\modules\lpeg.h">
|
||||||
<Filter>Lua\Modules</Filter>
|
<Filter>Lua\Modules</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="$(SrcDir)include\libaegisub\lua\ffi.h">
|
||||||
|
<Filter>Lua</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="$(SrcDir)include\libaegisub\lua\modules.h">
|
<ClInclude Include="$(SrcDir)include\libaegisub\lua\modules.h">
|
||||||
<Filter>Lua</Filter>
|
<Filter>Lua</Filter>
|
||||||
</ClInclude>
|
</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/
|
// Aegisub Project http://www.aegisub.org/
|
||||||
|
|
||||||
#include "libaegisub/fs.h"
|
#include "libaegisub/fs.h"
|
||||||
#include "libaegisub/type_name.h"
|
#include "libaegisub/lua/ffi.h"
|
||||||
|
|
||||||
#include <boost/filesystem/operations.hpp>
|
#include <boost/filesystem/operations.hpp>
|
||||||
#include <boost/filesystem/path.hpp>
|
#include <boost/filesystem/path.hpp>
|
||||||
#include <lua.hpp>
|
|
||||||
|
|
||||||
using namespace agi::fs;
|
using namespace agi::fs;
|
||||||
namespace bfs = boost::filesystem;
|
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) {
|
uintmax_t get_size(const char *path, char **err) {
|
||||||
return wrap(err, [=] { return Size(path); });
|
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) {
|
extern "C" int luaopen_lfs_impl(lua_State *L) {
|
||||||
lua_getglobal(L, "require");
|
agi::lua::register_lib_table(L, {"DirectoryIterator"},
|
||||||
lua_pushstring(L, "ffi");
|
"chdir", lfs_chdir,
|
||||||
lua_call(L, 1, 1);
|
"currentdir", currentdir,
|
||||||
|
"mkdir", mkdir,
|
||||||
lua_getfield(L, -1, "cdef");
|
"rmdir", lfs_rmdir,
|
||||||
lua_pushstring(L, "typedef struct DirectoryIterator DirectoryIterator;");
|
"touch", touch,
|
||||||
lua_call(L, 1, 0);
|
"get_mtime", get_mtime,
|
||||||
|
"get_mode", get_mode,
|
||||||
lua_getfield(L, -1, "cast");
|
"get_size", get_size,
|
||||||
lua_remove(L, -2); // ffi table
|
"dir_new", dir_new,
|
||||||
|
"dir_free", dir_free,
|
||||||
lua_createtable(L, 0, 12);
|
"dir_next", dir_next,
|
||||||
push_ffi_function(L, "chdir", lfs_chdir);
|
"dir_close", dir_close);
|
||||||
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
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,22 +14,11 @@
|
||||||
//
|
//
|
||||||
// Aegisub Project http://www.aegisub.org/
|
// Aegisub Project http://www.aegisub.org/
|
||||||
|
|
||||||
#include <libaegisub/type_name.h>
|
#include <libaegisub/lua/ffi.h>
|
||||||
|
|
||||||
#include <boost/locale/conversion.hpp>
|
#include <boost/locale/conversion.hpp>
|
||||||
#include <lua.hpp>
|
|
||||||
|
|
||||||
namespace {
|
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&)>
|
template<std::string (*func)(const char *, std::locale const&)>
|
||||||
char *wrap(const char *str, char **err) {
|
char *wrap(const char *str, char **err) {
|
||||||
try {
|
try {
|
||||||
|
@ -42,17 +31,9 @@ char *wrap(const char *str, char **err) {
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" int luaopen_unicode_impl(lua_State *L) {
|
extern "C" int luaopen_unicode_impl(lua_State *L) {
|
||||||
lua_getglobal(L, "require");
|
agi::lua::register_lib_table(L, {},
|
||||||
lua_pushstring(L, "ffi");
|
"to_upper_case", wrap<boost::locale::to_upper<char>>,
|
||||||
lua_call(L, 1, 1);
|
"to_lower_case", wrap<boost::locale::to_lower<char>>,
|
||||||
lua_getfield(L, -1, "cast");
|
"to_fold_case", wrap<boost::locale::fold_case<char>>);
|
||||||
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
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue