From bb3256d9e4afb35a936dd58bbeeb68567b27cdd3 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Fri, 2 Jun 2017 11:50:55 -0400 Subject: [PATCH] Add Lua callbacks that will walk a directory tree and return values as a table --- ext/sgct | 2 +- src/scripting/scriptengine.cpp | 30 +++++ src/scripting/scriptengine_lua.inl | 203 +++++++++++++++++++++-------- 3 files changed, 183 insertions(+), 52 deletions(-) diff --git a/ext/sgct b/ext/sgct index 55e6eb877d..40ea897067 160000 --- a/ext/sgct +++ b/ext/sgct @@ -1 +1 @@ -Subproject commit 55e6eb877d8fc02d3e3851e94fc5417a5b856217 +Subproject commit 40ea8970673c58a172dabab6ddccc45f0a0e92ac diff --git a/src/scripting/scriptengine.cpp b/src/scripting/scriptengine.cpp index ffd76288e0..cfb685a36a 100644 --- a/src/scripting/scriptengine.cpp +++ b/src/scripting/scriptengine.cpp @@ -428,6 +428,36 @@ void ScriptEngine::addBaseLibrary() { "string, string", "Registers a new path token provided by the first argument to the path " "provided in the second argument" + }, + { + "walkDirectory", + &luascriptfunctions::walkDirectory, + "string [bool, bool]", + "Walks a directory and returns all contents (files and directories) of " + "the directory as absolute paths. The first argument is the path of the " + "directory that should be walked, the second argument determines if the " + "walk is recursive and will continue in contained directories. The third " + "argument determines whether the table that is returned is sorted." + }, + { + "walkDirectoryFiles", + &luascriptfunctions::walkDirectoryFiles, + "string [bool, bool]", + "Walks a directory and returns the files of the directory as absolute " + "paths. The first argument is the path of the directory that should be " + "walked, the second argument determines if the walk is recursive and " + "will continue in contained directories. The third argument determines " + "whether the table that is returned is sorted." + }, + { + "walkDirectoryFolder", + &luascriptfunctions::walkDirectoryFolder, + "string [bool, bool]", + "Walks a directory and returns the subfolders of the directory as " + "absolute paths. The first argument is the path of the directory that " + "should be walked, the second argument determines if the walk is " + "recursive and will continue in contained directories. The third " + "argument determines whether the table that is returned is sorted." } } }; diff --git a/src/scripting/scriptengine_lua.inl b/src/scripting/scriptengine_lua.inl index 9fdf8c0a0d..d4dd178ba9 100644 --- a/src/scripting/scriptengine_lua.inl +++ b/src/scripting/scriptengine_lua.inl @@ -22,15 +22,75 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ +#include + namespace openspace { namespace luascriptfunctions { +namespace { + +using walkFunc = std::vector(ghoul::filesystem::Directory::*)( + ghoul::filesystem::Directory::Recursive, ghoul::filesystem::Directory::Sort) const; + +// Defining a common walk function that works off a pointer-to-member function (defined +// above) allows us to easily reuse this code +int walkCommon(lua_State* L, walkFunc func) { + // @CPP17 Replace with std::invoke +#define CALL_MEMBER_FN(object,ptrToMember) ((object).*(ptrToMember)) + + using namespace ghoul::filesystem; + const int nArguments = lua_gettop(L); + if (nArguments < 1 || nArguments > 3) { + return luaL_error(L, "Expected %i-%i arguments, got %i", 1, 3, nArguments); + } + + std::vector result; + if (nArguments == 1) { + // Only the path was passed + const std::string path = luaL_checkstring(L, -1); + result = CALL_MEMBER_FN(Directory(path), func)( + ghoul::filesystem::Directory::Recursive::No, + ghoul::filesystem::Directory::Sort::No + ); + } + else if (nArguments == 2) { + // The path and the recursive value were passed + const std::string path = luaL_checkstring(L, -2); + const bool recursive = lua_toboolean(L, -1) != 0; + result = CALL_MEMBER_FN(Directory(path), func)( + ghoul::filesystem::Directory::Recursive(recursive), + ghoul::filesystem::Directory::Sort::No + ); + } + else if (nArguments == 3) { + // All three arguments were passed + const std::string path = luaL_checkstring(L, -3); + const bool recursive = lua_toboolean(L, -2) != 0; + const bool sorted = lua_toboolean(L, -1) != 0; + result = CALL_MEMBER_FN(Directory(path), func)( + ghoul::filesystem::Directory::Recursive(recursive), + ghoul::filesystem::Directory::Sort(sorted) + ); + } + + // Copy values into the lua_State + lua_newtable(L); + + for (int i = 0; i < result.size(); ++i) { + lua_pushstring(L, result[i].c_str()); + lua_rawseti(L, -2, i + 1); + } + + return 1; +} +} // namespace + int printInternal(ghoul::logging::LogLevel level, lua_State* L) { using ghoul::lua::luaTypeToString; const std::string _loggerCat = "print"; - int nArguments = lua_gettop(L); + const int nArguments = lua_gettop(L); if (nArguments != 1) { return luaL_error(L, "Expected %i arguments, got %i", 1, nArguments); } @@ -61,79 +121,79 @@ int printInternal(ghoul::logging::LogLevel level, lua_State* L) { } /** - * \ingroup LuaScripts - * printTrace(*): - * Logs the passed value to the installed LogManager with a LogLevel of 'Trace'. - * For Boolean, numbers, and strings, the internal values are printed, for all other - * types, the type is printed instead - */ + * \ingroup LuaScripts + * printTrace(*): + * Logs the passed value to the installed LogManager with a LogLevel of 'Trace'. + * For Boolean, numbers, and strings, the internal values are printed, for all other + * types, the type is printed instead + */ int printTrace(lua_State* L) { return printInternal(ghoul::logging::LogLevel::Trace, L); } /** - * \ingroup LuaScripts - * printDebug(*): - * Logs the passed value to the installed LogManager with a LogLevel of 'Debug'. - * For Boolean, numbers, and strings, the internal values are printed, for all other - * types, the type is printed instead - */ + * \ingroup LuaScripts + * printDebug(*): + * Logs the passed value to the installed LogManager with a LogLevel of 'Debug'. + * For Boolean, numbers, and strings, the internal values are printed, for all other + * types, the type is printed instead + */ int printDebug(lua_State* L) { return printInternal(ghoul::logging::LogLevel::Debug, L); } /** - * \ingroup LuaScripts - * printInfo(*): - * Logs the passed value to the installed LogManager with a LogLevel of 'Info'. - * For Boolean, numbers, and strings, the internal values are printed, for all other - * types, the type is printed instead - */ + * \ingroup LuaScripts + * printInfo(*): + * Logs the passed value to the installed LogManager with a LogLevel of 'Info'. + * For Boolean, numbers, and strings, the internal values are printed, for all other + * types, the type is printed instead + */ int printInfo(lua_State* L) { return printInternal(ghoul::logging::LogLevel::Info, L); } /** - * \ingroup LuaScripts - * printWarning(*): - * Logs the passed value to the installed LogManager with a LogLevel of 'Warning'. - * For Boolean, numbers, and strings, the internal values are printed, for all other - * types, the type is printed instead - */ + * \ingroup LuaScripts + * printWarning(*): + * Logs the passed value to the installed LogManager with a LogLevel of 'Warning'. + * For Boolean, numbers, and strings, the internal values are printed, for all other + * types, the type is printed instead + */ int printWarning(lua_State* L) { return printInternal(ghoul::logging::LogLevel::Warning, L); } /** - * \ingroup LuaScripts - * printError(*): - * Logs the passed value to the installed LogManager with a LogLevel of 'Error'. - * For Boolean, numbers, and strings, the internal values are printed, for all other - * types, the type is printed instead - */ + * \ingroup LuaScripts + * printError(*): + * Logs the passed value to the installed LogManager with a LogLevel of 'Error'. + * For Boolean, numbers, and strings, the internal values are printed, for all other + * types, the type is printed instead + */ int printError(lua_State* L) { return printInternal(ghoul::logging::LogLevel::Error, L); } /** - * \ingroup LuaScripts - * printFatal(*): - * Logs the passed value to the installed LogManager with a LogLevel of 'Fatal'. - * For Boolean, numbers, and strings, the internal values are printed, for all other - * types, the type is printed instead - */ + * \ingroup LuaScripts + * printFatal(*): + * Logs the passed value to the installed LogManager with a LogLevel of 'Fatal'. + * For Boolean, numbers, and strings, the internal values are printed, for all other + * types, the type is printed instead + */ int printFatal(lua_State* L) { return printInternal(ghoul::logging::LogLevel::Fatal, L); } /** - * \ingroup LuaScripts - * absPath(string): - * Passes the argument to FileSystem::absolutePath, which resolves occuring path - * tokens and returns the absolute path. - */ + * \ingroup LuaScripts + * absPath(string): + * Passes the argument to FileSystem::absolutePath, which resolves occuring path + * tokens and returns the absolute path. + */ int absolutePath(lua_State* L) { - int nArguments = lua_gettop(L); + const int nArguments = lua_gettop(L); if (nArguments != 1) { return luaL_error(L, "Expected %d arguments, got %d", 1, nArguments); } @@ -145,19 +205,19 @@ int absolutePath(lua_State* L) { } /** - * \ingroup LuaScripts - * setPathToken(string, string): - * Registers the path token provided by the first argument to the path in the second - * argument. If the path token already exists, it will be silently overridden. - */ + * \ingroup LuaScripts + * setPathToken(string, string): + * Registers the path token provided by the first argument to the path in the second + * argument. If the path token already exists, it will be silently overridden. + */ int setPathToken(lua_State* L) { - int nArguments = lua_gettop(L); + const int nArguments = lua_gettop(L); if (nArguments != 2) { return luaL_error(L, "Expected %i arguments, got %i", 2, nArguments); } - std::string path = luaL_checkstring(L, -1); - std::string pathToken = luaL_checkstring(L, -2); + const std::string path = luaL_checkstring(L, -1); + const std::string pathToken = luaL_checkstring(L, -2); FileSys.registerPathToken( pathToken, path, @@ -166,6 +226,47 @@ int setPathToken(lua_State* L) { return 0; } +/** + * \ingroup LuaScripts + * walkDirectory(string, bool, bool): + * Walks a directory and returns the contents of the directory as absolute paths. The + * first argument is the path of the directory that should be walked, the second argument + * determines if the walk is recursive and will continue in contained directories. The + * default value for this parameter is "false". The third argument determines whether the + * table that is returned is sorted. The default value for this parameter is "false". + */ +int walkDirectory(lua_State* L) { + return walkCommon(L, &ghoul::filesystem::Directory::read); +} + +/** + * \ingroup LuaScripts + * walkDirectoryFiles(string, bool, bool): + * Walks a directory and returns the files of the directory as absolute paths. The first + * argument is the path of the directory that should be walked, the second argument + * determines if the walk is recursive and will continue in contained directories. The + * default value for this parameter is "false". The third argument determines whether the + * table that is returned is sorted. The default value for this parameter is "false". + */ +int walkDirectoryFiles(lua_State* L) { + return walkCommon(L, &ghoul::filesystem::Directory::readFiles); + +} + +/** +* \ingroup LuaScripts +* walkDirectory(string, bool, bool): +* Walks a directory and returns the subfolders of the directory as absolute paths. The +* first argument is the path of the directory that should be walked, the second argument +* determines if the walk is recursive and will continue in contained directories. The +* default value for this parameter is "false". The third argument determines whether the +* table that is returned is sorted. The default value for this parameter is "false". +*/ +int walkDirectoryFolder(lua_State* L) { + return walkCommon(L, &ghoul::filesystem::Directory::readDirectories); + +} + } // namespace luascriptfunctions } // namespace openspace