diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index bd318ee..83e70ac 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -8,5 +8,6 @@ add_library(bettola target_link_libraries(bettola PUBLIC ${LUA_LIBRARIES} sol2) -target_include_directories(bettola PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src) +target_include_directories(bettola PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src + ${LUA_INCLUDE_DIR}) diff --git a/common/src/command_processor.cpp b/common/src/command_processor.cpp index 609885b..f1695d1 100644 --- a/common/src/command_processor.cpp +++ b/common/src/command_processor.cpp @@ -1,8 +1,14 @@ #include "command_processor.h" #include "vfs.h" +#include "lua_processor.h" CommandProcessor::CommandProcessor(vfs_node* starting_dir) { _current_dir = starting_dir; + _lua = new LuaProcessor(); +} + +CommandProcessor::~CommandProcessor(void) { + delete _lua; } vfs_node* CommandProcessor::get_current_dir(void) { @@ -10,6 +16,11 @@ vfs_node* CommandProcessor::get_current_dir(void) { } std::string CommandProcessor::process_command(const std::string& command) { + /* Trim trailing whitespace. */ + std::string cmd = command; + size_t end = cmd.find_last_not_of(" \t\n\r"); + cmd = (end == std::string::npos) ? "" : cmd.substr(0, end+1); + if(command.rfind("cd ", 0) == 0) { std::string target_dir_name = command.substr(3); if(target_dir_name == "..") { @@ -27,18 +38,27 @@ std::string CommandProcessor::process_command(const std::string& command) { return "cd: no such file or directory\n"; } return get_full_path(_current_dir); - } else if(command == "ls") { - std::string response = ""; - if(_current_dir && _current_dir->type == DIR_NODE) { - for(auto const& [name, node] : _current_dir->children) { - response += name; - if(node->type == DIR_NODE) { - response += "/"; - } - response += " "; + } else if(cmd == "ls") { + /* Find the root of the VFS to look for the /bin directory. */ + vfs_node* root = _current_dir; + while(root->parent != nullptr) { + root = root->parent; + } + + fprintf(stderr, "DEBUG: VFS root found, name: '%s'\n", root->name.c_str()); + + /* Find and execute the ls.lua script. */ + if(root->children.count("bin")) { + fprintf(stderr, "DEBUG: Found '/bin' directory.\n"); + vfs_node* bin_dir = root->children["bin"]; + if(bin_dir->children.count("ls.lua")) { + fprintf(stderr, "DEBUG: Found '/bin/ls.lua'. Executing.\n"); + vfs_node* ls_script_node = bin_dir->children["ls.lua"]; + return _lua->execute(ls_script_node->content, _current_dir); } } - return response; + fprintf(stderr, "DEBUG: 'ls' command failed to find '/bin/ls.lua'.\n"); + return "ls: command not found\n"; } return "Unknown command: " + command + "\n"; diff --git a/common/src/command_processor.h b/common/src/command_processor.h index 08609f7..0bf7246 100644 --- a/common/src/command_processor.h +++ b/common/src/command_processor.h @@ -3,14 +3,17 @@ #include #include "vfs.h" +#include class CommandProcessor { public: CommandProcessor(vfs_node* starting_dir); + ~CommandProcessor(void); std::string process_command(const std::string& command); vfs_node* get_current_dir(void); private: vfs_node* _current_dir; + LuaProcessor* _lua; }; diff --git a/common/src/lua_processor.cpp b/common/src/lua_processor.cpp new file mode 100644 index 0000000..5090f19 --- /dev/null +++ b/common/src/lua_processor.cpp @@ -0,0 +1,29 @@ +#include "lua_processor.h" +#include "vfs.h" + +LuaProcessor::LuaProcessor(void) { + _lua.open_libraries(sol::lib::base, sol::lib::string, sol::lib::io); + + /* Expose vfs_node struct members to Lua. */ + _lua.new_usertype("vfs_node", + "name", &vfs_node::name, + "type", &vfs_node::type, + "children", &vfs_node::children); +} + +LuaProcessor::~LuaProcessor(void) {} + +std::string LuaProcessor::execute(const std::string& script, vfs_node* current_dir) { + try { + /* Pass the pointer for the current directory into the Lua env. */ + _lua["current_dir"] = current_dir; + sol::object result = _lua.script(script); + if(result.is()) { + return result.as(); + } + } catch(const sol::error& e) { + return e.what(); + } + /* Shouldn't reach this, just shutting the compiler up. */ + return "[Unknown error in LuaProcessor::execute]"; +} diff --git a/common/src/lua_processor.h b/common/src/lua_processor.h new file mode 100644 index 0000000..78b89ba --- /dev/null +++ b/common/src/lua_processor.h @@ -0,0 +1,18 @@ +#pragma once + +#include +#include + +/* Don't want the full header. */ +struct vfs_node; + +class LuaProcessor { +public: + LuaProcessor(void); + ~LuaProcessor(void); + + /* Executes a string of lua code and returns result as a string. */ + std::string execute(const std::string& script, vfs_node* current_dir); +private: + sol::state _lua; +}; diff --git a/common/src/vfs_manager.cpp b/common/src/vfs_manager.cpp index a233c14..e379b5b 100644 --- a/common/src/vfs_manager.cpp +++ b/common/src/vfs_manager.cpp @@ -29,9 +29,23 @@ vfs_node* vfs_manager::create_root_system(const std::string& system_type) { readme->content = "Welcome to your new virtual machine."; user->children["readme.txt"] = readme; - vfs_node* ls_exe = new_node("ls", FILE_NODE, bin); - ls_exe->content = "[executable]"; - bin->children["ls"] = ls_exe; + vfs_node* ls_script = new_node("ls.lua", FILE_NODE, bin); + ls_script->content = R"lua(-- /bin/ls.lua - Lists files in a directory. + local dir = current_dir -- Get directory object from C++. + local output = "" + + -- Iterate over the 'children' map exposed from c++. + for name, node in pairs(dir.children) do + output = output .. name + if node.type == 1 then + output = output .. "/" + end + output = output .. " " + end + return output + )lua"; + + bin->children["ls.lua"] = ls_script; if(system_type == "npc") { vfs_node* npc_file = new_node("npc_system.txt", FILE_NODE, root);