Skip to content

Commit

Permalink
Adding Support.extra dofile & friends
Browse files Browse the repository at this point in the history
- able to locate files nearby previously loaded files
- able to locate files inside .zip files
  • Loading branch information
nicolasnoble committed Dec 8, 2023
1 parent 3db2564 commit 7bb0c5d
Show file tree
Hide file tree
Showing 8 changed files with 165 additions and 23 deletions.
2 changes: 1 addition & 1 deletion src/gui/gui.cc
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ void PCSX::GUI::init(std::function<void()> applyArguments) {
m_luaConsole.setCmdExec([this, luaStdout](const std::string& cmd) {
ScopedOnlyLog scopedOnlyLog(this);
try {
g_emulator->m_lua->load(cmd, "console", false);
g_emulator->m_lua->load(cmd, "console:", false);
g_emulator->m_lua->pcall();
for (const auto& error : m_glErrors) {
m_luaConsole.addError(error);
Expand Down
120 changes: 120 additions & 0 deletions src/lua/extra.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,74 @@

#include "lua/extra.h"

#include <filesystem>
#include <string_view>
#include <vector>

#include "lua-protobuf/pb.h"
#include "lua/luawrapper.h"
#include "support/file.h"
#include "support/strings-helpers.h"
#include "support/zip.h"

namespace {

std::vector<PCSX::ZipArchive> s_archives;
PCSX::File* load(std::string_view name, std::string_view from, bool inArchives = true) {
bool doRelative = false;
if (!from.empty() && (from[0] == '@')) {
from = from.substr(1);
doRelative = true;
}
std::filesystem::path fromPath(from);
std::filesystem::path absolutePath(name);
std::filesystem::path relativePath(fromPath.parent_path() / name);
relativePath = std::filesystem::weakly_canonical(relativePath);

PCSX::File* file = nullptr;

if (inArchives) {
for (auto& archive : s_archives) {
if (doRelative) {
file = archive.openFile(relativePath.string());
if (!file->failed()) return file;
delete file;
}
file = archive.openFile(absolutePath.string());
if (!file->failed()) return file;
delete file;
}
} else {
for (auto& archive : s_archives) {
std::filesystem::path fromPath(from);
std::filesystem::path relativePath(archive.archiveFilename().parent_path() / name);
relativePath = std::filesystem::weakly_canonical(relativePath);
file = archive.openFile(relativePath.string());
if (!file->failed()) return file;
delete file;
file = archive.openFile(absolutePath.string());
if (!file->failed()) return file;
delete file;
}
}

if (doRelative) {
file = new PCSX::PosixFile(relativePath);
if (!file->failed()) return file;
delete file;
}
return new PCSX::PosixFile(absolutePath);
}

Check warning on line 79 in src/lua/extra.cc

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

❌ New issue: Complex Method

load has a cyclomatic complexity of 13, threshold = 9. This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.

Check warning on line 79 in src/lua/extra.cc

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

❌ New issue: Bumpy Road Ahead

load has 3 blocks with nested conditional logic. Any nesting of 2 or deeper is considered. Threshold is one single, nested block per function. The Bumpy Road code smell is a function that contains multiple chunks of nested conditional logic. The deeper the nesting and the more bumps, the lower the code health.

Check warning on line 79 in src/lua/extra.cc

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

❌ New issue: Deep, Nested Complexity

load has a nested complexity depth of 4, threshold = 4. This function contains deeply nested logic such as if statements and/or loops. The deeper the nesting, the lower the code health.

} // namespace

void PCSX::LuaFFI::addArchive(IO<File> file) {
auto& newArchive = s_archives.emplace_back(file);
if (newArchive.failed()) {
s_archives.pop_back();
throw std::runtime_error("Invalid zip file");
}
}

void PCSX::LuaFFI::open_extra(Lua L) {
L.getfieldtable("_LOADED", LUA_REGISTRYINDEX);
Expand Down Expand Up @@ -76,5 +142,59 @@ void PCSX::LuaFFI::open_extra(Lua L) {
L.load(protoc, "internal:lua-protobuf/protoc.lua");
L.setfield("protoc");

L.load(R"(
Support.extra = {
loadfile = function(name)
return loadstring(Support._internal.loadfile(name), '@' .. name)
end,
dofile = function(name)
local func, msg = loadstring(Support._internal.loadfile(name), '@' .. name)
if func then return func() end
error(msg)
end,
}
)",
"internal:extra.lua");

L.getfieldtable("Support", LUA_GLOBALSINDEX);
L.getfieldtable("extra");
L.declareFunc(
"addArchive",
[](lua_State* L_) -> int {
Lua L(L_);
lua_Debug ar = L.getinfo("S");
auto name = L.tostring();
for (auto& c : name) {
if (c == '\\') c = '/';
}
IO<File> file = load(name, ar.source);
if (file->failed()) return L.error("Unable to locate archive file");
auto& newArchive = s_archives.emplace_back(file);
if (newArchive.failed()) {
s_archives.pop_back();
return L.error("Invalid zip file");
}
return 0;
},
-1);
L.pop();
L.getfieldtable("_internal");
L.declareFunc(
"loadfile",
[](lua_State* L_) -> int {
Lua L(L_);
auto ar = L.getinfo("S", 2);
auto name = L.tostring();
IO<File> file = load(name, ar.has_value() ? ar->source : "");
if (file->failed()) return L.error("Unable to locate file");
L.push(file->readString(file->size()));
return 1;
},
-1);
L.pop();
L.pop();

Check warning on line 198 in src/lua/extra.cc

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

❌ New issue: Large Method

PCSX::LuaFFI::open_extra has 100 lines, threshold = 70. Large functions with many lines of code are generally harder to understand and lower the code health. Avoid adding more lines to this function.
L.pop();
}
2 changes: 2 additions & 0 deletions src/lua/extra.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@
#pragma once

#include "lua/luawrapper.h"
#include "support/file.h"

namespace PCSX {

namespace LuaFFI {
void open_extra(Lua);
void addArchive(IO<File>);
}

} // namespace PCSX
9 changes: 9 additions & 0 deletions src/lua/luawrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,15 @@ class Lua {

bool newmetatable(const char* name) { return luaL_newmetatable(L, name) != 0; }

std::optional<lua_Debug> getinfo(const char* what, int level = 1) {
lua_Debug ar;
int r = lua_getstack(L, level, &ar);
if (!r) return std::nullopt;
r = lua_getinfo(L, what, &ar);
if (!r) return std::nullopt;
return ar;
}

private:
lua_State* L;
};
Expand Down
26 changes: 16 additions & 10 deletions src/main/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "flags.h"
#include "fmt/chrono.h"
#include "gui/gui.h"
#include "lua/extra.h"
#include "lua/luawrapper.h"
#include "main/textui.h"
#include "spu/interface.h"
Expand Down Expand Up @@ -373,25 +374,30 @@ int pcsxMain(int argc, char **argv) {
PCSX::g_system = nullptr;
});
try {
auto & L = emulator->m_lua;
// Before going into the main loop, let's first load all of the Lua files
// from the command-line specified using the -dofile switch.
auto archives = args.values("archive");
for (auto &archive : archives) {
PCSX::IO<PCSX::File> file = new PCSX::PosixFile(archive);
if (file->failed()) {
throw std::runtime_error(fmt::format("Couldn't load file {}", archive));
}
PCSX::LuaFFI::addArchive(file);
}
auto dofiles = args.values("dofile");
L->load("return function(name) Support.extra.dofile(name) end", "internal:");
for (auto &dofile : dofiles) {
std::string name = std::string(dofile);
std::ifstream in(name, std::ifstream::in);
if (!in) {
throw std::runtime_error("Couldn't load file " + name);
}
std::ostringstream code;
code << in.rdbuf();
in.close();
emulator->m_lua->load(code.str(), name.c_str());
L->copy(-1);
L->push(dofile);
L->pcall(1);
}
L->pop();

// Then run all of the Lua "exec" commands.
auto luaexecs = args.values("exec");
for (auto &luaexec : luaexecs) {
emulator->m_lua->load(luaexec.data(), "cmdline");
L->load(luaexec.data(), "cmdline:");

Check warning on line 400 in src/main/main.cc

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

❌ Getting worse: Complex Method

pcsxMain increases in cyclomatic complexity from 50 to 51, threshold = 9. This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.
}

system->m_inStartup = false;
Expand Down
4 changes: 2 additions & 2 deletions src/support/version-windows.cc
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,10 @@ bool PCSX::Update::applyUpdate(const std::filesystem::path& binDir) {
script->writeString("$failed = $False\n");

unsigned count = 0;
zip.listAllFiles([&zip, &script, &tmp, &binDir, &count](const std::string_view& name) {
zip.listAllFiles([&zip, &script, &tmp, &binDir, &count](std::string_view name) {
auto filename = tmp / ("pcsx-update-file-" + std::to_string(count++) + ".tmp");
IO<File> out(new UvFile(filename, FileOps::TRUNCATE));
IO<File> in(zip.openFile(name));
IO<File> in(zip.openFile(std::string(name)));
Slice data = in->read(in->size());
uint8_t digest[16];
MD5 md5;
Expand Down
9 changes: 6 additions & 3 deletions src/support/zip.cc
Original file line number Diff line number Diff line change
Expand Up @@ -110,23 +110,26 @@ PCSX::ZipArchive::ZipArchive(IO<File> file) : m_file(file) {
}
}

void PCSX::ZipArchive::listFiles(std::function<bool(const std::string_view&)> walker) {
void PCSX::ZipArchive::listFiles(std::function<bool(std::string_view)> walker) {
for (auto& file : m_files) {
if (!file.isDirectory()) {
if (!walker(file.name)) return;
}
}
}

void PCSX::ZipArchive::listDirectories(std::function<bool(const std::string_view&)> walker) {
void PCSX::ZipArchive::listDirectories(std::function<bool(std::string_view)> walker) {
for (auto& file : m_files) {
if (file.isDirectory()) {
if (!walker(std::string_view(file.name.c_str(), file.name.length() - 1))) return;
}
}
}

PCSX::File* PCSX::ZipArchive::openFile(const std::string_view& path) {
PCSX::File* PCSX::ZipArchive::openFile(std::string path) {
for (auto& c : path) {
if (c == '\\') c = '/';
}

Check warning on line 132 in src/support/zip.cc

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

❌ New issue: Bumpy Road Ahead

PCSX::ZipArchive::openFile has 2 blocks with nested conditional logic. Any nesting of 2 or deeper is considered. Threshold is one single, nested block per function. The Bumpy Road code smell is a function that contains multiple chunks of nested conditional logic. The deeper the nesting and the more bumps, the lower the code health.
File* ret = nullptr;
for (auto& file : m_files) {
if (file.name == path) {
Expand Down
16 changes: 9 additions & 7 deletions src/support/zip.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,23 @@ class ZipArchive {
public:
ZipArchive(IO<File> file);
bool failed() { return m_failed; }
void listAllFiles(std::function<void(const std::string_view &)> walker) {
listFiles([walker](const std::string_view &name) -> bool {
void listAllFiles(std::function<void(std::string_view)> walker) {
listFiles([walker](std::string_view name) -> bool {
walker(name);
return true;
});
}
void listAllDirectories(std::function<void(const std::string_view &)> walker) {
listDirectories([walker](const std::string_view &name) -> bool {
void listAllDirectories(std::function<void(std::string_view)> walker) {
listDirectories([walker](std::string_view name) -> bool {
walker(name);
return true;
});
}
void listFiles(std::function<bool(const std::string_view &)> walker);
void listDirectories(std::function<bool(const std::string_view &)> walker);
File *openFile(const std::string_view &path);
void listFiles(std::function<bool(std::string_view)> walker);
void listDirectories(std::function<bool(std::string_view)> walker);
File *openFile(std::string path);

std::filesystem::path archiveFilename() { return m_file->filename(); }

private:
IO<File> m_file;
Expand Down

0 comments on commit 7bb0c5d

Please sign in to comment.