mirror of
https://github.com/love2d/love.git
synced 2026-08-20 04:30:09 +02:00
Rewrite the c module loader, adding a search path (fixes #1050)
Note: also removes the restriction that only fused games can load libraries from their save folders. --HG-- branch : minor
This commit is contained in:
@@ -261,6 +261,7 @@ public:
|
|||||||
// Require path accessors
|
// Require path accessors
|
||||||
// Not const because it's R/W
|
// Not const because it's R/W
|
||||||
virtual std::vector<std::string> &getRequirePath() = 0;
|
virtual std::vector<std::string> &getRequirePath() = 0;
|
||||||
|
virtual std::vector<std::string> &getCRequirePath() = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows a full (OS-dependent) path to be used with Filesystem::mount.
|
* Allows a full (OS-dependent) path to be used with Filesystem::mount.
|
||||||
|
|||||||
@@ -107,6 +107,7 @@ Filesystem::Filesystem()
|
|||||||
, fusedSet(false)
|
, fusedSet(false)
|
||||||
{
|
{
|
||||||
requirePath = {"?.lua", "?/init.lua"};
|
requirePath = {"?.lua", "?/init.lua"};
|
||||||
|
cRequirePath = {"??"};
|
||||||
}
|
}
|
||||||
|
|
||||||
Filesystem::~Filesystem()
|
Filesystem::~Filesystem()
|
||||||
@@ -771,6 +772,11 @@ std::vector<std::string> &Filesystem::getRequirePath()
|
|||||||
return requirePath;
|
return requirePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> &Filesystem::getCRequirePath()
|
||||||
|
{
|
||||||
|
return cRequirePath;
|
||||||
|
}
|
||||||
|
|
||||||
void Filesystem::allowMountingForPath(const std::string &path)
|
void Filesystem::allowMountingForPath(const std::string &path)
|
||||||
{
|
{
|
||||||
if (std::find(allowedMountPaths.begin(), allowedMountPaths.end(), path) == allowedMountPaths.end())
|
if (std::find(allowedMountPaths.begin(), allowedMountPaths.end(), path) == allowedMountPaths.end())
|
||||||
|
|||||||
@@ -97,6 +97,7 @@ public:
|
|||||||
bool areSymlinksEnabled() const;
|
bool areSymlinksEnabled() const;
|
||||||
|
|
||||||
std::vector<std::string> &getRequirePath();
|
std::vector<std::string> &getRequirePath();
|
||||||
|
std::vector<std::string> &getCRequirePath();
|
||||||
|
|
||||||
void allowMountingForPath(const std::string &path);
|
void allowMountingForPath(const std::string &path);
|
||||||
|
|
||||||
@@ -127,6 +128,7 @@ private:
|
|||||||
|
|
||||||
// Search path for require
|
// Search path for require
|
||||||
std::vector<std::string> requirePath;
|
std::vector<std::string> requirePath;
|
||||||
|
std::vector<std::string> cRequirePath;
|
||||||
|
|
||||||
std::vector<std::string> allowedMountPaths;
|
std::vector<std::string> allowedMountPaths;
|
||||||
|
|
||||||
|
|||||||
@@ -590,6 +590,24 @@ int w_getRequirePath(lua_State *L)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int w_getCRequirePath(lua_State *L)
|
||||||
|
{
|
||||||
|
std::stringstream path;
|
||||||
|
bool seperator = false;
|
||||||
|
for (auto &element : instance()->getCRequirePath())
|
||||||
|
{
|
||||||
|
if (seperator)
|
||||||
|
path << ";";
|
||||||
|
else
|
||||||
|
seperator = true;
|
||||||
|
|
||||||
|
path << element;
|
||||||
|
}
|
||||||
|
|
||||||
|
luax_pushstring(L, path.str());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int w_setRequirePath(lua_State *L)
|
int w_setRequirePath(lua_State *L)
|
||||||
{
|
{
|
||||||
std::string element = luax_checkstring(L, 1);
|
std::string element = luax_checkstring(L, 1);
|
||||||
@@ -605,6 +623,21 @@ int w_setRequirePath(lua_State *L)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int w_setCRequirePath(lua_State *L)
|
||||||
|
{
|
||||||
|
std::string element = luax_checkstring(L, 1);
|
||||||
|
auto &requirePath = instance()->getCRequirePath();
|
||||||
|
|
||||||
|
requirePath.clear();
|
||||||
|
std::stringstream path;
|
||||||
|
path << element;
|
||||||
|
|
||||||
|
while(std::getline(path, element, ';'))
|
||||||
|
requirePath.push_back(element);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int loader(lua_State *L)
|
int loader(lua_State *L)
|
||||||
{
|
{
|
||||||
std::string modulename = luax_tostring(L, 1);
|
std::string modulename = luax_tostring(L, 1);
|
||||||
@@ -651,6 +684,9 @@ int extloader(lua_State *L)
|
|||||||
std::string tokenized_name(filename);
|
std::string tokenized_name(filename);
|
||||||
std::string tokenized_function(filename);
|
std::string tokenized_function(filename);
|
||||||
|
|
||||||
|
// We need both the tokenized filename (dots replaced with slashes)
|
||||||
|
// and the tokenized function name (dots replaced with underscores)
|
||||||
|
// NOTE: Lua's loader queries more names than this one.
|
||||||
for (unsigned int i = 0; i < tokenized_name.size(); i++)
|
for (unsigned int i = 0; i < tokenized_name.size(); i++)
|
||||||
{
|
{
|
||||||
if (tokenized_name[i] == '.')
|
if (tokenized_name[i] == '.')
|
||||||
@@ -660,32 +696,29 @@ int extloader(lua_State *L)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tokenized_name += library_extension();
|
|
||||||
|
|
||||||
void *handle = nullptr;
|
void *handle = nullptr;
|
||||||
|
auto *inst = instance();
|
||||||
// If the game is fused, try looking for the DLL in the game's read paths.
|
for (std::string element : inst->getCRequirePath())
|
||||||
if (instance()->isFused())
|
|
||||||
{
|
{
|
||||||
try
|
// Replace ?? with the filename and extension
|
||||||
{
|
size_t pos = element.find("??");
|
||||||
std::string dir = instance()->getRealDirectory(tokenized_name.c_str());
|
if (pos != std::string::npos)
|
||||||
|
element.replace(pos, 2, tokenized_name + library_extension());
|
||||||
|
// Or ? with just the filename
|
||||||
|
pos = element.find('?');
|
||||||
|
if (pos != std::string::npos)
|
||||||
|
element.replace(pos, 1, tokenized_name);
|
||||||
|
|
||||||
// We don't want to look in the game's source, because it can be a
|
if (!inst->isFile(element.c_str()))
|
||||||
// zip sometimes and a folder other times.
|
continue;
|
||||||
if (dir.find(instance()->getSource()) == std::string::npos)
|
|
||||||
handle = SDL_LoadObject((dir + LOVE_PATH_SEPARATOR + tokenized_name).c_str());
|
|
||||||
}
|
|
||||||
catch (love::Exception &)
|
|
||||||
{
|
|
||||||
// Nothing...
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!handle)
|
// Now resolve the full path, as we're bypassing physfs for the next part.
|
||||||
{
|
element = inst->getRealDirectory(element.c_str()) + LOVE_PATH_SEPARATOR + element;
|
||||||
std::string path = std::string(instance()->getAppdataDirectory()) + LOVE_PATH_SEPARATOR LOVE_APPDATA_FOLDER LOVE_PATH_SEPARATOR + tokenized_name;
|
|
||||||
handle = SDL_LoadObject(path.c_str());
|
handle = SDL_LoadObject(element.c_str());
|
||||||
|
// Can fail, for instance if it turned out the source was a zip
|
||||||
|
if (handle)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!handle)
|
if (!handle)
|
||||||
@@ -694,6 +727,8 @@ int extloader(lua_State *L)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We look for both loveopen_ and luaopen_, so libraries with specific love support
|
||||||
|
// can tell when they've been loaded by love.
|
||||||
void *func = SDL_LoadFunction(handle, ("loveopen_" + tokenized_function).c_str());
|
void *func = SDL_LoadFunction(handle, ("loveopen_" + tokenized_function).c_str());
|
||||||
if (!func)
|
if (!func)
|
||||||
func = SDL_LoadFunction(handle, ("luaopen_" + tokenized_function).c_str());
|
func = SDL_LoadFunction(handle, ("luaopen_" + tokenized_function).c_str());
|
||||||
@@ -749,6 +784,8 @@ static const luaL_Reg functions[] =
|
|||||||
{ "newFileData", w_newFileData },
|
{ "newFileData", w_newFileData },
|
||||||
{ "getRequirePath", w_getRequirePath },
|
{ "getRequirePath", w_getRequirePath },
|
||||||
{ "setRequirePath", w_setRequirePath },
|
{ "setRequirePath", w_setRequirePath },
|
||||||
|
{ "getCRequirePath", w_getCRequirePath },
|
||||||
|
{ "setCRequirePath", w_setCRequirePath },
|
||||||
{ 0, 0 }
|
{ 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user